class library: Volume - remove debug message
[supercollider.git] / server / scsynth / SC_GraphDef.cpp
blob460f74e5b859f5e264e0acce165346ae750d102b
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 "clz.h"
23 #include "SC_Graph.h"
24 #include "SC_GraphDef.h"
25 #include "SC_Wire.h"
26 #include "SC_WireSpec.h"
27 #include "SC_UnitSpec.h"
28 #include "SC_UnitDef.h"
29 #include "SC_HiddenWorld.h"
30 #include "SC_WorldOptions.h"
31 #ifndef _MSC_VER
32 #include <dirent.h>
33 #endif //_MSC_VER
34 #include "ReadWriteMacros.h"
35 #include "SC_Prototypes.h"
36 #include "SC_CoreAudio.h"
37 #include "SC_DirUtils.h"
39 #ifdef _WIN32
40 #include "SC_Win32Utils.h"
41 #endif
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <sstream>
46 #include <stdexcept>
47 #include <string>
49 extern Malloc gMalloc;
51 int32 GetHash(ParamSpec* inParamSpec)
53 return inParamSpec->mHash;
56 int32* GetKey(ParamSpec* inParamSpec)
58 return inParamSpec->mName;
62 void ReadName(char*& buffer, int32* name);
63 void ReadName(char*& buffer, int32* name)
65 uint32 namelen = readUInt8(buffer);
66 if (namelen >= kSCNameByteLen) {
67 std::ostringstream os;
68 os << "name too long (> " << kSCNameByteLen - 1 << " chars): "
69 << std::string(buffer, namelen);
70 throw std::runtime_error(os.str());
72 memset(name, 0, kSCNameByteLen);
73 readData(buffer, (char*)name, namelen);
76 void ReadNodeDefName(char*& buffer, int32* name);
77 void ReadNodeDefName(char*& buffer, int32* name)
79 uint32 namelen = readUInt8(buffer);
80 if (namelen >= kSCNodeDefNameByteLen) {
81 std::ostringstream os;
82 os << "node definition name too long (> " << kSCNodeDefNameByteLen - 1 << " chars): "
83 << std::string(buffer, namelen);
84 throw std::runtime_error(os.str());
86 memset(name, 0, kSCNodeDefNameByteLen);
87 readData(buffer, (char*)name, namelen);
90 void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer);
91 void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer)
93 ReadName(buffer, inParamSpec->mName);
94 inParamSpec->mIndex = readInt32_be(buffer);
95 inParamSpec->mHash = Hash(inParamSpec->mName);
98 void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer);
99 void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer)
101 ReadName(buffer, inParamSpec->mName);
102 inParamSpec->mIndex = readInt16_be(buffer);
103 inParamSpec->mHash = Hash(inParamSpec->mName);
106 void InputSpec_Read(InputSpec* inInputSpec, char*& buffer);
107 void InputSpec_Read(InputSpec* inInputSpec, char*& buffer)
109 inInputSpec->mFromUnitIndex = readInt32_be(buffer);
110 inInputSpec->mFromOutputIndex = readInt32_be(buffer);
112 inInputSpec->mWireIndex = -1;
115 void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer);
116 void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer)
118 inInputSpec->mFromUnitIndex = (int16)readInt16_be(buffer);
119 inInputSpec->mFromOutputIndex = (int16)readInt16_be(buffer);
121 inInputSpec->mWireIndex = -1;
124 void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer);
125 void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer)
127 inOutputSpec->mCalcRate = readInt8(buffer);
128 inOutputSpec->mWireIndex = -1;
129 inOutputSpec->mBufferIndex = -1;
130 inOutputSpec->mNumConsumers = 0;
133 void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer);
134 void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer)
136 int32 name[kSCNameLen];
137 ReadName(buffer, name);
139 inUnitSpec->mUnitDef = GetUnitDef(name);
140 if (!inUnitSpec->mUnitDef) {
141 char str[256];
142 sprintf(str, "UGen '%s' not installed.", (char*)name);
143 throw std::runtime_error(str);
144 return;
146 inUnitSpec->mCalcRate = readInt8(buffer);
148 inUnitSpec->mNumInputs = readInt32_be(buffer);
149 inUnitSpec->mNumOutputs = readInt32_be(buffer);
150 inUnitSpec->mSpecialIndex = readInt16_be(buffer);
151 inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs);
152 inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs);
153 for (uint32 i=0; i<inUnitSpec->mNumInputs; ++i) {
154 InputSpec_Read(inUnitSpec->mInputSpec + i, buffer);
156 for (uint32 i=0; i<inUnitSpec->mNumOutputs; ++i) {
157 OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer);
159 uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs;
160 inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*));
163 void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer);
164 void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer)
166 int32 name[kSCNameLen];
167 ReadName(buffer, name);
169 inUnitSpec->mUnitDef = GetUnitDef(name);
170 if (!inUnitSpec->mUnitDef) {
171 char str[256];
172 sprintf(str, "UGen '%s' not installed.", (char*)name);
173 throw std::runtime_error(str);
174 return;
176 inUnitSpec->mCalcRate = readInt8(buffer);
178 inUnitSpec->mNumInputs = readInt16_be(buffer);
179 inUnitSpec->mNumOutputs = readInt16_be(buffer);
180 inUnitSpec->mSpecialIndex = readInt16_be(buffer);
181 inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs);
182 inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs);
183 for (uint32 i=0; i<inUnitSpec->mNumInputs; ++i) {
184 InputSpec_ReadVer1(inUnitSpec->mInputSpec + i, buffer);
186 for (uint32 i=0; i<inUnitSpec->mNumOutputs; ++i) {
187 OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer);
189 uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs;
190 inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*));
193 GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion);
194 GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion);
196 GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList);
197 GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList)
199 int32 magic = readInt32_be(buffer);
200 if (magic != (('S'<<24)|('C'<<16)|('g'<<8)|'f') /*'SCgf'*/) return inList;
202 int32 version = readInt32_be(buffer);
204 uint32 numDefs, i;
205 switch (version) {
206 case 2:
207 numDefs = readInt16_be(buffer);
209 for (i=0; i<numDefs; ++i) {
210 inList = GraphDef_Read(inWorld, buffer, inList, version);
212 return inList;
213 break;
214 case 1:
215 case 0:
216 numDefs = readInt16_be(buffer);
218 for (i=0; i<numDefs; ++i) {
219 inList = GraphDef_ReadVer1(inWorld, buffer, inList, version); // handles 1 and 0
221 return inList;
222 break;
224 default:
225 return inList;
226 break;
232 void ChooseMulAddFunc(GraphDef *graphDef, UnitSpec* unitSpec);
233 void DoBufferColoring(World *inWorld, GraphDef *inGraphDef);
235 void GraphDef_ReadVariant(World *inWorld, char*& buffer, GraphDef* inGraphDef, GraphDef* inVariant)
237 memcpy(inVariant, inGraphDef, sizeof(GraphDef));
239 inVariant->mNumVariants = 0;
240 inVariant->mVariants = 0;
242 ReadName(buffer, inVariant->mNodeDef.mName);
243 inVariant->mNodeDef.mHash = Hash(inVariant->mNodeDef.mName);
245 inVariant->mInitialControlValues = (float32*)malloc(sizeof(float32) * inGraphDef->mNumControls);
246 for (uint32 i=0; i<inGraphDef->mNumControls; ++i) {
247 inVariant->mInitialControlValues[i] = readFloat_be(buffer);
251 // ver 2
252 GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion)
254 int32 name[kSCNodeDefNameLen];
255 ReadNodeDefName(buffer, name);
257 GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef));
259 graphDef->mOriginal = graphDef;
261 graphDef->mNodeDef.mAllocSize = sizeof(Graph);
263 memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen);
265 graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName);
267 graphDef->mNumConstants = readInt32_be(buffer);
269 graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float));
270 for (uint32 i=0; i<graphDef->mNumConstants; ++i) {
271 graphDef->mConstants[i] = readFloat_be(buffer);
274 graphDef->mNumControls = readInt32_be(buffer);
275 graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls);
276 for (uint32 i=0; i<graphDef->mNumControls; ++i) {
277 graphDef->mInitialControlValues[i] = readFloat_be(buffer);
280 graphDef->mNumParamSpecs = readInt32_be(buffer);
281 if (graphDef->mNumParamSpecs) {
282 int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs);
283 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false);
284 graphDef->mParamSpecs = (ParamSpec*)malloc(graphDef->mNumParamSpecs * sizeof(ParamSpec));
285 for (uint32 i=0; i<graphDef->mNumParamSpecs; ++i) {
286 ParamSpec *paramSpec = graphDef->mParamSpecs + i;
287 ParamSpec_Read(paramSpec, buffer);
288 graphDef->mParamSpecTable->Add(paramSpec);
290 } else {
291 // empty table to eliminate test in Graph_SetControl
292 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false);
293 graphDef->mParamSpecs = 0;
296 graphDef->mNumWires = graphDef->mNumConstants;
297 graphDef->mNumUnitSpecs = readInt32_be(buffer);
298 graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs);
299 graphDef->mNumCalcUnits = 0;
300 for (uint32 i=0; i<graphDef->mNumUnitSpecs; ++i) {
301 UnitSpec *unitSpec = graphDef->mUnitSpecs + i;
302 UnitSpec_Read(unitSpec, buffer);
304 switch (unitSpec->mCalcRate)
306 case calc_ScalarRate :
307 unitSpec->mRateInfo = &inWorld->mBufRate;
308 break;
309 case calc_BufRate :
310 graphDef->mNumCalcUnits++;
311 unitSpec->mRateInfo = &inWorld->mBufRate;
312 break;
313 case calc_FullRate :
314 graphDef->mNumCalcUnits++;
315 unitSpec->mRateInfo = &inWorld->mFullRate;
316 break;
317 case calc_DemandRate :
318 unitSpec->mRateInfo = &inWorld->mBufRate;
319 break;
322 graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize;
323 graphDef->mNumWires += unitSpec->mNumOutputs;
326 DoBufferColoring(inWorld, graphDef);
328 graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire);
329 graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*);
330 graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*);
332 graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize;
333 graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize;
334 graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize;
336 graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float);
337 graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize;
339 graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*);
340 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize;
342 graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*);
343 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize;
346 graphDef->mNext = inList;
347 graphDef->mRefCount = 1;
349 graphDef->mNumVariants = readInt16_be(buffer);
350 if (graphDef->mNumVariants) {
351 graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef));
352 for (uint32 i=0; i<graphDef->mNumVariants; ++i) {
353 GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i);
357 return graphDef;
360 // ver 0 or 1
361 GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion)
363 int32 name[kSCNodeDefNameLen];
364 ReadNodeDefName(buffer, name);
366 GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef));
368 graphDef->mOriginal = graphDef;
370 graphDef->mNodeDef.mAllocSize = sizeof(Graph);
372 memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen);
374 graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName);
376 graphDef->mNumConstants = readInt16_be(buffer);
377 graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float));
378 for (uint32 i=0; i<graphDef->mNumConstants; ++i) {
379 graphDef->mConstants[i] = readFloat_be(buffer);
382 graphDef->mNumControls = readInt16_be(buffer);
383 graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls);
384 for (uint32 i=0; i<graphDef->mNumControls; ++i) {
385 graphDef->mInitialControlValues[i] = readFloat_be(buffer);
388 graphDef->mNumParamSpecs = readInt16_be(buffer);
389 if (graphDef->mNumParamSpecs) {
390 int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs);
391 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false);
392 graphDef->mParamSpecs = (ParamSpec*)malloc(graphDef->mNumParamSpecs * sizeof(ParamSpec));
393 for (uint32 i=0; i<graphDef->mNumParamSpecs; ++i) {
394 ParamSpec *paramSpec = graphDef->mParamSpecs + i;
395 ParamSpec_ReadVer1(paramSpec, buffer);
396 graphDef->mParamSpecTable->Add(paramSpec);
398 } else {
399 // empty table to eliminate test in Graph_SetControl
400 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false);
401 graphDef->mParamSpecs = 0;
404 graphDef->mNumWires = graphDef->mNumConstants;
405 graphDef->mNumUnitSpecs = readInt16_be(buffer);
406 graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs);
407 graphDef->mNumCalcUnits = 0;
408 for (uint32 i=0; i<graphDef->mNumUnitSpecs; ++i) {
409 UnitSpec *unitSpec = graphDef->mUnitSpecs + i;
410 UnitSpec_ReadVer1(unitSpec, buffer);
412 switch (unitSpec->mCalcRate)
414 case calc_ScalarRate :
415 unitSpec->mRateInfo = &inWorld->mBufRate;
416 break;
417 case calc_BufRate :
418 graphDef->mNumCalcUnits++;
419 unitSpec->mRateInfo = &inWorld->mBufRate;
420 break;
421 case calc_FullRate :
422 graphDef->mNumCalcUnits++;
423 unitSpec->mRateInfo = &inWorld->mFullRate;
424 break;
425 case calc_DemandRate :
426 unitSpec->mRateInfo = &inWorld->mBufRate;
427 break;
430 graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize;
431 graphDef->mNumWires += unitSpec->mNumOutputs;
434 DoBufferColoring(inWorld, graphDef);
436 graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire);
437 graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*);
438 graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*);
440 graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize;
441 graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize;
442 graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize;
444 graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float);
445 graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize;
447 graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*);
448 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize;
450 graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*);
451 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize;
454 graphDef->mNext = inList;
455 graphDef->mRefCount = 1;
457 if (inVersion >= 1) {
458 graphDef->mNumVariants = readInt16_be(buffer);
459 if (graphDef->mNumVariants) {
460 graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef));
461 for (uint32 i=0; i<graphDef->mNumVariants; ++i) {
462 GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i);
467 return graphDef;
471 void GraphDef_Define(World *inWorld, GraphDef *inList)
473 GraphDef *graphDef = inList;
474 while (graphDef) {
475 GraphDef *next = graphDef->mNext;
477 GraphDef* previousDef = World_GetGraphDef(inWorld, graphDef->mNodeDef.mName);
478 if (previousDef) {
479 World_RemoveGraphDef(inWorld, previousDef);
480 if (--previousDef->mRefCount == 0) {
481 GraphDef_DeleteMsg(inWorld, previousDef);
484 World_AddGraphDef(inWorld, graphDef);
485 graphDef->mNext = 0;
486 graphDef = next;
490 void GraphDef_Remove(World *inWorld, int32 *inName)
492 GraphDef* graphDef = World_GetGraphDef(inWorld, inName);
493 if (graphDef) {
494 World_RemoveGraphDef(inWorld, graphDef);
495 if (--graphDef->mRefCount == 0) {
496 GraphDef_DeleteMsg(inWorld, graphDef);
501 void GraphDef_DeleteMsg(World *inWorld, GraphDef *inDef)
503 DeleteGraphDefMsg msg;
504 msg.mDef = inDef;
505 inWorld->hw->mDeleteGraphDefs.Write(msg);
507 small_scpacket packet;
508 packet.adds("/d_removed");
509 packet.maketags(1);
510 packet.addtag(',');
511 packet.addtag('s');
512 packet.adds((char*)inDef->mNodeDef.mName);
514 ReplyAddress *users = inWorld->hw->mUsers;
515 int numUsers = inWorld->hw->mNumUsers;
516 for (int i=0; i<numUsers; ++i) {
517 SendReply(users+i, packet.data(), packet.size());
521 GraphDef* GraphDef_Recv(World *inWorld, char *buffer, GraphDef *inList)
524 try {
525 inList = GraphDefLib_Read(inWorld, buffer, inList);
526 } catch (std::exception& exc) {
527 scprintf("exception in GraphDef_Recv: %s\n", exc.what());
528 } catch (...) {
529 scprintf("unknown exception in GraphDef_Recv\n");
532 return inList;
535 GraphDef* GraphDef_LoadGlob(World *inWorld, const char *pattern, GraphDef *inList)
537 SC_GlobHandle* glob = sc_Glob(pattern);
538 if (!glob) return inList;
540 const char* filename;
541 while ((filename = sc_GlobNext(glob)) != 0) {
542 int len = strlen(filename);
543 if (strncmp(filename+len-9, ".scsyndef", 9)==0) {
544 inList = GraphDef_Load(inWorld, filename, inList);
546 // why? <sk>
547 GraphDef_Load(inWorld, filename, inList);
550 sc_GlobFree(glob);
551 return inList;
554 GraphDef* GraphDef_Load(World *inWorld, const char *filename, GraphDef *inList)
556 FILE *file = fopen(filename, "rb");
558 if (!file) {
559 scprintf("*** ERROR: can't fopen '%s'\n", filename);
560 return inList;
563 fseek(file, 0, SEEK_END);
564 int size = ftell(file);
565 char *buffer = (char*)malloc(size);
566 if (!buffer) {
567 scprintf("*** ERROR: can't malloc buffer size %d\n", size);
568 fclose(file);
569 return inList;
571 fseek(file, 0, SEEK_SET);
573 size_t readSize = fread(buffer, 1, size, file);
574 fclose(file);
576 if (readSize!= size) {
577 scprintf("*** ERROR: invalid fread\n", size);
578 free(buffer);
579 return inList;
582 try {
583 inList = GraphDefLib_Read(inWorld, buffer, inList);
584 } catch (std::exception& exc) {
585 scprintf("exception in GrafDef_Load: %s\n", exc.what());
586 scprintf("while reading file '%s'\n", filename);
587 } catch (...) {
588 scprintf("unknown exception in GrafDef_Load\n");
589 scprintf("while reading file '%s'\n", filename);
592 free(buffer);
594 return inList;
597 GraphDef* GraphDef_LoadDir(World *inWorld, char *dirname, GraphDef *inList)
599 SC_DirHandle *dir = sc_OpenDir(dirname);
600 if (!dir) {
601 scprintf("*** ERROR: open directory failed '%s'\n", dirname);
602 return inList;
605 for (;;) {
606 char diritem[MAXPATHLEN];
607 bool skipItem = false;
608 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
609 if (!validItem) break;
610 if (skipItem) continue;
612 if (sc_DirectoryExists(diritem)) {
613 inList = GraphDef_LoadDir(inWorld, diritem, inList);
614 } else {
615 int dnamelen = strlen(diritem);
616 if (strncmp(diritem+dnamelen-9, ".scsyndef", 9) == 0) {
617 inList = GraphDef_Load(inWorld, diritem, inList);
622 sc_CloseDir(dir);
623 return inList;
626 void UnitSpec_Free(UnitSpec *inUnitSpec);
627 void UnitSpec_Free(UnitSpec *inUnitSpec)
629 free(inUnitSpec->mInputSpec);
630 free(inUnitSpec->mOutputSpec);
633 void GraphDef_Free(GraphDef *inGraphDef)
635 if (inGraphDef != inGraphDef->mOriginal) return;
637 for (uint32 i=0; i<inGraphDef->mNumUnitSpecs; ++i) {
638 UnitSpec_Free(inGraphDef->mUnitSpecs + i);
640 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
641 free(inGraphDef->mVariants[i].mInitialControlValues);
643 delete inGraphDef->mParamSpecTable;
644 free(inGraphDef->mParamSpecs);
645 free(inGraphDef->mInitialControlValues);
646 free(inGraphDef->mConstants);
647 free(inGraphDef->mUnitSpecs);
648 free(inGraphDef->mVariants);
649 free(inGraphDef);
652 void NodeDef_Dump(NodeDef *inNodeDef)
654 scprintf("mName '%s'\n", (char*)inNodeDef->mName);
655 scprintf("mHash %d\n", inNodeDef->mHash);
656 scprintf("mAllocSize %lu\n", inNodeDef->mAllocSize);
659 void GraphDef_Dump(GraphDef *inGraphDef)
661 NodeDef_Dump(&inGraphDef->mNodeDef);
663 scprintf("mNumControls %d\n", inGraphDef->mNumControls);
664 scprintf("mNumWires %d\n", inGraphDef->mNumWires);
665 scprintf("mNumUnitSpecs %d\n", inGraphDef->mNumUnitSpecs);
666 scprintf("mNumWireBufs %d\n", inGraphDef->mNumWireBufs);
668 for (uint32 i=0; i<inGraphDef->mNumControls; ++i) {
669 scprintf(" %d mInitialControlValues %g\n", i, inGraphDef->mInitialControlValues[i]);
672 for (uint32 i=0; i<inGraphDef->mNumWires; ++i) {
673 //WireSpec_Dump(inGraphDef->mWireSpec + i);
675 for (uint32 i=0; i<inGraphDef->mNumUnitSpecs; ++i) {
676 //UnitSpec_Dump(inGraphDef->mUnitSpecs + i);
681 SynthBufferAllocator
683 var nextBufIndex = 0;
684 var stack;
685 var refs;
687 *new {
688 ^super.new.init
690 init {
691 refs = Bag.new;
693 alloc { arg count;
694 var bufNumber;
695 if (stack.size > 0, {
696 bufNumber = stack.pop
698 bufNumber = nextBufIndex;
699 nextBufIndex = nextBufIndex + 1;
701 refs.add(bufNumber, count);
702 ^bufNumber
704 release { arg bufNumber;
705 refs.remove(bufNumber);
706 if (refs.includes(bufNumber).not, { stack = stack.add(bufNumber) });
708 numBufs { ^nextBufIndex }
712 struct BufColorAllocator
714 int16 *refs;
715 int16 *stack;
716 int16 stackPtr;
717 int16 nextIndex;
718 int16 refsMaxSize;
719 int16 stackMaxSize;
721 BufColorAllocator();
722 ~BufColorAllocator();
724 uint32 alloc(uint32 count);
725 bool release(int inIndex);
726 int NumBufs() { return nextIndex; }
729 inline BufColorAllocator::BufColorAllocator()
731 refsMaxSize = 32;
732 stackMaxSize = 32;
733 refs = (int16*)calloc(refsMaxSize, sizeof(int16));
734 stack = (int16*)calloc(stackMaxSize, sizeof(int16));
735 stackPtr = 0;
736 nextIndex = 0;
739 inline BufColorAllocator::~BufColorAllocator()
741 free(refs);
742 free(stack);
745 inline uint32 BufColorAllocator::alloc(uint32 count)
747 uint32 outIndex;
748 if (stackPtr) {
749 outIndex = stack[--stackPtr];
750 } else {
751 outIndex = nextIndex++;
753 if (outIndex >= refsMaxSize) {
754 refs = (int16*)realloc(refs, refsMaxSize*2*sizeof(int16));
755 memset(refs + refsMaxSize, 0, refsMaxSize*sizeof(int16));
756 refsMaxSize *= 2;
758 refs[outIndex] = count;
759 return outIndex;
762 inline bool BufColorAllocator::release(int inIndex)
764 if (refs[inIndex] == 0) return false;
765 if (--refs[inIndex] == 0) {
766 if (stackPtr >= stackMaxSize) {
767 stack = (int16*)realloc(stack, stackMaxSize*2*sizeof(int16));
768 memset(stack + stackMaxSize, 0, stackMaxSize*sizeof(int16));
769 stackMaxSize *= 2;
771 stack[stackPtr++] = inIndex;
773 return true;
776 static void ReleaseInputBuffers(GraphDef *inGraphDef, UnitSpec *unitSpec, BufColorAllocator& bufColor)
778 for (int64 i=(int64)(unitSpec->mNumInputs)-1; i>=0; --i) {
779 InputSpec *inputSpec = unitSpec->mInputSpec + i;
780 if (inputSpec->mFromUnitIndex >= 0) {
781 UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex;
782 OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex;
783 inputSpec->mWireIndex = outputSpec->mWireIndex;
784 if (outputSpec->mCalcRate == calc_FullRate) {
786 if (unitSpec->mCalcRate == calc_DemandRate)
787 // we never release any input buffers of demand-rate ugens
788 continue;
790 if (!bufColor.release(outputSpec->mBufferIndex)) {
791 scprintf("buffer coloring error: tried to release output with zero count\n");
792 scprintf("output: %d %s %d\n", inputSpec->mFromUnitIndex,
793 outUnit->mUnitDef->mUnitDefName, inputSpec->mFromOutputIndex);
794 scprintf("input: %s %d\n", unitSpec->mUnitDef->mUnitDefName, i);
795 throw std::runtime_error("buffer coloring error.");
798 } else {
799 inputSpec->mWireIndex = inputSpec->mFromOutputIndex;
804 static void AllocOutputBuffers(UnitSpec *unitSpec, BufColorAllocator& bufColor, int32& wireIndexCtr)
806 //scprintf("AllocOutputBuffers %s numoutputs %d\n", unitSpec->mUnitDef->mUnitDefName, unitSpec->mNumOutputs);
807 for (uint32 i=0; i<unitSpec->mNumOutputs; ++i) {
808 OutputSpec *outputSpec = unitSpec->mOutputSpec + i;
809 outputSpec->mWireIndex = wireIndexCtr++;
810 if (outputSpec->mCalcRate == calc_FullRate) {
811 uint32 bufIndex = bufColor.alloc(outputSpec->mNumConsumers);
812 outputSpec->mBufferIndex = bufIndex;
817 void DoBufferColoring(World *inWorld, GraphDef *inGraphDef)
819 // count consumers of outputs
820 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
821 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
822 for (uint32 i=0; i<unitSpec->mNumInputs; ++i) {
823 InputSpec *inputSpec = unitSpec->mInputSpec + i;
824 if (inputSpec->mFromUnitIndex >= 0) {
825 UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex;
826 OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex;
827 outputSpec->mNumConsumers ++;
832 // buffer coloring
834 BufColorAllocator bufColor;
835 int32 wireIndexCtr = inGraphDef->mNumConstants; // mNumConstants is a uint32, but limited to int32 in OSC
836 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
837 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
838 if (unitSpec->mUnitDef->mFlags & kUnitDef_CantAliasInputsToOutputs) {
839 // set wire index, alloc outputs
840 AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr);
841 // set wire index, release inputs
842 ReleaseInputBuffers(inGraphDef, unitSpec, bufColor);
843 } else {
844 // set wire index, release inputs
845 ReleaseInputBuffers(inGraphDef, unitSpec, bufColor);
846 // set wire index, alloc outputs
847 AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr);
851 inGraphDef->mNumWireBufs = bufColor.NumBufs();
852 if (inWorld->mRunning)
854 // cannot reallocate interconnect buffers while running audio.
855 if (inGraphDef->mNumWireBufs > inWorld->hw->mMaxWireBufs) {
856 throw std::runtime_error("exceeded number of interconnect buffers.");
858 } else {
859 inWorld->hw->mMaxWireBufs = sc_max(inWorld->hw->mMaxWireBufs, inGraphDef->mNumWireBufs);
863 // multiply buf indices by buf length for proper offset
864 int bufLength = inWorld->mBufLength;
865 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
866 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
867 for (uint32 i=0; i<unitSpec->mNumOutputs; ++i) {
868 OutputSpec *outputSpec = unitSpec->mOutputSpec + i;
869 if (outputSpec->mCalcRate == calc_FullRate) {
870 outputSpec->mBufferIndex *= bufLength;