1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 
22 #include "SC_Group.h"
23 #include "SC_SynthDef.h"
24 #include "SC_World.h"
25 #include "SC_WorldOptions.h"
26 #include "SC_Errors.h"
27 #include <stdio.h>
28 #include <stdexcept>
29 #include <limits.h>
30 #include "SC_Prototypes.h"
31 #include "SC_HiddenWorld.h"
32 #include "Unroll.h"
33 
34 void Node_StateMsg(Node* inNode, int inState);
35 
36 // create a new node
Node_New(World * inWorld,NodeDef * def,int32 inID,Node ** outNode)37 int Node_New(World* inWorld, NodeDef* def, int32 inID, Node** outNode) {
38     if (inID < 0) {
39         if (inID == -1) { // -1 means generate an id for the event
40             HiddenWorld* hw = inWorld->hw;
41             inID = hw->mHiddenID = (hw->mHiddenID - 8) | 0x80000000;
42         } else {
43             return kSCErr_ReservedNodeID;
44         }
45     }
46 
47     if (World_GetNode(inWorld, inID)) {
48         return kSCErr_DuplicateNodeID;
49     }
50 
51     Node* node = (Node*)World_Alloc(inWorld, def->mAllocSize);
52 
53     node->mWorld = inWorld;
54     node->mDef = def;
55     node->mParent = nullptr;
56     node->mPrev = nullptr;
57     node->mNext = nullptr;
58     node->mIsGroup = false;
59 
60     node->mID = inID;
61     node->mHash = Hash(inID);
62     if (!World_AddNode(inWorld, node)) {
63         World_Free(inWorld, node);
64         return kSCErr_TooManyNodes;
65     }
66 
67     inWorld->hw->mRecentID = inID;
68 
69     *outNode = node;
70 
71     return kSCErr_None;
72 }
73 
74 // node destructor
Node_Dtor(Node * inNode)75 void Node_Dtor(Node* inNode) {
76     Node_StateMsg(inNode, kNode_End);
77     Node_Remove(inNode);
78     World* world = inNode->mWorld;
79     world->hw->mNodeLib->Remove(inNode);
80     World_Free(world, inNode);
81 }
82 
83 // remove a node from a group
Node_Remove(Node * s)84 void Node_Remove(Node* s) {
85     Group* group = s->mParent;
86 
87     if (s->mPrev)
88         s->mPrev->mNext = s->mNext;
89     else if (group)
90         group->mHead = s->mNext;
91 
92     if (s->mNext)
93         s->mNext->mPrev = s->mPrev;
94     else if (group)
95         group->mTail = s->mPrev;
96 
97     s->mPrev = s->mNext = nullptr;
98     s->mParent = nullptr;
99 }
100 
Node_RemoveID(Node * inNode)101 void Node_RemoveID(Node* inNode) {
102     if (inNode->mID == 0)
103         return; // failed
104 
105     World* world = inNode->mWorld;
106     if (!World_RemoveNode(world, inNode)) {
107         int err = kSCErr_Failed; // shouldn't happen..
108         throw err;
109     }
110 
111     HiddenWorld* hw = world->hw;
112     int id = hw->mHiddenID = (hw->mHiddenID - 8) | 0x80000000;
113     inNode->mID = id;
114     inNode->mHash = Hash(id);
115     if (!World_AddNode(world, inNode)) {
116         scprintf("mysterious failure in Node_RemoveID\n");
117         Node_Delete(inNode);
118         // enums are uncatchable. must throw an int.
119         int err = kSCErr_Failed; // shouldn't happen..
120         throw err;
121     }
122 
123     // inWorld->hw->mRecentID = id;
124 }
125 
126 // delete a node
Node_Delete(Node * inNode)127 void Node_Delete(Node* inNode) {
128     if (inNode->mID == 0)
129         return; // failed
130     if (inNode->mIsGroup)
131         Group_Dtor((Group*)inNode);
132     else
133         Graph_Dtor((Graph*)inNode);
134 }
135 
136 // add a node after another one
Node_AddAfter(Node * s,Node * afterThisOne)137 void Node_AddAfter(Node* s, Node* afterThisOne) {
138     if (!afterThisOne->mParent || s->mID == 0)
139         return; // failed
140 
141     s->mParent = afterThisOne->mParent;
142     s->mPrev = afterThisOne;
143     s->mNext = afterThisOne->mNext;
144 
145     if (afterThisOne->mNext)
146         afterThisOne->mNext->mPrev = s;
147     else
148         s->mParent->mTail = s;
149     afterThisOne->mNext = s;
150 }
151 
152 // add a node before another one
Node_AddBefore(Node * s,Node * beforeThisOne)153 void Node_AddBefore(Node* s, Node* beforeThisOne) {
154     if (!beforeThisOne->mParent || s->mID == 0)
155         return; // failed
156 
157     s->mParent = beforeThisOne->mParent;
158     s->mPrev = beforeThisOne->mPrev;
159     s->mNext = beforeThisOne;
160 
161     if (beforeThisOne->mPrev)
162         beforeThisOne->mPrev->mNext = s;
163     else
164         s->mParent->mHead = s;
165     beforeThisOne->mPrev = s;
166 }
167 
Node_Replace(Node * s,Node * replaceThisOne)168 void Node_Replace(Node* s, Node* replaceThisOne) {
169     // scprintf("->Node_Replace\n");
170     Group* group = replaceThisOne->mParent;
171     if (!group)
172         return; // failed
173     if (s->mID == 0)
174         return;
175 
176     s->mParent = group;
177     s->mPrev = replaceThisOne->mPrev;
178     s->mNext = replaceThisOne->mNext;
179 
180     if (s->mPrev)
181         s->mPrev->mNext = s;
182     else
183         group->mHead = s;
184 
185     if (s->mNext)
186         s->mNext->mPrev = s;
187     else
188         group->mTail = s;
189 
190     replaceThisOne->mPrev = replaceThisOne->mNext = nullptr;
191     replaceThisOne->mParent = nullptr;
192 
193     Node_Delete(replaceThisOne);
194     // scprintf("<-Node_Replace\n");
195 }
196 
197 // set a node's control so that it reads from a control bus - index argument
Node_MapControl(Node * inNode,int inIndex,int inBus)198 void Node_MapControl(Node* inNode, int inIndex, int inBus) {
199     if (inNode->mIsGroup) {
200         Group_MapControl((Group*)inNode, inIndex, inBus);
201     } else {
202         Graph_MapControl((Graph*)inNode, inIndex, inBus);
203     }
204 }
205 
206 // set a node's control so that it reads from a control bus - name argument
Node_MapControl(Node * inNode,int32 inHash,int32 * inName,int inIndex,int inBus)207 void Node_MapControl(Node* inNode, int32 inHash, int32* inName, int inIndex, int inBus) {
208     if (inNode->mIsGroup) {
209         Group_MapControl((Group*)inNode, inHash, inName, inIndex, inBus);
210     } else {
211         Graph_MapControl((Graph*)inNode, inHash, inName, inIndex, inBus);
212     }
213 }
214 
215 // set a node's control so that it reads from a control bus - index argument
Node_MapAudioControl(Node * inNode,int inIndex,int inBus)216 void Node_MapAudioControl(Node* inNode, int inIndex, int inBus) {
217     if (inNode->mIsGroup) {
218         Group_MapAudioControl((Group*)inNode, inIndex, inBus);
219     } else {
220         Graph_MapAudioControl((Graph*)inNode, inIndex, inBus);
221     }
222 }
223 
224 // set a node's control so that it reads from a control bus - name argument
Node_MapAudioControl(Node * inNode,int32 inHash,int32 * inName,int inIndex,int inBus)225 void Node_MapAudioControl(Node* inNode, int32 inHash, int32* inName, int inIndex, int inBus) {
226     if (inNode->mIsGroup) {
227         Group_MapAudioControl((Group*)inNode, inHash, inName, inIndex, inBus);
228     } else {
229         Graph_MapAudioControl((Graph*)inNode, inHash, inName, inIndex, inBus);
230     }
231 }
232 
233 // set a node's control value - index argument
Node_SetControl(Node * inNode,int inIndex,float inValue)234 void Node_SetControl(Node* inNode, int inIndex, float inValue) {
235     if (inNode->mIsGroup) {
236         Group_SetControl((Group*)inNode, inIndex, inValue);
237     } else {
238         Graph_SetControl((Graph*)inNode, inIndex, inValue);
239     }
240 }
241 
242 // set a node's control value - name argument
Node_SetControl(Node * inNode,int32 inHash,int32 * inName,int inIndex,float inValue)243 void Node_SetControl(Node* inNode, int32 inHash, int32* inName, int inIndex, float inValue) {
244     if (inNode->mIsGroup) {
245         Group_SetControl((Group*)inNode, inHash, inName, inIndex, inValue);
246     } else {
247         Graph_SetControl((Graph*)inNode, inHash, inName, inIndex, inValue);
248     }
249 }
250 
251 // this function can be installed using Node_SetRun to cause a node to do nothing
252 // during its execution time.
Node_NullCalc(struct Node *)253 void Node_NullCalc(struct Node* /*inNode*/) {}
254 
255 void Graph_FirstCalc(Graph* inGraph);
256 void Graph_NullFirstCalc(Graph* inGraph);
257 
258 // if inRun is zero then the node's calc function is set to Node_NullCalc,
259 // otherwise its normal calc function is installed.
Node_SetRun(Node * inNode,int inRun)260 void Node_SetRun(Node* inNode, int inRun) {
261     if (inRun) {
262         if (inNode->mCalcFunc == &Node_NullCalc) {
263             if (inNode->mIsGroup) {
264                 inNode->mCalcFunc = (NodeCalcFunc)&Group_Calc;
265             } else {
266                 inNode->mCalcFunc = (NodeCalcFunc)&Graph_Calc;
267             }
268             Node_StateMsg(inNode, kNode_On);
269         }
270     } else {
271         if (inNode->mCalcFunc != &Node_NullCalc) {
272             if (!inNode->mIsGroup && inNode->mCalcFunc == (NodeCalcFunc)&Graph_FirstCalc) {
273                 inNode->mCalcFunc = (NodeCalcFunc)&Graph_NullFirstCalc;
274             } else {
275                 inNode->mCalcFunc = (NodeCalcFunc)&Node_NullCalc;
276             }
277             Node_StateMsg(inNode, kNode_Off);
278         }
279     }
280 }
281 
282 
Node_Trace(Node * inNode)283 void Node_Trace(Node* inNode) {
284     if (inNode->mIsGroup) {
285         Group_Trace((Group*)inNode);
286     } else {
287         Graph_Trace((Graph*)inNode);
288     }
289 }
290 
Node_End(Node * inNode)291 void Node_End(Node* inNode) { inNode->mCalcFunc = (NodeCalcFunc)&Node_Delete; }
292 
293 
294 // send a trigger from a node to a client program.
295 // this function puts the trigger on a FIFO which is harvested by another thread that
296 // actually does the sending.
Node_SendTrigger(Node * inNode,int triggerID,float value)297 void Node_SendTrigger(Node* inNode, int triggerID, float value) {
298     World* world = inNode->mWorld;
299     if (!world->mRealTime)
300         return;
301 
302     TriggerMsg msg;
303     msg.mWorld = world;
304     msg.mNodeID = inNode->mID;
305     msg.mTriggerID = triggerID;
306     msg.mValue = value;
307     world->hw->mTriggers.Write(msg);
308 }
309 
310 // Send a reply from a node to a client program.
311 //
312 // This function puts the reply on a FIFO which is harvested by another thread that
313 // actually does the sending.
314 //
315 // NOTE: Only to be called from the realtime thread.
Node_SendReply(Node * inNode,int replyID,const char * cmdName,int numArgs,const float * values)316 void Node_SendReply(Node* inNode, int replyID, const char* cmdName, int numArgs, const float* values) {
317     World* world = inNode->mWorld;
318     if (!world->mRealTime)
319         return;
320 
321     const int cmdNameSize = strlen(cmdName);
322     void* mem = World_Alloc(world, cmdNameSize + numArgs * sizeof(float));
323     if (mem == nullptr)
324         return;
325 
326     NodeReplyMsg msg;
327     msg.mWorld = world;
328     msg.mNodeID = inNode->mID;
329     msg.mID = replyID;
330     msg.mValues = (float*)((char*)mem + cmdNameSize);
331     memcpy(msg.mValues, values, numArgs * sizeof(float));
332     msg.mNumArgs = numArgs;
333     msg.mCmdName = (char*)mem;
334     memcpy(msg.mCmdName, cmdName, cmdNameSize);
335     msg.mCmdNameSize = cmdNameSize;
336     msg.mRTMemory = mem;
337     world->hw->mNodeMsgs.Write(msg);
338 }
339 
Node_SendReply(Node * inNode,int replyID,const char * cmdName,float value)340 void Node_SendReply(Node* inNode, int replyID, const char* cmdName, float value) {
341     Node_SendReply(inNode, replyID, cmdName, 1, &value);
342 }
343 
344 // notify a client program of a node's state change.
345 // this function puts the message on a FIFO which is harvested by another thread that
346 // actually does the sending.
Node_StateMsg(Node * inNode,int inState)347 void Node_StateMsg(Node* inNode, int inState) {
348     if (inNode->mID < 0 && inState != kNode_Info)
349         return; // no notification for negative IDs
350 
351     World* world = inNode->mWorld;
352     if (!world->mRealTime)
353         return;
354 
355     NodeEndMsg msg;
356     msg.mWorld = world;
357     msg.mNodeID = inNode->mID;
358     msg.mGroupID = inNode->mParent ? inNode->mParent->mNode.mID : -1;
359     msg.mPrevNodeID = inNode->mPrev ? inNode->mPrev->mID : -1;
360     msg.mNextNodeID = inNode->mNext ? inNode->mNext->mID : -1;
361     if (inNode->mIsGroup) {
362         Group* group = (Group*)inNode;
363         msg.mIsGroup = 1;
364         msg.mHeadID = group->mHead ? group->mHead->mID : -1;
365         msg.mTailID = group->mTail ? group->mTail->mID : -1;
366     } else {
367         msg.mIsGroup = 0;
368         msg.mHeadID = -1;
369         msg.mTailID = -1;
370     }
371     msg.mState = inState;
372     world->hw->mNodeEnds.Write(msg);
373 }
374 
375 #include "SC_Unit.h"
376 
Unit_DoneAction(int doneAction,Unit * unit)377 void Unit_DoneAction(int doneAction, Unit* unit) {
378     switch (doneAction) {
379     case 1:
380         Node_SetRun(&unit->mParent->mNode, 0);
381         break;
382     case 2:
383         Node_End(&unit->mParent->mNode);
384         break;
385     case 3: {
386         Node_End(&unit->mParent->mNode);
387         Node* prev = unit->mParent->mNode.mPrev;
388         if (prev)
389             Node_End(prev);
390     } break;
391     case 4: {
392         Node_End(&unit->mParent->mNode);
393         Node* next = unit->mParent->mNode.mNext;
394         if (next)
395             Node_End(next);
396     } break;
397     case 5: {
398         Node_End(&unit->mParent->mNode);
399         Node* prev = unit->mParent->mNode.mPrev;
400         if (!prev)
401             break;
402         if (prev && prev->mIsGroup)
403             Group_DeleteAll((Group*)prev);
404         else
405             Node_End(prev);
406     } break;
407     case 6: {
408         Node_End(&unit->mParent->mNode);
409         Node* next = unit->mParent->mNode.mNext;
410         if (!next)
411             break;
412         if (next->mIsGroup)
413             Group_DeleteAll((Group*)next);
414         else
415             Node_End(next);
416     } break;
417     case 7: {
418         Node* node = &unit->mParent->mNode;
419         while (node) {
420             Node* prev = node->mPrev;
421             Node_End(node);
422             node = prev;
423         }
424     } break;
425     case 8: {
426         Node* node = &unit->mParent->mNode;
427         while (node) {
428             Node* next = node->mNext;
429             Node_End(node);
430             node = next;
431         }
432     } break;
433     case 9: {
434         Node_End(&unit->mParent->mNode);
435         Node* prev = unit->mParent->mNode.mPrev;
436         if (prev)
437             Node_SetRun(prev, 0);
438     } break;
439     case 10: {
440         Node_End(&unit->mParent->mNode);
441         Node* next = unit->mParent->mNode.mNext;
442         if (next)
443             Node_SetRun(next, 0);
444     } break;
445     case 11: {
446         Node_End(&unit->mParent->mNode);
447         Node* prev = unit->mParent->mNode.mPrev;
448         if (!prev)
449             break;
450         if (prev->mIsGroup)
451             Group_DeepFreeGraphs((Group*)prev);
452         else
453             Node_End(prev);
454     } break;
455     case 12: {
456         Node_End(&unit->mParent->mNode);
457         Node* next = unit->mParent->mNode.mNext;
458         if (!next)
459             break;
460         if (next->mIsGroup)
461             Group_DeepFreeGraphs((Group*)next);
462         else
463             Node_End(next);
464     } break;
465     case 13: {
466         Node* node = unit->mParent->mNode.mParent->mHead;
467         while (node) {
468             Node* next = node->mNext;
469             Node_End(node);
470             node = next;
471         }
472     } break;
473     case 14:
474         Node_End(&unit->mParent->mNode.mParent->mNode);
475         break;
476     case 15: {
477         Node_End(&unit->mParent->mNode);
478         Node* next = unit->mParent->mNode.mNext;
479         if (next)
480             Node_SetRun(next, 1);
481     } break;
482     }
483 }
484