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