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