common: prevent buffer overflow
[supercollider.git] / server / scsynth / SC_Graph.cpp
blob6985696395cc049561c5840226271da8f04cec8d
1 /*
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
22 #include "SC_Graph.h"
23 #include "SC_GraphDef.h"
24 #include "SC_Unit.h"
25 #include "SC_UnitSpec.h"
26 #include "SC_UnitDef.h"
27 #include "SC_HiddenWorld.h"
28 #include "SC_Wire.h"
29 #include "SC_WireSpec.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include "SC_Prototypes.h"
33 #include "SC_Errors.h"
34 #include "Unroll.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;
57 world->mNumGraphs --;
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
74 Graph* graph;
75 int err = Node_New(inWorld, &inGraphDef->mNodeDef, inID, (Node**)&graph);
76 if (err) return err;
77 Graph_Ctor(inWorld, inGraphDef, graph, args,argtype);
78 *outGraph = graph;
79 return err;
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;
99 // set calc func
100 graph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_FirstCalc;
102 // allocate wires
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;
127 /* add */
128 int* graphControlRates = graph->mControlRates;
129 for (int i=0; i<numControls; ++i, ++graphControls) {
130 *graphControls = initialControlValues[i];
131 graphMapControls[i] = graphControls;
132 /* add */
133 graphControlRates[i] = 0; // init to 0 for now... control bus is 1, audio is 2
137 // set controls
138 //if argtype == true -> normal args as always
139 //if argtype == false -> setn type args
140 if(argtype) {
141 while( msg->remain()>=8) {
142 int i = 0;
143 int loop = 0;
144 if (msg->nextTag('i') == 's') {
145 int32* name = msg->gets4();
146 int32 hash = Hash(name);
147 do {
148 switch (msg->nextTag('f') ) {
149 case 'f' :
150 case 'i' :
152 float32 value = msg->getf();
153 Graph_SetControl(graph, hash, name, i, value);
154 break;
156 case 's' :
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);
162 } else {
163 if (*string == 'a') {
164 int bus = sc_atoi(string+1);
165 Graph_MapAudioControl(graph, hash, name, i, bus);
168 break;
170 case ']':
171 msg->count++;
172 loop -= 1;
173 break;
174 case '[':
175 msg->count++;
176 loop += 1;
177 i -= 1;
178 break;
180 ++i;
182 while (loop);
183 } else {
184 int32 index = msg->geti();
185 do {
186 switch (msg->nextTag('f') ) {
187 case 'f' :
188 case 'i' :
190 float32 value = msg->getf();
191 Graph_SetControl(graph, index + i, value);
192 break;
194 case 's' :
196 const char* string = msg->gets();
197 if ( *string == 'c') {
198 int bus = sc_atoi(string+1);
199 Graph_MapControl(graph, index + i, bus);
200 } else {
201 if (*string == 'a') {
202 int bus = sc_atoi(string+1);
203 Graph_MapAudioControl(graph, index + i, bus);
206 break;
208 case ']':
209 msg->count++;
210 loop -= 1;
211 break;
212 case '[':
213 msg->count++;
214 loop += 1;
215 i -= 1;
216 break;
218 ++i;
220 while (loop);
228 // while( msg->remain()>=8) {
229 // int i = 0;
230 // int loop = 0;
231 // if (msg->nextTag('i') == 's') {
232 // int32* name = msg->gets4();
233 // int32 hash = Hash(name);
234 // if (msg->nextTag('f') == '[' ) {
235 // msg->count++;
236 // loop = 1;
237 // }
238 // do {
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);
244 // }
245 // } else {
246 // if (msg->nextTag('f') == ']' ) {
247 // msg->count++;
248 // loop = 0;
249 // } else {
250 // float32 value = msg->getf();
251 // Graph_SetControl(graph, hash, name, i, value);
252 // }
253 // }
254 // ++i;
255 // }
256 // while (loop);
257 // } else {
258 // int32 index = msg->geti();
259 // if (msg->nextTag('f') == '[' ) {
260 // msg->count++;
261 // loop = 1;
262 // }
263 // do {
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);
269 // }
270 // } else {
271 // if (msg->nextTag('f') == ']' ) {
272 // msg->count++;
273 // loop = 0;
274 // } else {
275 // float32 value = msg->getf();
276 // Graph_SetControl(graph, index + i, value);
277 // }
278 // }
279 // ++i;
280 // }
281 // while (loop);
282 // }
283 // }
285 // }
286 else{
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);
300 } else {
301 if (*string == 'a') {
302 int bus = sc_atoi(string+1);
303 Graph_MapAudioControl(graph, hash, name, i, bus);
306 } else {
307 float32 value = msg->getf();
308 Graph_SetControl(graph, hash, name, i, value);
309 //Node_SetControl(node, hash, name, i, value);
312 } else {
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);
322 } else {
323 if (*string == 'a') {
324 int bus = sc_atoi(string+1);
325 Graph_MapAudioControl(graph, index + i, bus);
328 } else {
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) {
345 wire->mFromUnit = 0;
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
362 // initialize units
363 //scprintf("initialize units\n");
364 Unit** calcUnits = graph->mCalcUnits;
365 Unit** graphUnits = graph->mUnits;
366 int calcCtr=0;
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);
375 // set parent
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;
390 unitInput[j] = wire;
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;
414 } else {
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..
436 throw err;
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..
448 throw err;
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];
461 // call constructor
462 (*unit->mUnitDef->mUnitCtorFunc)(unit);
464 //scprintf("<-Graph_FirstCalc\n");
466 inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_Calc;
467 // now do actual graph calculation
468 Graph_Calc(inGraph);
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];
480 // call constructor
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;
501 int i = 0;
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;
516 if (unroll4) {
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]);
521 i+=4;
524 int unroll2 = remain4 / 2;
525 int remain2 = remain4 % 2;
526 if (unroll2) {
527 Graph_Calc_unit(calcUnits[i]);
528 Graph_Calc_unit(calcUnits[i+1]);
529 i += 2;
532 if (remain2)
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));
550 scprintf("\n");
551 (unit->mCalcFunc)(unit, unit->mBufLength);
552 scprintf(" out");
553 for (int j=0; j<unit->mNumOutputs; ++j) {
554 scprintf(" %g", ZOUT0(j));
556 scprintf("\n");
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];
573 return kSCErr_None;
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
590 *ptr = inValue;
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);