common: prevent buffer overflow
[supercollider.git] / server / scsynth / SC_Node.cpp
blob55c62fd9691e89c42f711097aeb66f79a392cd95
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
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.
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.
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
22 #include "SC_Group.h"
23 #include "SC_SynthDef.h"
24 #include "SC_World.h"
25 #include "SC_Errors.h"
26 #include <stdio.h>
27 #include <stdexcept>
28 #include <limits.h>
29 #include "SC_Prototypes.h"
30 #include "SC_HiddenWorld.h"
31 #include "Unroll.h"
33 void Node_StateMsg(Node* inNode, int inState);
35 // create a new node
36 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;
47 if (World_GetNode(inWorld, inID)) {
48 return kSCErr_DuplicateNodeID;
51 Node* node = (Node*)World_Alloc(inWorld, def->mAllocSize);
53 node->mWorld = inWorld;
54 node->mDef = def;
55 node->mParent = 0;
56 node->mPrev = 0;
57 node->mNext = 0;
58 node->mIsGroup = false;
60 node->mID = inID;
61 node->mHash = Hash(inID);
62 if (!World_AddNode(inWorld, node)) {
63 World_Free(inWorld, node);
64 return kSCErr_TooManyNodes;
67 inWorld->hw->mRecentID = inID;
69 *outNode = node;
71 return kSCErr_None;
74 // node destructor
75 void Node_Dtor(Node *inNode)
77 Node_StateMsg(inNode, kNode_End);
78 Node_Remove(inNode);
79 World *world = inNode->mWorld;
80 world->hw->mNodeLib->Remove(inNode);
81 World_Free(world, inNode);
84 // remove a node from a group
85 void Node_Remove(Node* s)
87 Group *group = s->mParent;
89 if (s->mPrev) s->mPrev->mNext = s->mNext;
90 else if (group) group->mHead = s->mNext;
92 if (s->mNext) s->mNext->mPrev = s->mPrev;
93 else if (group) group->mTail = s->mPrev;
95 s->mPrev = s->mNext = 0;
96 s->mParent = 0;
100 // delete a node
101 void Node_Delete(Node* inNode)
103 if (inNode->mID == 0) return; // failed
104 if (inNode->mIsGroup) Group_Dtor((Group*)inNode);
105 else Graph_Dtor((Graph*)inNode);
108 // add a node after another one
109 void Node_AddAfter(Node* s, Node *afterThisOne)
111 if (!afterThisOne->mParent || s->mID == 0) return; // failed
113 s->mParent = afterThisOne->mParent;
114 s->mPrev = afterThisOne;
115 s->mNext = afterThisOne->mNext;
117 if (afterThisOne->mNext) afterThisOne->mNext->mPrev = s;
118 else s->mParent->mTail = s;
119 afterThisOne->mNext = s;
122 // add a node before another one
123 void Node_AddBefore(Node* s, Node *beforeThisOne)
125 if (!beforeThisOne->mParent || s->mID == 0) return; // failed
127 s->mParent = beforeThisOne->mParent;
128 s->mPrev = beforeThisOne->mPrev;
129 s->mNext = beforeThisOne;
131 if (beforeThisOne->mPrev) beforeThisOne->mPrev->mNext = s;
132 else s->mParent->mHead = s;
133 beforeThisOne->mPrev = s;
136 void Node_Replace(Node* s, Node *replaceThisOne)
138 //scprintf("->Node_Replace\n");
139 Group *group = replaceThisOne->mParent;
140 if (!group) return; // failed
141 if (s->mID == 0) return;
143 s->mParent = group;
144 s->mPrev = replaceThisOne->mPrev;
145 s->mNext = replaceThisOne->mNext;
147 if (s->mPrev) s->mPrev->mNext = s;
148 else group->mHead = s;
150 if (s->mNext) s->mNext->mPrev = s;
151 else group->mTail = s;
153 replaceThisOne->mPrev = replaceThisOne->mNext = 0;
154 replaceThisOne->mParent = 0;
156 Node_Delete(replaceThisOne);
157 //scprintf("<-Node_Replace\n");
160 // set a node's control so that it reads from a control bus - index argument
161 void Node_MapControl(Node* inNode, int inIndex, int inBus)
163 if (inNode->mIsGroup) {
164 Group_MapControl((Group*)inNode, inIndex, inBus);
165 } else {
166 Graph_MapControl((Graph*)inNode, inIndex, inBus);
170 // set a node's control so that it reads from a control bus - name argument
171 void Node_MapControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus)
173 if (inNode->mIsGroup) {
174 Group_MapControl((Group*)inNode, inHash, inName, inIndex, inBus);
175 } else {
176 Graph_MapControl((Graph*)inNode, inHash, inName, inIndex, inBus);
180 // set a node's control so that it reads from a control bus - index argument
181 void Node_MapAudioControl(Node* inNode, int inIndex, int inBus)
183 if (inNode->mIsGroup) {
184 Group_MapAudioControl((Group*)inNode, inIndex, inBus);
185 } else {
186 Graph_MapAudioControl((Graph*)inNode, inIndex, inBus);
190 // set a node's control so that it reads from a control bus - name argument
191 void Node_MapAudioControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus)
193 if (inNode->mIsGroup) {
194 Group_MapAudioControl((Group*)inNode, inHash, inName, inIndex, inBus);
195 } else {
196 Graph_MapAudioControl((Graph*)inNode, inHash, inName, inIndex, inBus);
200 // set a node's control value - index argument
201 void Node_SetControl(Node* inNode, int inIndex, float inValue)
203 if (inNode->mIsGroup) {
204 Group_SetControl((Group*)inNode, inIndex, inValue);
205 } else {
206 Graph_SetControl((Graph*)inNode, inIndex, inValue);
210 // set a node's control value - name argument
211 void Node_SetControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, float inValue)
213 if (inNode->mIsGroup) {
214 Group_SetControl((Group*)inNode, inHash, inName, inIndex, inValue);
215 } else {
216 Graph_SetControl((Graph*)inNode, inHash, inName, inIndex, inValue);
220 // this function can be installed using Node_SetRun to cause a node to do nothing
221 // during its execution time.
222 void Node_NullCalc(struct Node* /*inNode*/)
226 void Graph_FirstCalc(Graph *inGraph);
227 void Graph_NullFirstCalc(Graph *inGraph);
229 // if inRun is zero then the node's calc function is set to Node_NullCalc,
230 // otherwise its normal calc function is installed.
231 void Node_SetRun(Node* inNode, int inRun)
233 if (inRun) {
234 if (inNode->mCalcFunc == &Node_NullCalc) {
235 if (inNode->mIsGroup) {
236 inNode->mCalcFunc = (NodeCalcFunc)&Group_Calc;
237 } else {
238 inNode->mCalcFunc = (NodeCalcFunc)&Graph_Calc;
240 Node_StateMsg(inNode, kNode_On);
242 } else {
243 if (inNode->mCalcFunc != &Node_NullCalc) {
244 if (!inNode->mIsGroup && inNode->mCalcFunc == (NodeCalcFunc)&Graph_FirstCalc) {
245 inNode->mCalcFunc = (NodeCalcFunc)&Graph_NullFirstCalc;
246 } else {
247 inNode->mCalcFunc = (NodeCalcFunc)&Node_NullCalc;
249 Node_StateMsg(inNode, kNode_Off);
255 void Node_Trace(Node *inNode)
257 if (inNode->mIsGroup) {
258 Group_Trace((Group*)inNode);
259 } else {
260 Graph_Trace((Graph*)inNode);
264 void Node_End(Node* inNode)
266 inNode->mCalcFunc = (NodeCalcFunc)&Node_Delete;
270 // send a trigger from a node to a client program.
271 // this function puts the trigger on a FIFO which is harvested by another thread that
272 // actually does the sending.
273 void Node_SendTrigger(Node* inNode, int triggerID, float value)
275 World *world = inNode->mWorld;
276 if (!world->mRealTime) return;
278 TriggerMsg msg;
279 msg.mWorld = world;
280 msg.mNodeID = inNode->mID;
281 msg.mTriggerID = triggerID;
282 msg.mValue = value;
283 world->hw->mTriggers.Write(msg);
286 // Send a reply from a node to a client program.
288 // This function puts the reply on a FIFO which is harvested by another thread that
289 // actually does the sending.
291 // NOTE: Only to be called from the realtime thread.
292 void Node_SendReply(Node* inNode, int replyID, const char* cmdName, int numArgs, const float* values)
294 World *world = inNode->mWorld;
295 if (!world->mRealTime) return;
297 const int cmdNameSize = strlen(cmdName);
298 void* mem = World_Alloc(world, cmdNameSize + numArgs*sizeof(float));
299 if (mem == 0)
300 return;
302 NodeReplyMsg msg;
303 msg.mWorld = world;
304 msg.mNodeID = inNode->mID;
305 msg.mID = replyID;
306 msg.mValues = (float*)((char*)mem + cmdNameSize);
307 memcpy(msg.mValues, values, numArgs*sizeof(float));
308 msg.mNumArgs = numArgs;
309 msg.mCmdName = (char*)mem;
310 memcpy(msg.mCmdName, cmdName, cmdNameSize);
311 msg.mCmdNameSize = cmdNameSize;
312 msg.mRTMemory = mem;
313 world->hw->mNodeMsgs.Write(msg);
316 void Node_SendReply(Node* inNode, int replyID, const char* cmdName, float value)
318 Node_SendReply(inNode, replyID, cmdName, 1, &value);
321 // notify a client program of a node's state change.
322 // this function puts the message on a FIFO which is harvested by another thread that
323 // actually does the sending.
324 void Node_StateMsg(Node* inNode, int inState)
326 if (inNode->mID < 0 && inState != kNode_Info) return; // no notification for negative IDs
328 World *world = inNode->mWorld;
329 if (!world->mRealTime) return;
331 NodeEndMsg msg;
332 msg.mWorld = world;
333 msg.mNodeID = inNode->mID;
334 msg.mGroupID = inNode->mParent ? inNode->mParent->mNode.mID : -1 ;
335 msg.mPrevNodeID = inNode->mPrev ? inNode->mPrev->mID : -1 ;
336 msg.mNextNodeID = inNode->mNext ? inNode->mNext->mID : -1 ;
337 if (inNode->mIsGroup) {
338 Group *group = (Group*)inNode;
339 msg.mIsGroup = 1;
340 msg.mHeadID = group->mHead ? group->mHead->mID : -1;
341 msg.mTailID = group->mTail ? group->mTail->mID : -1;
342 } else {
343 msg.mIsGroup = 0;
344 msg.mHeadID = -1;
345 msg.mTailID = -1;
347 msg.mState = inState;
348 world->hw->mNodeEnds.Write(msg);
351 #include "SC_Unit.h"
353 void Unit_DoneAction(int doneAction, Unit *unit)
355 switch (doneAction)
357 case 1 :
358 Node_SetRun(&unit->mParent->mNode, 0);
359 break;
360 case 2 :
361 Node_End(&unit->mParent->mNode);
362 break;
363 case 3 :
365 Node_End(&unit->mParent->mNode);
366 Node* prev = unit->mParent->mNode.mPrev;
367 if (prev) Node_End(prev);
368 } break;
369 case 4 :
371 Node_End(&unit->mParent->mNode);
372 Node* next = unit->mParent->mNode.mNext;
373 if (next) Node_End(next);
374 } break;
375 case 5 :
377 Node_End(&unit->mParent->mNode);
378 Node* prev = unit->mParent->mNode.mPrev;
379 if (!prev) break;
380 if (prev && prev->mIsGroup) Group_DeleteAll((Group*)prev);
381 else Node_End(prev);
382 } break;
383 case 6 :
385 Node_End(&unit->mParent->mNode);
386 Node* next = unit->mParent->mNode.mNext;
387 if (!next) break;
388 if (next->mIsGroup) Group_DeleteAll((Group*)next);
389 else Node_End(next);
390 } break;
391 case 7 :
393 Node* node = &unit->mParent->mNode;
394 while (node) {
395 Node *prev = node->mPrev;
396 Node_End(node);
397 node = prev;
399 } break;
400 case 8 :
402 Node* node = &unit->mParent->mNode;
403 while (node) {
404 Node *next = node->mNext;
405 Node_End(node);
406 node = next;
408 } break;
409 case 9 :
411 Node_End(&unit->mParent->mNode);
412 Node* prev = unit->mParent->mNode.mPrev;
413 if (prev) Node_SetRun(prev, 0);
414 } break;
415 case 10 :
417 Node_End(&unit->mParent->mNode);
418 Node* next = unit->mParent->mNode.mNext;
419 if (next) Node_SetRun(next, 0);
420 } break;
421 case 11 :
423 Node_End(&unit->mParent->mNode);
424 Node* prev = unit->mParent->mNode.mPrev;
425 if (!prev) break;
426 if (prev->mIsGroup) Group_DeepFreeGraphs((Group*)prev);
427 else Node_End(prev);
428 } break;
429 case 12 :
431 Node_End(&unit->mParent->mNode);
432 Node* next = unit->mParent->mNode.mNext;
433 if (!next) break;
434 if (next->mIsGroup) Group_DeepFreeGraphs((Group*)next);
435 else Node_End(next);
436 } break;
437 case 13 :
439 Node* node = unit->mParent->mNode.mParent->mHead;
440 while (node) {
441 Node *next = node->mNext;
442 Node_End(node);
443 node = next;
445 } break;
446 case 14 :
447 Node_End(&unit->mParent->mNode.mParent->mNode);
448 break;