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
23 #include "SC_SynthDef.h"
25 #include "SC_Errors.h"
29 #include "SC_Prototypes.h"
30 #include "SC_HiddenWorld.h"
33 void Node_StateMsg(Node
* inNode
, int inState
);
36 int Node_New(World
*inWorld
, NodeDef
*def
, int32 inID
, Node
** outNode
)
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;
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
;
58 node
->mIsGroup
= false;
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
;
75 void Node_Dtor(Node
*inNode
)
77 Node_StateMsg(inNode
, kNode_End
);
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;
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;
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
);
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
);
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
);
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
);
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
);
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
);
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
)
234 if (inNode
->mCalcFunc
== &Node_NullCalc
) {
235 if (inNode
->mIsGroup
) {
236 inNode
->mCalcFunc
= (NodeCalcFunc
)&Group_Calc
;
238 inNode
->mCalcFunc
= (NodeCalcFunc
)&Graph_Calc
;
240 Node_StateMsg(inNode
, kNode_On
);
243 if (inNode
->mCalcFunc
!= &Node_NullCalc
) {
244 if (!inNode
->mIsGroup
&& inNode
->mCalcFunc
== (NodeCalcFunc
)&Graph_FirstCalc
) {
245 inNode
->mCalcFunc
= (NodeCalcFunc
)&Graph_NullFirstCalc
;
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
);
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;
280 msg
.mNodeID
= inNode
->mID
;
281 msg
.mTriggerID
= triggerID
;
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));
304 msg
.mNodeID
= inNode
->mID
;
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
;
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;
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
;
340 msg
.mHeadID
= group
->mHead
? group
->mHead
->mID
: -1;
341 msg
.mTailID
= group
->mTail
? group
->mTail
->mID
: -1;
347 msg
.mState
= inState
;
348 world
->hw
->mNodeEnds
.Write(msg
);
353 void Unit_DoneAction(int doneAction
, Unit
*unit
)
358 Node_SetRun(&unit
->mParent
->mNode
, 0);
361 Node_End(&unit
->mParent
->mNode
);
365 Node_End(&unit
->mParent
->mNode
);
366 Node
* prev
= unit
->mParent
->mNode
.mPrev
;
367 if (prev
) Node_End(prev
);
371 Node_End(&unit
->mParent
->mNode
);
372 Node
* next
= unit
->mParent
->mNode
.mNext
;
373 if (next
) Node_End(next
);
377 Node_End(&unit
->mParent
->mNode
);
378 Node
* prev
= unit
->mParent
->mNode
.mPrev
;
380 if (prev
&& prev
->mIsGroup
) Group_DeleteAll((Group
*)prev
);
385 Node_End(&unit
->mParent
->mNode
);
386 Node
* next
= unit
->mParent
->mNode
.mNext
;
388 if (next
->mIsGroup
) Group_DeleteAll((Group
*)next
);
393 Node
* node
= &unit
->mParent
->mNode
;
395 Node
*prev
= node
->mPrev
;
402 Node
* node
= &unit
->mParent
->mNode
;
404 Node
*next
= node
->mNext
;
411 Node_End(&unit
->mParent
->mNode
);
412 Node
* prev
= unit
->mParent
->mNode
.mPrev
;
413 if (prev
) Node_SetRun(prev
, 0);
417 Node_End(&unit
->mParent
->mNode
);
418 Node
* next
= unit
->mParent
->mNode
.mNext
;
419 if (next
) Node_SetRun(next
, 0);
423 Node_End(&unit
->mParent
->mNode
);
424 Node
* prev
= unit
->mParent
->mNode
.mPrev
;
426 if (prev
->mIsGroup
) Group_DeepFreeGraphs((Group
*)prev
);
431 Node_End(&unit
->mParent
->mNode
);
432 Node
* next
= unit
->mParent
->mNode
.mNext
;
434 if (next
->mIsGroup
) Group_DeepFreeGraphs((Group
*)next
);
439 Node
* node
= unit
->mParent
->mNode
.mParent
->mHead
;
441 Node
*next
= node
->mNext
;
447 Node_End(&unit
->mParent
->mNode
.mParent
->mNode
);