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_GraphDef.h"
25 #include "SC_UnitSpec.h"
26 #include "SC_UnitDef.h"
27 #include "SC_HiddenWorld.h"
29 #include "SC_WireSpec.h"
32 #include "SC_Prototypes.h"
33 #include "SC_Errors.h"
36 void Unit_ChooseMulAddFunc(Unit
* unit
);
38 ////////////////////////////////////////////////////////////////////////////////
40 void Graph_FirstCalc(Graph
*inGraph
);
42 void Graph_Dtor(Graph
*inGraph
)
44 //scprintf("->Graph_Dtor %d\n", inGraph->mNode.mID);
45 World
*world
= inGraph
->mNode
.mWorld
;
46 int numUnits
= inGraph
->mNumUnits
;
47 Unit
** graphUnits
= inGraph
->mUnits
;
48 if (inGraph
->mNode
.mCalcFunc
!= (NodeCalcFunc
)Graph_FirstCalc
) {
49 // the above test insures that dtors are not called if ctors have not been called.
50 for (int i
= 0; i
<numUnits
; ++i
) {
51 Unit
*unit
= graphUnits
[i
];
52 UnitDtorFunc dtor
= unit
->mUnitDef
->mUnitDtorFunc
;
53 if (dtor
) (dtor
)(unit
);
56 world
->mNumUnits
-= numUnits
;
59 GraphDef
* def
= GRAPHDEF(inGraph
);
60 if (--def
->mRefCount
<= 0) {
61 if (world
->mRealTime
) GraphDef_DeleteMsg(world
, def
);
62 else GraphDef_Free(def
);
65 Node_Dtor(&inGraph
->mNode
);
66 //scprintf("<-Graph_Dtor\n");
69 ////////////////////////////////////////////////////////////////////////////////
71 int Graph_New(struct World
*inWorld
, struct GraphDef
*inGraphDef
, int32 inID
,
72 struct sc_msg_iter
* args
, Graph
** outGraph
,bool argtype
)//true for normal args , false for setn type args
75 int err
= Node_New(inWorld
, &inGraphDef
->mNodeDef
, inID
, (Node
**)&graph
);
77 Graph_Ctor(inWorld
, inGraphDef
, graph
, args
,argtype
);
83 void Graph_Ctor(World
*inWorld
, GraphDef
*inGraphDef
, Graph
*graph
, sc_msg_iter
*msg
,bool argtype
)//true for normal args , false for setn type args
85 //scprintf("->Graph_Ctor\n");
87 // hit the memory allocator only once.
88 char *memory
= (char*)graph
+ sizeof(Graph
);
90 // allocate space for children
91 int numUnits
= inGraphDef
->mNumUnitSpecs
;
92 graph
->mNumUnits
= numUnits
;
93 inWorld
->mNumUnits
+= numUnits
;
94 inWorld
->mNumGraphs
++;
96 graph
->mUnits
= (Unit
**)memory
;
97 memory
+= inGraphDef
->mUnitsAllocSize
;
100 graph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_FirstCalc
;
103 graph
->mNumWires
= inGraphDef
->mNumWires
;
104 graph
->mWire
= (Wire
*)memory
;
105 memory
+= inGraphDef
->mWiresAllocSize
;
107 graph
->mNumCalcUnits
= inGraphDef
->mNumCalcUnits
;
108 graph
->mCalcUnits
= (Unit
**)memory
;
109 memory
+= inGraphDef
->mCalcUnitsAllocSize
;
111 // initialize controls
112 int numControls
= inGraphDef
->mNumControls
;
113 graph
->mNumControls
= numControls
;
114 graph
->mControls
= (float*)memory
;
115 memory
+= inGraphDef
->mControlAllocSize
;
117 graph
->mMapControls
= (float**)memory
;
118 memory
+= inGraphDef
->mMapControlsAllocSize
;
120 graph
->mControlRates
= (int*)memory
;
121 memory
+= inGraphDef
->mMapControlRatesAllocSize
;
124 float* graphControls
= graph
->mControls
;
125 float* initialControlValues
= inGraphDef
->mInitialControlValues
;
126 float** graphMapControls
= graph
->mMapControls
;
128 int* graphControlRates
= graph
->mControlRates
;
129 for (int i
=0; i
<numControls
; ++i
, ++graphControls
) {
130 *graphControls
= initialControlValues
[i
];
131 graphMapControls
[i
] = graphControls
;
133 graphControlRates
[i
] = 0; // init to 0 for now... control bus is 1, audio is 2
138 //if argtype == true -> normal args as always
139 //if argtype == false -> setn type args
141 while( msg
->remain()>=8) {
144 if (msg
->nextTag('i') == 's') {
145 int32
* name
= msg
->gets4();
146 int32 hash
= Hash(name
);
148 switch (msg
->nextTag('f') ) {
152 float32 value
= msg
->getf();
153 Graph_SetControl(graph
, hash
, name
, i
, value
);
158 const char* string
= msg
->gets();
159 if ( *string
== 'c') {
160 int bus
= sc_atoi(string
+1);
161 Graph_MapControl(graph
, hash
, name
, i
, bus
);
163 if (*string
== 'a') {
164 int bus
= sc_atoi(string
+1);
165 Graph_MapAudioControl(graph
, hash
, name
, i
, bus
);
184 int32 index
= msg
->geti();
186 switch (msg
->nextTag('f') ) {
190 float32 value
= msg
->getf();
191 Graph_SetControl(graph
, index
+ i
, value
);
196 const char* string
= msg
->gets();
197 if ( *string
== 'c') {
198 int bus
= sc_atoi(string
+1);
199 Graph_MapControl(graph
, index
+ i
, bus
);
201 if (*string
== 'a') {
202 int bus
= sc_atoi(string
+1);
203 Graph_MapAudioControl(graph
, index
+ i
, bus
);
228 // while( msg->remain()>=8) {
231 // if (msg->nextTag('i') == 's') {
232 // int32* name = msg->gets4();
233 // int32 hash = Hash(name);
234 // if (msg->nextTag('f') == '[' ) {
239 // if (msg->nextTag('f') == 's' ) {
240 // const char* string = msg->gets();
241 // if ( *string == 'c') {
242 // int bus = sc_atoi(string+1);
243 // Graph_MapControl(graph, hash, name, i, bus);
246 // if (msg->nextTag('f') == ']' ) {
250 // float32 value = msg->getf();
251 // Graph_SetControl(graph, hash, name, i, value);
258 // int32 index = msg->geti();
259 // if (msg->nextTag('f') == '[' ) {
264 // if (msg->nextTag('f') == 's') {
265 // const char* string = msg->gets();
266 // if (*string == 'c') {
267 // int bus = sc_atoi(string+1);
268 // Graph_MapControl(graph, index + i, bus);
271 // if (msg->nextTag('f') == ']' ) {
275 // float32 value = msg->getf();
276 // Graph_SetControl(graph, index + i, value);
288 while (msg
->remain()) {
289 if (msg
->nextTag('i') == 's') {
290 int32
* name
= msg
->gets4();
291 int32 hash
= Hash(name
);
292 int32 n
= msg
->geti();
293 for (int i
=0; msg
->remain() && i
<n
; ++i
) {
294 if (msg
->nextTag('f') == 's') {
295 const char* string
= msg
->gets();
296 if (*string
== 'c') {
297 int bus
= sc_atoi(string
+1);
298 Graph_MapControl(graph
, hash
, name
, i
, bus
);
299 //Node_MapControl(node, hash, name, i, bus);
301 if (*string
== 'a') {
302 int bus
= sc_atoi(string
+1);
303 Graph_MapAudioControl(graph
, hash
, name
, i
, bus
);
307 float32 value
= msg
->getf();
308 Graph_SetControl(graph
, hash
, name
, i
, value
);
309 //Node_SetControl(node, hash, name, i, value);
313 int32 index
= msg
->geti();
314 int32 n
= msg
->geti();
315 for (int i
=0; msg
->remain() && i
<n
; ++i
) {
316 if (msg
->nextTag('f') == 's') {
317 const char* string
= msg
->gets();
318 if (*string
== 'c') {
319 int bus
= sc_atoi(string
+1);
320 Graph_MapControl(graph
, index
+i
, bus
);
321 //Node_MapControl(node, index+i, bus);
323 if (*string
== 'a') {
324 int bus
= sc_atoi(string
+1);
325 Graph_MapAudioControl(graph
, index
+ i
, bus
);
329 float32 value
= msg
->getf();
330 Graph_SetControl(graph
, index
+i
, value
);
331 //Node_SetControl(node, index+i, value);
338 // set up scalar values
339 Wire
*graphWires
= graph
->mWire
;
340 int numConstants
= inGraphDef
->mNumConstants
;
342 float *constants
= inGraphDef
->mConstants
;
343 Wire
*wire
= graphWires
;
344 for (int i
=0; i
<numConstants
; ++i
, ++wire
) {
346 wire
->mCalcRate
= calc_ScalarRate
;
347 wire
->mBuffer
= &wire
->mScalarValue
;
348 wire
->mScalarValue
= constants
[i
];
352 graph
->mSampleOffset
= inWorld
->mSampleOffset
;
353 graph
->mSubsampleOffset
= inWorld
->mSubsampleOffset
;
354 graph
->mRGen
= inWorld
->mRGen
; // defaults to rgen zero.
356 graph
->mLocalAudioBusUnit
= NULL
;
357 graph
->mLocalControlBusUnit
= NULL
;
359 graph
->localBufNum
= 0;
360 graph
->localMaxBufNum
= 0; // this is set from synth
363 //scprintf("initialize units\n");
364 Unit
** calcUnits
= graph
->mCalcUnits
;
365 Unit
** graphUnits
= graph
->mUnits
;
368 float *bufspace
= inWorld
->hw
->mWireBufSpace
;
369 int wireCtr
= numConstants
;
370 UnitSpec
*unitSpec
= inGraphDef
->mUnitSpecs
;
371 for (int i
=0; i
<numUnits
; ++i
, ++unitSpec
) {
372 // construct unit from spec
373 Unit
*unit
= Unit_New(inWorld
, unitSpec
, memory
);
376 unit
->mParent
= graph
;
377 unit
->mParentIndex
= i
;
379 graphUnits
[i
] = unit
;
382 // hook up unit inputs
383 //scprintf("hook up unit inputs\n");
384 InputSpec
*inputSpec
= unitSpec
->mInputSpec
;
385 Wire
** unitInput
= unit
->mInput
;
386 float** unitInBuf
= unit
->mInBuf
;
387 int numInputs
= unitSpec
->mNumInputs
;
388 for (int j
=0; j
<numInputs
; ++j
, ++inputSpec
) {
389 Wire
*wire
= graphWires
+ inputSpec
->mWireIndex
;
391 unitInBuf
[j
] = wire
->mBuffer
;
396 // hook up unit outputs
397 //scprintf("hook up unit outputs\n");
398 Wire
** unitOutput
= unit
->mOutput
;
399 float** unitOutBuf
= unit
->mOutBuf
;
400 int numOutputs
= unitSpec
->mNumOutputs
;
401 Wire
*wire
= graphWires
+ wireCtr
;
402 wireCtr
+= numOutputs
;
403 int unitCalcRate
= unit
->mCalcRate
;
404 if (unitCalcRate
== calc_FullRate
) {
405 OutputSpec
*outputSpec
= unitSpec
->mOutputSpec
;
406 for (int j
=0; j
<numOutputs
; ++j
, ++wire
, ++outputSpec
) {
407 wire
->mFromUnit
= unit
;
408 wire
->mCalcRate
= calc_FullRate
;
409 wire
->mBuffer
= bufspace
+ outputSpec
->mBufferIndex
;
410 unitOutput
[j
] = wire
;
411 unitOutBuf
[j
] = wire
->mBuffer
;
413 calcUnits
[calcCtr
++] = unit
;
415 for (int j
=0; j
<numOutputs
; ++j
, ++wire
) {
416 wire
->mFromUnit
= unit
;
417 wire
->mCalcRate
= unitCalcRate
;
418 wire
->mBuffer
= &wire
->mScalarValue
;
419 unitOutput
[j
] = wire
;
420 unitOutBuf
[j
] = wire
->mBuffer
;
422 if (unitCalcRate
== calc_BufRate
) {
423 calcUnits
[calcCtr
++] = unit
;
429 inGraphDef
->mRefCount
++ ;
432 void Graph_RemoveID(World
* inWorld
, Graph
*inGraph
)
434 if (!World_RemoveNode(inWorld
, &inGraph
->mNode
)) {
435 int err
= kSCErr_Failed
; // shouldn't happen..
439 HiddenWorld
* hw
= inWorld
->hw
;
440 int id
= hw
->mHiddenID
= (hw
->mHiddenID
- 8) | 0x80000000;
441 inGraph
->mNode
.mID
= id
;
442 inGraph
->mNode
.mHash
= Hash(id
);
443 if (!World_AddNode(inWorld
, &inGraph
->mNode
)) {
444 scprintf("mysterious failure in Graph_RemoveID\n");
445 Node_Delete(&inGraph
->mNode
);
446 // enums are uncatchable. must throw an int.
447 int err
= kSCErr_Failed
; // shouldn't happen..
451 //inWorld->hw->mRecentID = id;
454 void Graph_FirstCalc(Graph
*inGraph
)
456 //scprintf("->Graph_FirstCalc\n");
457 int numUnits
= inGraph
->mNumUnits
;
458 Unit
**units
= inGraph
->mUnits
;
459 for (int i
=0; i
<numUnits
; ++i
) {
460 Unit
*unit
= units
[i
];
462 (*unit
->mUnitDef
->mUnitCtorFunc
)(unit
);
464 //scprintf("<-Graph_FirstCalc\n");
466 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_Calc
;
467 // now do actual graph calculation
471 void Node_NullCalc(struct Node
* /*inNode*/);
473 void Graph_NullFirstCalc(Graph
*inGraph
)
475 //scprintf("->Graph_FirstCalc\n");
476 int numUnits
= inGraph
->mNumUnits
;
477 Unit
**units
= inGraph
->mUnits
;
478 for (int i
=0; i
<numUnits
; ++i
) {
479 Unit
*unit
= units
[i
];
481 (*unit
->mUnitDef
->mUnitCtorFunc
)(unit
);
483 //scprintf("<-Graph_FirstCalc\n");
485 inGraph
->mNode
.mCalcFunc
= &Node_NullCalc
;
488 inline void Graph_Calc_unit(Unit
* unit
)
490 (unit
->mCalcFunc
)(unit
, unit
->mBufLength
);
493 void Graph_Calc(Graph
*inGraph
)
495 //scprintf("->Graph_Calc\n");
496 int numCalcUnits
= inGraph
->mNumCalcUnits
;
497 Unit
**calcUnits
= inGraph
->mCalcUnits
;
499 int unroll8
= numCalcUnits
/ 8;
500 int remain8
= numCalcUnits
% 8;
503 for (int j
= 0; j
!=unroll8
; i
+= 8, ++j
) {
504 Graph_Calc_unit(calcUnits
[i
]);
505 Graph_Calc_unit(calcUnits
[i
+1]);
506 Graph_Calc_unit(calcUnits
[i
+2]);
507 Graph_Calc_unit(calcUnits
[i
+3]);
508 Graph_Calc_unit(calcUnits
[i
+4]);
509 Graph_Calc_unit(calcUnits
[i
+5]);
510 Graph_Calc_unit(calcUnits
[i
+6]);
511 Graph_Calc_unit(calcUnits
[i
+7]);
514 int unroll4
= remain8
/ 4;
515 int remain4
= remain8
% 4;
517 Graph_Calc_unit(calcUnits
[i
]);
518 Graph_Calc_unit(calcUnits
[i
+1]);
519 Graph_Calc_unit(calcUnits
[i
+2]);
520 Graph_Calc_unit(calcUnits
[i
+3]);
524 int unroll2
= remain4
/ 2;
525 int remain2
= remain4
% 2;
527 Graph_Calc_unit(calcUnits
[i
]);
528 Graph_Calc_unit(calcUnits
[i
+1]);
533 Graph_Calc_unit(calcUnits
[i
]);
535 //scprintf("<-Graph_Calc\n");
538 void Graph_CalcTrace(Graph
*inGraph
);
539 void Graph_CalcTrace(Graph
*inGraph
)
541 int numCalcUnits
= inGraph
->mNumCalcUnits
;
542 Unit
**calcUnits
= inGraph
->mCalcUnits
;
543 scprintf("\nTRACE %d %s #units: %d\n", inGraph
->mNode
.mID
, inGraph
->mNode
.mDef
->mName
, numCalcUnits
);
544 for (int i
=0; i
<numCalcUnits
; ++i
) {
545 Unit
*unit
= calcUnits
[i
];
546 scprintf(" unit %d %s\n in ", i
, (char*)unit
->mUnitDef
->mUnitDefName
);
547 for (int j
=0; j
<unit
->mNumInputs
; ++j
) {
548 scprintf(" %g", ZIN0(j
));
551 (unit
->mCalcFunc
)(unit
, unit
->mBufLength
);
553 for (int j
=0; j
<unit
->mNumOutputs
; ++j
) {
554 scprintf(" %g", ZOUT0(j
));
558 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_Calc
;
561 void Graph_Trace(Graph
*inGraph
)
563 if (inGraph
->mNode
.mCalcFunc
== (NodeCalcFunc
)&Graph_Calc
) {
564 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_CalcTrace
;
569 int Graph_GetControl(Graph
* inGraph
, uint32 inIndex
, float& outValue
)
571 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return kSCErr_IndexOutOfRange
;
572 outValue
= inGraph
->mControls
[inIndex
];
576 int Graph_GetControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, float& outValue
)
578 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
579 ParamSpec
*spec
= table
->Get(inHash
, inName
);
580 if (!spec
) return kSCErr_IndexOutOfRange
;
581 return Graph_GetControl(inGraph
, spec
->mIndex
+ inIndex
, outValue
);
584 void Graph_SetControl(Graph
* inGraph
, uint32 inIndex
, float inValue
)
586 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
587 inGraph
->mControlRates
[inIndex
] = 0;
588 float *ptr
= inGraph
->mControls
+ inIndex
;
589 inGraph
->mMapControls
[inIndex
] = ptr
; // unmap the control
593 void Graph_SetControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, float inValue
)
595 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
596 ParamSpec
*spec
= table
->Get(inHash
, inName
);
597 if (spec
) Graph_SetControl(inGraph
, spec
->mIndex
+ inIndex
, inValue
);
602 void Graph_MapControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, uint32 inBus
)
604 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
605 ParamSpec
*spec
= table
->Get(inHash
, inName
);
606 if (spec
) Graph_MapControl(inGraph
, spec
->mIndex
+ inIndex
, inBus
);
609 void Graph_MapControl(Graph
* inGraph
, uint32 inIndex
, uint32 inBus
)
611 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
612 World
*world
= inGraph
->mNode
.mWorld
;
613 if (inBus
>= 0x80000000) {
614 inGraph
->mControlRates
[inIndex
] = 0;
615 inGraph
->mMapControls
[inIndex
] = inGraph
->mControls
+ inIndex
;
616 } else if (inBus
< world
->mNumControlBusChannels
) {
617 inGraph
->mControlRates
[inIndex
] = 1;
618 inGraph
->mMapControls
[inIndex
] = world
->mControlBus
+ inBus
;
622 void Graph_MapAudioControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, uint32 inBus
)
624 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
625 ParamSpec
*spec
= table
->Get(inHash
, inName
);
626 if (spec
) Graph_MapAudioControl(inGraph
, spec
->mIndex
+ inIndex
, inBus
);
629 void Graph_MapAudioControl(Graph
* inGraph
, uint32 inIndex
, uint32 inBus
)
631 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
632 World
*world
= inGraph
->mNode
.mWorld
;
633 // inGraph->mControlRates[inIndex] = 2;
634 /* what is the below doing??? it is unmapping by looking for negative ints */
635 if (inBus
>= 0x80000000) {
636 inGraph
->mControlRates
[inIndex
] = 0;
637 inGraph
->mMapControls
[inIndex
] = inGraph
->mControls
+ inIndex
;
638 } else if (inBus
< world
->mNumAudioBusChannels
) {
639 inGraph
->mControlRates
[inIndex
] = 2;
640 inGraph
->mMapControls
[inIndex
] = world
->mAudioBus
+ (inBus
* world
->mBufLength
);