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_Win32Utils.h"
23 #include "SC_Graph.h"
24 #include "SC_GraphDef.h"
25 #include "SC_Unit.h"
26 #include "SC_UnitSpec.h"
27 #include "SC_UnitDef.h"
28 #include "SC_HiddenWorld.h"
29 #include "SC_WorldOptions.h"
30 #include "SC_Wire.h"
31 #include "SC_WireSpec.h"
32 #include <stdio.h>
33 #include <string.h>
34 #include "SC_Prototypes.h"
35 #include "SC_Errors.h"
36 #include "Unroll.h"
37 
38 void Unit_ChooseMulAddFunc(Unit* unit);
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 
42 void Graph_FirstCalc(Graph* inGraph);
43 
Graph_Dtor(Graph * inGraph)44 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)
55                 (dtor)(unit);
56         }
57     }
58     world->mNumUnits -= numUnits;
59     world->mNumGraphs--;
60 
61     GraphDef* def = GRAPHDEF(inGraph);
62     if (--def->mRefCount <= 0) {
63         if (world->mRealTime)
64             GraphDef_DeleteMsg(world, def);
65         else
66             GraphDef_Free(def);
67     }
68 
69     Node_Dtor(&inGraph->mNode);
70     // scprintf("<-Graph_Dtor\n");
71 }
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 
Graph_New(struct World * inWorld,struct GraphDef * inGraphDef,int32 inID,struct sc_msg_iter * args,Graph ** outGraph,bool argtype)75 int Graph_New(struct World* inWorld, struct GraphDef* inGraphDef, int32 inID, struct sc_msg_iter* args,
76               Graph** outGraph, bool argtype) // true for normal args , false for setn type args
77 {
78     Graph* graph;
79     int err = Node_New(inWorld, &inGraphDef->mNodeDef, inID, (Node**)&graph);
80     if (err)
81         return err;
82     Graph_Ctor(inWorld, inGraphDef, graph, args, argtype);
83     *outGraph = graph;
84     return err;
85 }
86 
87 
Graph_Ctor(World * inWorld,GraphDef * inGraphDef,Graph * graph,sc_msg_iter * msg,bool argtype)88 void Graph_Ctor(World* inWorld, GraphDef* inGraphDef, Graph* graph, sc_msg_iter* msg,
89                 bool argtype) // true for normal args , false for setn type args
90 {
91     // scprintf("->Graph_Ctor\n");
92 
93     // hit the memory allocator only once.
94     char* memory = (char*)graph + sizeof(Graph);
95 
96     // allocate space for children
97     uint32 numUnits = inGraphDef->mNumUnitSpecs;
98     graph->mNumUnits = numUnits;
99     inWorld->mNumUnits += numUnits;
100     inWorld->mNumGraphs++;
101     graph->mUnits = (Unit**)memory;
102     memory += inGraphDef->mUnitsAllocSize;
103 
104     // set calc func
105     graph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_FirstCalc;
106 
107     // allocate wires
108     graph->mNumWires = inGraphDef->mNumWires;
109     graph->mWire = (Wire*)memory;
110     memory += inGraphDef->mWiresAllocSize;
111 
112     graph->mNumCalcUnits = inGraphDef->mNumCalcUnits;
113     graph->mCalcUnits = (Unit**)memory;
114     memory += inGraphDef->mCalcUnitsAllocSize;
115 
116     // initialize controls
117     uint32 numControls = inGraphDef->mNumControls;
118     graph->mNumControls = numControls;
119     graph->mControls = (float*)memory;
120     memory += inGraphDef->mControlAllocSize;
121 
122     graph->mAudioBusOffsets = (int32*)memory;
123     memory += inGraphDef->mAudioMapBusOffsetSize;
124 
125     graph->mMapControls = (float**)memory;
126     memory += inGraphDef->mMapControlsAllocSize;
127 
128     graph->mControlRates = (int*)memory;
129     memory += inGraphDef->mMapControlRatesAllocSize;
130 
131     {
132         float* graphControls = graph->mControls;
133         float* initialControlValues = inGraphDef->mInitialControlValues;
134         float** graphMapControls = graph->mMapControls;
135         /* add */
136         int* graphControlRates = graph->mControlRates;
137         for (uint32 i = 0; i < numControls; ++i, ++graphControls) {
138             *graphControls = initialControlValues[i];
139             graphMapControls[i] = graphControls;
140             /* add */
141             graphControlRates[i] = 0; // init to 0 for now... control bus is 1, audio is 2
142             graph->mAudioBusOffsets[i] = -1;
143         }
144     }
145 
146     // set controls
147     // if argtype == true -> normal args as always
148     // if argtype == false -> setn type args
149     if (argtype) {
150         while (msg->remain() >= 8) {
151             int i = 0;
152             int loop = 0;
153             if (msg->nextTag('i') == 's') {
154                 int32* name = msg->gets4();
155                 int32 hash = Hash(name);
156                 do {
157                     switch (msg->nextTag('f')) {
158                     case 'f':
159                     case 'i': {
160                         float32 value = msg->getf();
161                         Graph_SetControl(graph, hash, name, i, value);
162                         break;
163                     }
164                     case 's': {
165                         const char* string = msg->gets();
166                         if (*string == 'c') {
167                             int bus = sc_atoi(string + 1);
168                             Graph_MapControl(graph, hash, name, i, bus);
169                         } else {
170                             if (*string == 'a') {
171                                 int bus = sc_atoi(string + 1);
172                                 Graph_MapAudioControl(graph, hash, name, i, bus);
173                             }
174                         }
175                         break;
176                     }
177                     case ']':
178                         msg->count++;
179                         loop -= 1;
180                         break;
181                     case '[':
182                         msg->count++;
183                         loop += 1;
184                         i -= 1;
185                         break;
186                     }
187                     ++i;
188                 } while (loop);
189             } else {
190                 int32 index = msg->geti();
191                 do {
192                     switch (msg->nextTag('f')) {
193                     case 'f':
194                     case 'i': {
195                         float32 value = msg->getf();
196                         Graph_SetControl(graph, index + i, value);
197                         break;
198                     }
199                     case 's': {
200                         const char* string = msg->gets();
201                         if (*string == 'c') {
202                             int bus = sc_atoi(string + 1);
203                             Graph_MapControl(graph, index + i, bus);
204                         } else {
205                             if (*string == 'a') {
206                                 int bus = sc_atoi(string + 1);
207                                 Graph_MapAudioControl(graph, index + i, bus);
208                             }
209                         }
210                         break;
211                     }
212                     case ']':
213                         msg->count++;
214                         loop -= 1;
215                         break;
216                     case '[':
217                         msg->count++;
218                         loop += 1;
219                         i -= 1;
220                         break;
221                     }
222                     ++i;
223                 } while (loop);
224             }
225         }
226     }
227 
228 
229     //{
230     //	    while( msg->remain()>=8) {
231     //		int i = 0;
232     //		int loop = 0;
233     //		if (msg->nextTag('i') == 's') {
234     //		    int32* name = msg->gets4();
235     //		    int32 hash = Hash(name);
236     //		    if (msg->nextTag('f') == '[' ) {
237     //			    msg->count++;
238     //			    loop = 1;
239     //		    }
240     //		    do {
241     //			if (msg->nextTag('f') == 's' ) {
242     //			    const char* string = msg->gets();
243     //			    if ( *string == 'c') {
244     //				int bus = sc_atoi(string+1);
245     //				Graph_MapControl(graph, hash, name, i, bus);
246     //			    }
247     //			} else {
248     //			    if (msg->nextTag('f') == ']' ) {
249     //				msg->count++;
250     //				loop = 0;
251     //			    } else {
252     //				float32 value = msg->getf();
253     //				Graph_SetControl(graph, hash, name, i, value);
254     //			    }
255     //			}
256     //			++i;
257     //		    }
258     //		    while (loop);
259     //		} else {
260     //		    int32 index = msg->geti();
261     //		    if (msg->nextTag('f') == '[' ) {
262     //			msg->count++;
263     //			loop = 1;
264     //		    }
265     //		    do {
266     //			if (msg->nextTag('f') == 's') {
267     //			    const char* string = msg->gets();
268     //			    if (*string == 'c') {
269     //				int bus = sc_atoi(string+1);
270     //				Graph_MapControl(graph, index + i, bus);
271     //			    }
272     //			} else {
273     //			    if (msg->nextTag('f') == ']' ) {
274     //				msg->count++;
275     //				loop = 0;
276     //			    } else {
277     //				float32 value = msg->getf();
278     //				Graph_SetControl(graph, index + i, value);
279     //			    }
280     //			}
281     //			++i;
282     //		    }
283     //		    while (loop);
284     //		}
285     //	    }
286     //
287     //	}
288     else {
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);
301                         } else {
302                             if (*string == 'a') {
303                                 int bus = sc_atoi(string + 1);
304                                 Graph_MapAudioControl(graph, hash, name, i, bus);
305                             }
306                         }
307                     } else {
308                         float32 value = msg->getf();
309                         Graph_SetControl(graph, hash, name, i, value);
310                         // Node_SetControl(node, hash, name, i, value);
311                     }
312                 }
313             } else {
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);
323                         } else {
324                             if (*string == 'a') {
325                                 int bus = sc_atoi(string + 1);
326                                 Graph_MapAudioControl(graph, index + i, bus);
327                             }
328                         }
329                     } else {
330                         float32 value = msg->getf();
331                         Graph_SetControl(graph, index + i, value);
332                         // Node_SetControl(node, index+i, value);
333                     }
334                 }
335             }
336         }
337     }
338 
339     // set up scalar values
340     Wire* graphWires = graph->mWire;
341     int numConstants = inGraphDef->mNumConstants;
342     {
343         float* constants = inGraphDef->mConstants;
344         Wire* wire = graphWires;
345         for (int i = 0; i < numConstants; ++i, ++wire) {
346             wire->mFromUnit = nullptr;
347             wire->mCalcRate = calc_ScalarRate;
348             wire->mBuffer = &wire->mScalarValue;
349             wire->mScalarValue = constants[i];
350         }
351     }
352 
353     graph->mSampleOffset = inWorld->mSampleOffset;
354     graph->mSubsampleOffset = inWorld->mSubsampleOffset;
355     graph->mRGen = inWorld->mRGen; // defaults to rgen zero.
356 
357     graph->mLocalAudioBusUnit = nullptr;
358     graph->mLocalControlBusUnit = nullptr;
359 
360     graph->localBufNum = 0;
361     graph->localMaxBufNum = 0; // this is set from synth
362 
363     // initialize units
364     // scprintf("initialize units\n");
365     Unit** calcUnits = graph->mCalcUnits;
366     Unit** graphUnits = graph->mUnits;
367     int calcCtr = 0;
368 
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);
375 
376         // set parent
377         unit->mParent = graph;
378         unit->mParentIndex = i;
379 
380         graphUnits[i] = unit;
381 
382         {
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;
391                 unitInput[j] = wire;
392                 unitInBuf[j] = wire->mBuffer;
393             }
394         }
395 
396         {
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;
413                 }
414                 calcUnits[calcCtr++] = unit;
415             } else {
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;
422                 }
423                 if (unitCalcRate == calc_BufRate) {
424                     calcUnits[calcCtr++] = unit;
425                 }
426             }
427         }
428     }
429 
430     inGraphDef->mRefCount++;
431 }
432 
Graph_FirstCalc(Graph * inGraph)433 void Graph_FirstCalc(Graph* inGraph) {
434     // scprintf("->Graph_FirstCalc\n");
435     uint32 numUnits = inGraph->mNumUnits;
436     Unit** units = inGraph->mUnits;
437     for (uint32 i = 0; i < numUnits; ++i) {
438         Unit* unit = units[i];
439         // call constructor
440         (*unit->mUnitDef->mUnitCtorFunc)(unit);
441     }
442     // scprintf("<-Graph_FirstCalc\n");
443 
444     inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_Calc;
445     // now do actual graph calculation
446     Graph_Calc(inGraph);
447 }
448 
449 void Node_NullCalc(struct Node* /*inNode*/);
450 
Graph_NullFirstCalc(Graph * inGraph)451 void Graph_NullFirstCalc(Graph* inGraph) {
452     // scprintf("->Graph_FirstCalc\n");
453     uint32 numUnits = inGraph->mNumUnits;
454     Unit** units = inGraph->mUnits;
455     for (uint32 i = 0; i < numUnits; ++i) {
456         Unit* unit = units[i];
457         // call constructor
458         (*unit->mUnitDef->mUnitCtorFunc)(unit);
459     }
460     // scprintf("<-Graph_FirstCalc\n");
461 
462     inGraph->mNode.mCalcFunc = &Node_NullCalc;
463 }
464 
Graph_Calc_unit(Unit * unit)465 inline void Graph_Calc_unit(Unit* unit) { (unit->mCalcFunc)(unit, unit->mBufLength); }
466 
Graph_Calc(Graph * inGraph)467 void Graph_Calc(Graph* inGraph) {
468     // scprintf("->Graph_Calc\n");
469     uint32 numCalcUnits = inGraph->mNumCalcUnits;
470     Unit** calcUnits = inGraph->mCalcUnits;
471 
472     int unroll8 = numCalcUnits / 8;
473     int remain8 = numCalcUnits % 8;
474     int i = 0;
475 
476     for (int j = 0; j != unroll8; i += 8, ++j) {
477         Graph_Calc_unit(calcUnits[i]);
478         Graph_Calc_unit(calcUnits[i + 1]);
479         Graph_Calc_unit(calcUnits[i + 2]);
480         Graph_Calc_unit(calcUnits[i + 3]);
481         Graph_Calc_unit(calcUnits[i + 4]);
482         Graph_Calc_unit(calcUnits[i + 5]);
483         Graph_Calc_unit(calcUnits[i + 6]);
484         Graph_Calc_unit(calcUnits[i + 7]);
485     }
486 
487     int unroll4 = remain8 / 4;
488     int remain4 = remain8 % 4;
489     if (unroll4) {
490         Graph_Calc_unit(calcUnits[i]);
491         Graph_Calc_unit(calcUnits[i + 1]);
492         Graph_Calc_unit(calcUnits[i + 2]);
493         Graph_Calc_unit(calcUnits[i + 3]);
494         i += 4;
495     }
496 
497     int unroll2 = remain4 / 2;
498     int remain2 = remain4 % 2;
499     if (unroll2) {
500         Graph_Calc_unit(calcUnits[i]);
501         Graph_Calc_unit(calcUnits[i + 1]);
502         i += 2;
503     }
504 
505     if (remain2)
506         Graph_Calc_unit(calcUnits[i]);
507 
508     // scprintf("<-Graph_Calc\n");
509 }
510 
511 void Graph_CalcTrace(Graph* inGraph);
Graph_CalcTrace(Graph * inGraph)512 void Graph_CalcTrace(Graph* inGraph) {
513     uint32 numCalcUnits = inGraph->mNumCalcUnits;
514     Unit** calcUnits = inGraph->mCalcUnits;
515     scprintf("\nTRACE %d  %s    #units: %d\n", inGraph->mNode.mID, inGraph->mNode.mDef->mName, numCalcUnits);
516     for (uint32 i = 0; i < numCalcUnits; ++i) {
517         Unit* unit = calcUnits[i];
518         scprintf("  unit %d %s\n    in ", i, (char*)unit->mUnitDef->mUnitDefName);
519         for (uint32 j = 0; j < unit->mNumInputs; ++j) {
520             scprintf(" %g", ZIN0(j));
521         }
522         scprintf("\n");
523         (unit->mCalcFunc)(unit, unit->mBufLength);
524         scprintf("    out");
525         for (uint32 j = 0; j < unit->mNumOutputs; ++j) {
526             scprintf(" %g", ZOUT0(j));
527         }
528         scprintf("\n");
529     }
530     inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_Calc;
531 }
532 
Graph_Trace(Graph * inGraph)533 void Graph_Trace(Graph* inGraph) {
534     if (inGraph->mNode.mCalcFunc == (NodeCalcFunc)&Graph_Calc) {
535         inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_CalcTrace;
536     }
537 }
538 
539 
Graph_GetControl(Graph * inGraph,uint32 inIndex,float & outValue)540 int Graph_GetControl(Graph* inGraph, uint32 inIndex, float& outValue) {
541     if (inIndex >= GRAPHDEF(inGraph)->mNumControls)
542         return kSCErr_IndexOutOfRange;
543     outValue = inGraph->mControls[inIndex];
544     return kSCErr_None;
545 }
546 
Graph_GetControl(Graph * inGraph,int32 inHash,int32 * inName,uint32 inIndex,float & outValue)547 int Graph_GetControl(Graph* inGraph, int32 inHash, int32* inName, uint32 inIndex, float& outValue) {
548     ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph);
549     ParamSpec* spec = table->Get(inHash, inName);
550     if (!spec || inIndex >= spec->mNumChannels)
551         return kSCErr_IndexOutOfRange;
552     return Graph_GetControl(inGraph, spec->mIndex + inIndex, outValue);
553 }
554 
Graph_SetControl(Graph * inGraph,uint32 inIndex,float inValue)555 void Graph_SetControl(Graph* inGraph, uint32 inIndex, float inValue) {
556     if (inIndex >= GRAPHDEF(inGraph)->mNumControls)
557         return;
558     inGraph->mControlRates[inIndex] = 0;
559     float* ptr = inGraph->mControls + inIndex;
560     inGraph->mMapControls[inIndex] = ptr; // unmap the control
561     *ptr = inValue;
562 }
563 
Graph_SetControl(Graph * inGraph,int32 inHash,int32 * inName,uint32 inIndex,float inValue)564 void Graph_SetControl(Graph* inGraph, int32 inHash, int32* inName, uint32 inIndex, float inValue) {
565     ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph);
566     ParamSpec* spec = table->Get(inHash, inName);
567     if (!spec || inIndex >= spec->mNumChannels)
568         return;
569     // printf("setting: %s: to value %f\n", spec->mName, inValue);
570     Graph_SetControl(inGraph, spec->mIndex + inIndex, inValue);
571 }
572 
573 
Graph_MapControl(Graph * inGraph,int32 inHash,int32 * inName,uint32 inIndex,uint32 inBus)574 void Graph_MapControl(Graph* inGraph, int32 inHash, int32* inName, uint32 inIndex, uint32 inBus) {
575     ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph);
576     ParamSpec* spec = table->Get(inHash, inName);
577     if (!spec || inIndex >= spec->mNumChannels)
578         return;
579     // printf("mapping: %s: to bus index %i\n", spec->mName, inBus);
580     Graph_MapControl(inGraph, spec->mIndex + inIndex, inBus);
581 }
582 
Graph_MapControl(Graph * inGraph,uint32 inIndex,uint32 inBus)583 void Graph_MapControl(Graph* inGraph, uint32 inIndex, uint32 inBus) {
584     if (inIndex >= GRAPHDEF(inGraph)->mNumControls)
585         return;
586     World* world = inGraph->mNode.mWorld;
587     if (inBus >= 0x80000000) {
588         inGraph->mControlRates[inIndex] = 0;
589         inGraph->mMapControls[inIndex] = inGraph->mControls + inIndex;
590     } else if (inBus < world->mNumControlBusChannels) {
591         inGraph->mControlRates[inIndex] = 1;
592         inGraph->mMapControls[inIndex] = world->mControlBus + inBus;
593     }
594 }
595 
Graph_MapAudioControl(Graph * inGraph,int32 inHash,int32 * inName,uint32 inIndex,uint32 inBus)596 void Graph_MapAudioControl(Graph* inGraph, int32 inHash, int32* inName, uint32 inIndex, uint32 inBus) {
597     ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph);
598     ParamSpec* spec = table->Get(inHash, inName);
599     if (!spec || inIndex >= spec->mNumChannels)
600         return;
601     // printf("mapping: %s: to bus index %i\n", spec->mName, inBus);
602     if (spec)
603         Graph_MapAudioControl(inGraph, spec->mIndex + inIndex, inBus);
604 }
605 
Graph_MapAudioControl(Graph * inGraph,uint32 inIndex,uint32 inBus)606 void Graph_MapAudioControl(Graph* inGraph, uint32 inIndex, uint32 inBus) {
607     if (inIndex >= GRAPHDEF(inGraph)->mNumControls)
608         return;
609     World* world = inGraph->mNode.mWorld;
610     /* what is the below doing??? it is unmapping by looking for negative ints */
611     if (inBus >= 0x80000000) {
612         inGraph->mControlRates[inIndex] = 0;
613         inGraph->mMapControls[inIndex] = inGraph->mControls + inIndex;
614     } else if (inBus < world->mNumAudioBusChannels) {
615         inGraph->mControlRates[inIndex] = 2;
616         inGraph->mAudioBusOffsets[inIndex] = inBus;
617         inGraph->mMapControls[inIndex] = world->mAudioBus + (inBus * world->mBufLength);
618     }
619 }
620