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"
28 #include "SC_WorldOptions.h"
30 #include "SC_WireSpec.h"
33 #include "SC_Prototypes.h"
34 #include "SC_Errors.h"
37 void Unit_ChooseMulAddFunc(Unit
* unit
);
39 ////////////////////////////////////////////////////////////////////////////////
41 void Graph_FirstCalc(Graph
*inGraph
);
43 void Graph_Dtor(Graph
*inGraph
)
45 //scprintf("->Graph_Dtor %d\n", inGraph->mNode.mID);
46 World
*world
= inGraph
->mNode
.mWorld
;
47 uint32 numUnits
= inGraph
->mNumUnits
;
48 Unit
** graphUnits
= inGraph
->mUnits
;
49 if (inGraph
->mNode
.mCalcFunc
!= (NodeCalcFunc
)Graph_FirstCalc
) {
50 // the above test insures that dtors are not called if ctors have not been called.
51 for (uint32 i
= 0; i
<numUnits
; ++i
) {
52 Unit
*unit
= graphUnits
[i
];
53 UnitDtorFunc dtor
= unit
->mUnitDef
->mUnitDtorFunc
;
54 if (dtor
) (dtor
)(unit
);
57 world
->mNumUnits
-= numUnits
;
60 GraphDef
* def
= GRAPHDEF(inGraph
);
61 if (--def
->mRefCount
<= 0) {
62 if (world
->mRealTime
) GraphDef_DeleteMsg(world
, def
);
63 else GraphDef_Free(def
);
66 Node_Dtor(&inGraph
->mNode
);
67 //scprintf("<-Graph_Dtor\n");
70 ////////////////////////////////////////////////////////////////////////////////
72 int Graph_New(struct World
*inWorld
, struct GraphDef
*inGraphDef
, int32 inID
,
73 struct sc_msg_iter
* args
, Graph
** outGraph
,bool argtype
)//true for normal args , false for setn type args
76 int err
= Node_New(inWorld
, &inGraphDef
->mNodeDef
, inID
, (Node
**)&graph
);
78 Graph_Ctor(inWorld
, inGraphDef
, graph
, args
,argtype
);
84 void Graph_Ctor(World
*inWorld
, GraphDef
*inGraphDef
, Graph
*graph
, sc_msg_iter
*msg
,bool argtype
)//true for normal args , false for setn type args
86 //scprintf("->Graph_Ctor\n");
88 // hit the memory allocator only once.
89 char *memory
= (char*)graph
+ sizeof(Graph
);
91 // allocate space for children
92 uint32 numUnits
= inGraphDef
->mNumUnitSpecs
;
93 graph
->mNumUnits
= numUnits
;
94 inWorld
->mNumUnits
+= numUnits
;
95 inWorld
->mNumGraphs
++;
97 graph
->mUnits
= (Unit
**)memory
;
98 memory
+= inGraphDef
->mUnitsAllocSize
;
101 graph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_FirstCalc
;
104 graph
->mNumWires
= inGraphDef
->mNumWires
;
105 graph
->mWire
= (Wire
*)memory
;
106 memory
+= inGraphDef
->mWiresAllocSize
;
108 graph
->mNumCalcUnits
= inGraphDef
->mNumCalcUnits
;
109 graph
->mCalcUnits
= (Unit
**)memory
;
110 memory
+= inGraphDef
->mCalcUnitsAllocSize
;
112 // initialize controls
113 uint32 numControls
= inGraphDef
->mNumControls
;
114 graph
->mNumControls
= numControls
;
115 graph
->mControls
= (float*)memory
;
116 memory
+= inGraphDef
->mControlAllocSize
;
118 graph
->mMapControls
= (float**)memory
;
119 memory
+= inGraphDef
->mMapControlsAllocSize
;
121 graph
->mControlRates
= (int*)memory
;
122 memory
+= inGraphDef
->mMapControlRatesAllocSize
;
125 float* graphControls
= graph
->mControls
;
126 float* initialControlValues
= inGraphDef
->mInitialControlValues
;
127 float** graphMapControls
= graph
->mMapControls
;
129 int* graphControlRates
= graph
->mControlRates
;
130 for (uint32 i
=0; i
<numControls
; ++i
, ++graphControls
) {
131 *graphControls
= initialControlValues
[i
];
132 graphMapControls
[i
] = graphControls
;
134 graphControlRates
[i
] = 0; // init to 0 for now... control bus is 1, audio is 2
139 //if argtype == true -> normal args as always
140 //if argtype == false -> setn type args
142 while( msg
->remain()>=8) {
145 if (msg
->nextTag('i') == 's') {
146 int32
* name
= msg
->gets4();
147 int32 hash
= Hash(name
);
149 switch (msg
->nextTag('f') ) {
153 float32 value
= msg
->getf();
154 Graph_SetControl(graph
, hash
, name
, i
, value
);
159 const char* string
= msg
->gets();
160 if ( *string
== 'c') {
161 int bus
= sc_atoi(string
+1);
162 Graph_MapControl(graph
, hash
, name
, i
, bus
);
164 if (*string
== 'a') {
165 int bus
= sc_atoi(string
+1);
166 Graph_MapAudioControl(graph
, hash
, name
, i
, bus
);
185 int32 index
= msg
->geti();
187 switch (msg
->nextTag('f') ) {
191 float32 value
= msg
->getf();
192 Graph_SetControl(graph
, index
+ i
, value
);
197 const char* string
= msg
->gets();
198 if ( *string
== 'c') {
199 int bus
= sc_atoi(string
+1);
200 Graph_MapControl(graph
, index
+ i
, bus
);
202 if (*string
== 'a') {
203 int bus
= sc_atoi(string
+1);
204 Graph_MapAudioControl(graph
, index
+ i
, bus
);
229 // while( msg->remain()>=8) {
232 // if (msg->nextTag('i') == 's') {
233 // int32* name = msg->gets4();
234 // int32 hash = Hash(name);
235 // if (msg->nextTag('f') == '[' ) {
240 // if (msg->nextTag('f') == 's' ) {
241 // const char* string = msg->gets();
242 // if ( *string == 'c') {
243 // int bus = sc_atoi(string+1);
244 // Graph_MapControl(graph, hash, name, i, bus);
247 // if (msg->nextTag('f') == ']' ) {
251 // float32 value = msg->getf();
252 // Graph_SetControl(graph, hash, name, i, value);
259 // int32 index = msg->geti();
260 // if (msg->nextTag('f') == '[' ) {
265 // if (msg->nextTag('f') == 's') {
266 // const char* string = msg->gets();
267 // if (*string == 'c') {
268 // int bus = sc_atoi(string+1);
269 // Graph_MapControl(graph, index + i, bus);
272 // if (msg->nextTag('f') == ']' ) {
276 // float32 value = msg->getf();
277 // Graph_SetControl(graph, index + i, value);
289 while (msg
->remain()) {
290 if (msg
->nextTag('i') == 's') {
291 int32
* name
= msg
->gets4();
292 int32 hash
= Hash(name
);
293 int32 n
= msg
->geti();
294 for (int i
=0; msg
->remain() && i
<n
; ++i
) {
295 if (msg
->nextTag('f') == 's') {
296 const char* string
= msg
->gets();
297 if (*string
== 'c') {
298 int bus
= sc_atoi(string
+1);
299 Graph_MapControl(graph
, hash
, name
, i
, bus
);
300 //Node_MapControl(node, hash, name, i, bus);
302 if (*string
== 'a') {
303 int bus
= sc_atoi(string
+1);
304 Graph_MapAudioControl(graph
, hash
, name
, i
, bus
);
308 float32 value
= msg
->getf();
309 Graph_SetControl(graph
, hash
, name
, i
, value
);
310 //Node_SetControl(node, hash, name, i, value);
314 int32 index
= msg
->geti();
315 int32 n
= msg
->geti();
316 for (int i
=0; msg
->remain() && i
<n
; ++i
) {
317 if (msg
->nextTag('f') == 's') {
318 const char* string
= msg
->gets();
319 if (*string
== 'c') {
320 int bus
= sc_atoi(string
+1);
321 Graph_MapControl(graph
, index
+i
, bus
);
322 //Node_MapControl(node, index+i, bus);
324 if (*string
== 'a') {
325 int bus
= sc_atoi(string
+1);
326 Graph_MapAudioControl(graph
, index
+ i
, bus
);
330 float32 value
= msg
->getf();
331 Graph_SetControl(graph
, index
+i
, value
);
332 //Node_SetControl(node, index+i, value);
339 // set up scalar values
340 Wire
*graphWires
= graph
->mWire
;
341 int numConstants
= inGraphDef
->mNumConstants
;
343 float *constants
= inGraphDef
->mConstants
;
344 Wire
*wire
= graphWires
;
345 for (int i
=0; i
<numConstants
; ++i
, ++wire
) {
347 wire
->mCalcRate
= calc_ScalarRate
;
348 wire
->mBuffer
= &wire
->mScalarValue
;
349 wire
->mScalarValue
= constants
[i
];
353 graph
->mSampleOffset
= inWorld
->mSampleOffset
;
354 graph
->mSubsampleOffset
= inWorld
->mSubsampleOffset
;
355 graph
->mRGen
= inWorld
->mRGen
; // defaults to rgen zero.
357 graph
->mLocalAudioBusUnit
= NULL
;
358 graph
->mLocalControlBusUnit
= NULL
;
360 graph
->localBufNum
= 0;
361 graph
->localMaxBufNum
= 0; // this is set from synth
364 //scprintf("initialize units\n");
365 Unit
** calcUnits
= graph
->mCalcUnits
;
366 Unit
** graphUnits
= graph
->mUnits
;
369 float *bufspace
= inWorld
->hw
->mWireBufSpace
;
370 uint32 wireCtr
= numConstants
; // never more than numConstants + numOutputs
371 UnitSpec
*unitSpec
= inGraphDef
->mUnitSpecs
;
372 for (uint32 i
=0; i
<numUnits
; ++i
, ++unitSpec
) {
373 // construct unit from spec
374 Unit
*unit
= Unit_New(inWorld
, unitSpec
, memory
);
377 unit
->mParent
= graph
;
378 unit
->mParentIndex
= i
;
380 graphUnits
[i
] = unit
;
383 // hook up unit inputs
384 //scprintf("hook up unit inputs\n");
385 InputSpec
*inputSpec
= unitSpec
->mInputSpec
;
386 Wire
** unitInput
= unit
->mInput
;
387 float** unitInBuf
= unit
->mInBuf
;
388 uint32 numInputs
= unitSpec
->mNumInputs
;
389 for (uint32 j
=0; j
<numInputs
; ++j
, ++inputSpec
) {
390 Wire
*wire
= graphWires
+ inputSpec
->mWireIndex
;
392 unitInBuf
[j
] = wire
->mBuffer
;
397 // hook up unit outputs
398 //scprintf("hook up unit outputs\n");
399 Wire
** unitOutput
= unit
->mOutput
;
400 float** unitOutBuf
= unit
->mOutBuf
;
401 uint32 numOutputs
= unitSpec
->mNumOutputs
;
402 Wire
*wire
= graphWires
+ wireCtr
;
403 wireCtr
+= numOutputs
;
404 int unitCalcRate
= unit
->mCalcRate
;
405 if (unitCalcRate
== calc_FullRate
) {
406 OutputSpec
*outputSpec
= unitSpec
->mOutputSpec
;
407 for (uint32 j
=0; j
<numOutputs
; ++j
, ++wire
, ++outputSpec
) {
408 wire
->mFromUnit
= unit
;
409 wire
->mCalcRate
= calc_FullRate
;
410 wire
->mBuffer
= bufspace
+ outputSpec
->mBufferIndex
;
411 unitOutput
[j
] = wire
;
412 unitOutBuf
[j
] = wire
->mBuffer
;
414 calcUnits
[calcCtr
++] = unit
;
416 for (uint32 j
=0; j
<numOutputs
; ++j
, ++wire
) {
417 wire
->mFromUnit
= unit
;
418 wire
->mCalcRate
= unitCalcRate
;
419 wire
->mBuffer
= &wire
->mScalarValue
;
420 unitOutput
[j
] = wire
;
421 unitOutBuf
[j
] = wire
->mBuffer
;
423 if (unitCalcRate
== calc_BufRate
) {
424 calcUnits
[calcCtr
++] = unit
;
430 inGraphDef
->mRefCount
++ ;
433 void Graph_RemoveID(World
* inWorld
, Graph
*inGraph
)
435 if (!World_RemoveNode(inWorld
, &inGraph
->mNode
)) {
436 int err
= kSCErr_Failed
; // shouldn't happen..
440 HiddenWorld
* hw
= inWorld
->hw
;
441 int id
= hw
->mHiddenID
= (hw
->mHiddenID
- 8) | 0x80000000;
442 inGraph
->mNode
.mID
= id
;
443 inGraph
->mNode
.mHash
= Hash(id
);
444 if (!World_AddNode(inWorld
, &inGraph
->mNode
)) {
445 scprintf("mysterious failure in Graph_RemoveID\n");
446 Node_Delete(&inGraph
->mNode
);
447 // enums are uncatchable. must throw an int.
448 int err
= kSCErr_Failed
; // shouldn't happen..
452 //inWorld->hw->mRecentID = id;
455 void Graph_FirstCalc(Graph
*inGraph
)
457 //scprintf("->Graph_FirstCalc\n");
458 uint32 numUnits
= inGraph
->mNumUnits
;
459 Unit
**units
= inGraph
->mUnits
;
460 for (uint32 i
=0; i
<numUnits
; ++i
) {
461 Unit
*unit
= units
[i
];
463 (*unit
->mUnitDef
->mUnitCtorFunc
)(unit
);
465 //scprintf("<-Graph_FirstCalc\n");
467 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_Calc
;
468 // now do actual graph calculation
472 void Node_NullCalc(struct Node
* /*inNode*/);
474 void Graph_NullFirstCalc(Graph
*inGraph
)
476 //scprintf("->Graph_FirstCalc\n");
477 uint32 numUnits
= inGraph
->mNumUnits
;
478 Unit
**units
= inGraph
->mUnits
;
479 for (uint32 i
=0; i
<numUnits
; ++i
) {
480 Unit
*unit
= units
[i
];
482 (*unit
->mUnitDef
->mUnitCtorFunc
)(unit
);
484 //scprintf("<-Graph_FirstCalc\n");
486 inGraph
->mNode
.mCalcFunc
= &Node_NullCalc
;
489 inline void Graph_Calc_unit(Unit
* unit
)
491 (unit
->mCalcFunc
)(unit
, unit
->mBufLength
);
494 void Graph_Calc(Graph
*inGraph
)
496 //scprintf("->Graph_Calc\n");
497 uint32 numCalcUnits
= inGraph
->mNumCalcUnits
;
498 Unit
**calcUnits
= inGraph
->mCalcUnits
;
500 int unroll8
= numCalcUnits
/ 8;
501 int remain8
= numCalcUnits
% 8;
504 for (int j
= 0; j
!=unroll8
; i
+= 8, ++j
) {
505 Graph_Calc_unit(calcUnits
[i
]);
506 Graph_Calc_unit(calcUnits
[i
+1]);
507 Graph_Calc_unit(calcUnits
[i
+2]);
508 Graph_Calc_unit(calcUnits
[i
+3]);
509 Graph_Calc_unit(calcUnits
[i
+4]);
510 Graph_Calc_unit(calcUnits
[i
+5]);
511 Graph_Calc_unit(calcUnits
[i
+6]);
512 Graph_Calc_unit(calcUnits
[i
+7]);
515 int unroll4
= remain8
/ 4;
516 int remain4
= remain8
% 4;
518 Graph_Calc_unit(calcUnits
[i
]);
519 Graph_Calc_unit(calcUnits
[i
+1]);
520 Graph_Calc_unit(calcUnits
[i
+2]);
521 Graph_Calc_unit(calcUnits
[i
+3]);
525 int unroll2
= remain4
/ 2;
526 int remain2
= remain4
% 2;
528 Graph_Calc_unit(calcUnits
[i
]);
529 Graph_Calc_unit(calcUnits
[i
+1]);
534 Graph_Calc_unit(calcUnits
[i
]);
536 //scprintf("<-Graph_Calc\n");
539 void Graph_CalcTrace(Graph
*inGraph
);
540 void Graph_CalcTrace(Graph
*inGraph
)
542 uint32 numCalcUnits
= inGraph
->mNumCalcUnits
;
543 Unit
**calcUnits
= inGraph
->mCalcUnits
;
544 scprintf("\nTRACE %d %s #units: %d\n", inGraph
->mNode
.mID
, inGraph
->mNode
.mDef
->mName
, numCalcUnits
);
545 for (uint32 i
=0; i
<numCalcUnits
; ++i
) {
546 Unit
*unit
= calcUnits
[i
];
547 scprintf(" unit %d %s\n in ", i
, (char*)unit
->mUnitDef
->mUnitDefName
);
548 for (uint32 j
=0; j
<unit
->mNumInputs
; ++j
) {
549 scprintf(" %g", ZIN0(j
));
552 (unit
->mCalcFunc
)(unit
, unit
->mBufLength
);
554 for (uint32 j
=0; j
<unit
->mNumOutputs
; ++j
) {
555 scprintf(" %g", ZOUT0(j
));
559 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_Calc
;
562 void Graph_Trace(Graph
*inGraph
)
564 if (inGraph
->mNode
.mCalcFunc
== (NodeCalcFunc
)&Graph_Calc
) {
565 inGraph
->mNode
.mCalcFunc
= (NodeCalcFunc
)&Graph_CalcTrace
;
570 int Graph_GetControl(Graph
* inGraph
, uint32 inIndex
, float& outValue
)
572 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return kSCErr_IndexOutOfRange
;
573 outValue
= inGraph
->mControls
[inIndex
];
577 int Graph_GetControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, float& outValue
)
579 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
580 ParamSpec
*spec
= table
->Get(inHash
, inName
);
581 if (!spec
) return kSCErr_IndexOutOfRange
;
582 return Graph_GetControl(inGraph
, spec
->mIndex
+ inIndex
, outValue
);
585 void Graph_SetControl(Graph
* inGraph
, uint32 inIndex
, float inValue
)
587 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
588 inGraph
->mControlRates
[inIndex
] = 0;
589 float *ptr
= inGraph
->mControls
+ inIndex
;
590 inGraph
->mMapControls
[inIndex
] = ptr
; // unmap the control
594 void Graph_SetControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, float inValue
)
596 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
597 ParamSpec
*spec
= table
->Get(inHash
, inName
);
598 if (spec
) Graph_SetControl(inGraph
, spec
->mIndex
+ inIndex
, inValue
);
603 void Graph_MapControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, uint32 inBus
)
605 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
606 ParamSpec
*spec
= table
->Get(inHash
, inName
);
607 if (spec
) Graph_MapControl(inGraph
, spec
->mIndex
+ inIndex
, inBus
);
610 void Graph_MapControl(Graph
* inGraph
, uint32 inIndex
, uint32 inBus
)
612 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
613 World
*world
= inGraph
->mNode
.mWorld
;
614 if (inBus
>= 0x80000000) {
615 inGraph
->mControlRates
[inIndex
] = 0;
616 inGraph
->mMapControls
[inIndex
] = inGraph
->mControls
+ inIndex
;
617 } else if (inBus
< world
->mNumControlBusChannels
) {
618 inGraph
->mControlRates
[inIndex
] = 1;
619 inGraph
->mMapControls
[inIndex
] = world
->mControlBus
+ inBus
;
623 void Graph_MapAudioControl(Graph
* inGraph
, int32 inHash
, int32
*inName
, uint32 inIndex
, uint32 inBus
)
625 ParamSpecTable
* table
= GRAPH_PARAM_TABLE(inGraph
);
626 ParamSpec
*spec
= table
->Get(inHash
, inName
);
627 if (spec
) Graph_MapAudioControl(inGraph
, spec
->mIndex
+ inIndex
, inBus
);
630 void Graph_MapAudioControl(Graph
* inGraph
, uint32 inIndex
, uint32 inBus
)
632 if (inIndex
>= GRAPHDEF(inGraph
)->mNumControls
) return;
633 World
*world
= inGraph
->mNode
.mWorld
;
634 // inGraph->mControlRates[inIndex] = 2;
635 /* what is the below doing??? it is unmapping by looking for negative ints */
636 if (inBus
>= 0x80000000) {
637 inGraph
->mControlRates
[inIndex
] = 0;
638 inGraph
->mMapControls
[inIndex
] = inGraph
->mControls
+ inIndex
;
639 } else if (inBus
< world
->mNumAudioBusChannels
) {
640 inGraph
->mControlRates
[inIndex
] = 2;
641 inGraph
->mMapControls
[inIndex
] = world
->mAudioBus
+ (inBus
* world
->mBufLength
);