Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / scsynth / SC_GraphDef.cpp
blob5b8dd27bb68ff6a56b61fd78ea4b0e36f9638397
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 #ifndef _MSC_VER
31 #include <dirent.h>
32 #endif //_MSC_VER
33 #include "ReadWriteMacros.h"
34 #include "SC_Prototypes.h"
35 #include "SC_CoreAudio.h"
36 #include "SC_DirUtils.h"
38 #ifdef _WIN32
39 #include "SC_Win32Utils.h"
40 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sstream>
45 #include <stdexcept>
46 #include <string>
48 extern Malloc gMalloc;
50 int32 GetHash(ParamSpec* inParamSpec)
52 return inParamSpec->mHash;
55 int32* GetKey(ParamSpec* inParamSpec)
57 return inParamSpec->mName;
61 void ReadName(char*& buffer, int32* name);
62 void ReadName(char*& buffer, int32* name)
64 uint32 namelen = readUInt8(buffer);
65 if (namelen >= kSCNameByteLen) {
66 std::ostringstream os;
67 os << "name too long (> " << kSCNameByteLen - 1 << " chars): "
68 << std::string(buffer, namelen);
69 throw std::runtime_error(os.str());
71 memset(name, 0, kSCNameByteLen);
72 readData(buffer, (char*)name, namelen);
75 void ReadNodeDefName(char*& buffer, int32* name);
76 void ReadNodeDefName(char*& buffer, int32* name)
78 uint32 namelen = readUInt8(buffer);
79 if (namelen >= kSCNodeDefNameByteLen) {
80 std::ostringstream os;
81 os << "node definition name too long (> " << kSCNodeDefNameByteLen - 1 << " chars): "
82 << std::string(buffer, namelen);
83 throw std::runtime_error(os.str());
85 memset(name, 0, kSCNodeDefNameByteLen);
86 readData(buffer, (char*)name, namelen);
89 void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer);
90 void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer)
92 ReadName(buffer, inParamSpec->mName);
93 inParamSpec->mIndex = readInt32_be(buffer);
94 inParamSpec->mHash = Hash(inParamSpec->mName);
97 void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer);
98 void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer)
100 ReadName(buffer, inParamSpec->mName);
101 inParamSpec->mIndex = readInt16_be(buffer);
102 inParamSpec->mHash = Hash(inParamSpec->mName);
105 void InputSpec_Read(InputSpec* inInputSpec, char*& buffer);
106 void InputSpec_Read(InputSpec* inInputSpec, char*& buffer)
108 inInputSpec->mFromUnitIndex = readInt32_be(buffer);
109 inInputSpec->mFromOutputIndex = readInt32_be(buffer);
111 inInputSpec->mWireIndex = -1;
114 void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer);
115 void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer)
117 inInputSpec->mFromUnitIndex = (int16)readInt16_be(buffer);
118 inInputSpec->mFromOutputIndex = (int16)readInt16_be(buffer);
120 inInputSpec->mWireIndex = -1;
123 void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer);
124 void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer)
126 inOutputSpec->mCalcRate = readInt8(buffer);
127 inOutputSpec->mWireIndex = -1;
128 inOutputSpec->mBufferIndex = -1;
129 inOutputSpec->mNumConsumers = 0;
132 void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer);
133 void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer)
135 int32 name[kSCNameLen];
136 ReadName(buffer, name);
138 inUnitSpec->mUnitDef = GetUnitDef(name);
139 if (!inUnitSpec->mUnitDef) {
140 char str[256];
141 sprintf(str, "UGen '%s' not installed.", (char*)name);
142 throw std::runtime_error(str);
143 return;
145 inUnitSpec->mCalcRate = readInt8(buffer);
147 inUnitSpec->mNumInputs = readInt32_be(buffer);
148 inUnitSpec->mNumOutputs = readInt32_be(buffer);
149 inUnitSpec->mSpecialIndex = readInt16_be(buffer);
150 inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs);
151 inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs);
152 for (uint32 i=0; i<inUnitSpec->mNumInputs; ++i) {
153 InputSpec_Read(inUnitSpec->mInputSpec + i, buffer);
155 for (uint32 i=0; i<inUnitSpec->mNumOutputs; ++i) {
156 OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer);
158 uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs;
159 inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*));
162 void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer);
163 void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer)
165 int32 name[kSCNameLen];
166 ReadName(buffer, name);
168 inUnitSpec->mUnitDef = GetUnitDef(name);
169 if (!inUnitSpec->mUnitDef) {
170 char str[256];
171 sprintf(str, "UGen '%s' not installed.", (char*)name);
172 throw std::runtime_error(str);
173 return;
175 inUnitSpec->mCalcRate = readInt8(buffer);
177 inUnitSpec->mNumInputs = readInt16_be(buffer);
178 inUnitSpec->mNumOutputs = readInt16_be(buffer);
179 inUnitSpec->mSpecialIndex = readInt16_be(buffer);
180 inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs);
181 inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs);
182 for (uint32 i=0; i<inUnitSpec->mNumInputs; ++i) {
183 InputSpec_ReadVer1(inUnitSpec->mInputSpec + i, buffer);
185 for (uint32 i=0; i<inUnitSpec->mNumOutputs; ++i) {
186 OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer);
188 uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs;
189 inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*));
192 GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion);
193 GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion);
195 GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList);
196 GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList)
198 int32 magic = readInt32_be(buffer);
199 if (magic != (('S'<<24)|('C'<<16)|('g'<<8)|'f') /*'SCgf'*/) return inList;
201 int32 version = readInt32_be(buffer);
203 uint32 numDefs, i;
204 switch (version) {
205 case 2:
206 numDefs = readInt16_be(buffer);
208 for (i=0; i<numDefs; ++i) {
209 inList = GraphDef_Read(inWorld, buffer, inList, version);
211 return inList;
212 break;
213 case 1:
214 case 0:
215 numDefs = readInt16_be(buffer);
217 for (i=0; i<numDefs; ++i) {
218 inList = GraphDef_ReadVer1(inWorld, buffer, inList, version); // handles 1 and 0
220 return inList;
221 break;
223 default:
224 return inList;
225 break;
231 void ChooseMulAddFunc(GraphDef *graphDef, UnitSpec* unitSpec);
232 void DoBufferColoring(World *inWorld, GraphDef *inGraphDef);
234 void GraphDef_ReadVariant(World *inWorld, char*& buffer, GraphDef* inGraphDef, GraphDef* inVariant)
236 memcpy(inVariant, inGraphDef, sizeof(GraphDef));
238 inVariant->mNumVariants = 0;
239 inVariant->mVariants = 0;
241 ReadName(buffer, inVariant->mNodeDef.mName);
242 inVariant->mNodeDef.mHash = Hash(inVariant->mNodeDef.mName);
244 inVariant->mInitialControlValues = (float32*)malloc(sizeof(float32) * inGraphDef->mNumControls);
245 for (uint32 i=0; i<inGraphDef->mNumControls; ++i) {
246 inVariant->mInitialControlValues[i] = readFloat_be(buffer);
250 // ver 2
251 GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion)
253 int32 name[kSCNodeDefNameLen];
254 ReadNodeDefName(buffer, name);
256 GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef));
258 graphDef->mOriginal = graphDef;
260 graphDef->mNodeDef.mAllocSize = sizeof(Graph);
262 memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen);
264 graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName);
266 graphDef->mNumConstants = readInt32_be(buffer);
268 graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float));
269 for (uint32 i=0; i<graphDef->mNumConstants; ++i) {
270 graphDef->mConstants[i] = readFloat_be(buffer);
273 graphDef->mNumControls = readInt32_be(buffer);
274 graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls);
275 for (uint32 i=0; i<graphDef->mNumControls; ++i) {
276 graphDef->mInitialControlValues[i] = readFloat_be(buffer);
279 graphDef->mNumParamSpecs = readInt32_be(buffer);
280 if (graphDef->mNumParamSpecs) {
281 int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs);
282 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false);
283 graphDef->mParamSpecs = (ParamSpec*)malloc(graphDef->mNumParamSpecs * sizeof(ParamSpec));
284 for (uint32 i=0; i<graphDef->mNumParamSpecs; ++i) {
285 ParamSpec *paramSpec = graphDef->mParamSpecs + i;
286 ParamSpec_Read(paramSpec, buffer);
287 graphDef->mParamSpecTable->Add(paramSpec);
289 } else {
290 // empty table to eliminate test in Graph_SetControl
291 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false);
292 graphDef->mParamSpecs = 0;
295 graphDef->mNumWires = graphDef->mNumConstants;
296 graphDef->mNumUnitSpecs = readInt32_be(buffer);
297 graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs);
298 graphDef->mNumCalcUnits = 0;
299 for (uint32 i=0; i<graphDef->mNumUnitSpecs; ++i) {
300 UnitSpec *unitSpec = graphDef->mUnitSpecs + i;
301 UnitSpec_Read(unitSpec, buffer);
303 switch (unitSpec->mCalcRate)
305 case calc_ScalarRate :
306 unitSpec->mRateInfo = &inWorld->mBufRate;
307 break;
308 case calc_BufRate :
309 graphDef->mNumCalcUnits++;
310 unitSpec->mRateInfo = &inWorld->mBufRate;
311 break;
312 case calc_FullRate :
313 graphDef->mNumCalcUnits++;
314 unitSpec->mRateInfo = &inWorld->mFullRate;
315 break;
316 case calc_DemandRate :
317 unitSpec->mRateInfo = &inWorld->mBufRate;
318 break;
321 graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize;
322 graphDef->mNumWires += unitSpec->mNumOutputs;
325 DoBufferColoring(inWorld, graphDef);
327 graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire);
328 graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*);
329 graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*);
331 graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize;
332 graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize;
333 graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize;
335 graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float);
336 graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize;
338 graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*);
339 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize;
341 graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*);
342 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize;
345 graphDef->mNext = inList;
346 graphDef->mRefCount = 1;
348 graphDef->mNumVariants = readInt16_be(buffer);
349 if (graphDef->mNumVariants) {
350 graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef));
351 for (uint32 i=0; i<graphDef->mNumVariants; ++i) {
352 GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i);
356 return graphDef;
359 // ver 0 or 1
360 GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion)
362 int32 name[kSCNodeDefNameLen];
363 ReadNodeDefName(buffer, name);
365 GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef));
367 graphDef->mOriginal = graphDef;
369 graphDef->mNodeDef.mAllocSize = sizeof(Graph);
371 memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen);
373 graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName);
375 graphDef->mNumConstants = readInt16_be(buffer);
376 graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float));
377 for (uint32 i=0; i<graphDef->mNumConstants; ++i) {
378 graphDef->mConstants[i] = readFloat_be(buffer);
381 graphDef->mNumControls = readInt16_be(buffer);
382 graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls);
383 for (uint32 i=0; i<graphDef->mNumControls; ++i) {
384 graphDef->mInitialControlValues[i] = readFloat_be(buffer);
387 graphDef->mNumParamSpecs = readInt16_be(buffer);
388 if (graphDef->mNumParamSpecs) {
389 int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs);
390 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false);
391 graphDef->mParamSpecs = (ParamSpec*)malloc(graphDef->mNumParamSpecs * sizeof(ParamSpec));
392 for (uint32 i=0; i<graphDef->mNumParamSpecs; ++i) {
393 ParamSpec *paramSpec = graphDef->mParamSpecs + i;
394 ParamSpec_ReadVer1(paramSpec, buffer);
395 graphDef->mParamSpecTable->Add(paramSpec);
397 } else {
398 // empty table to eliminate test in Graph_SetControl
399 graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false);
400 graphDef->mParamSpecs = 0;
403 graphDef->mNumWires = graphDef->mNumConstants;
404 graphDef->mNumUnitSpecs = readInt16_be(buffer);
405 graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs);
406 graphDef->mNumCalcUnits = 0;
407 for (uint32 i=0; i<graphDef->mNumUnitSpecs; ++i) {
408 UnitSpec *unitSpec = graphDef->mUnitSpecs + i;
409 UnitSpec_ReadVer1(unitSpec, buffer);
411 switch (unitSpec->mCalcRate)
413 case calc_ScalarRate :
414 unitSpec->mRateInfo = &inWorld->mBufRate;
415 break;
416 case calc_BufRate :
417 graphDef->mNumCalcUnits++;
418 unitSpec->mRateInfo = &inWorld->mBufRate;
419 break;
420 case calc_FullRate :
421 graphDef->mNumCalcUnits++;
422 unitSpec->mRateInfo = &inWorld->mFullRate;
423 break;
424 case calc_DemandRate :
425 unitSpec->mRateInfo = &inWorld->mBufRate;
426 break;
429 graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize;
430 graphDef->mNumWires += unitSpec->mNumOutputs;
433 DoBufferColoring(inWorld, graphDef);
435 graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire);
436 graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*);
437 graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*);
439 graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize;
440 graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize;
441 graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize;
443 graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float);
444 graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize;
446 graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*);
447 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize;
449 graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*);
450 graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize;
453 graphDef->mNext = inList;
454 graphDef->mRefCount = 1;
456 if (inVersion >= 1) {
457 graphDef->mNumVariants = readInt16_be(buffer);
458 if (graphDef->mNumVariants) {
459 graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef));
460 for (uint32 i=0; i<graphDef->mNumVariants; ++i) {
461 GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i);
466 return graphDef;
470 void GraphDef_Define(World *inWorld, GraphDef *inList)
472 GraphDef *graphDef = inList;
473 while (graphDef) {
474 GraphDef *next = graphDef->mNext;
476 GraphDef* previousDef = World_GetGraphDef(inWorld, graphDef->mNodeDef.mName);
477 if (previousDef) {
478 World_RemoveGraphDef(inWorld, previousDef);
479 if (--previousDef->mRefCount == 0) {
480 GraphDef_DeleteMsg(inWorld, previousDef);
483 World_AddGraphDef(inWorld, graphDef);
484 graphDef->mNext = 0;
485 graphDef = next;
489 void GraphDef_Remove(World *inWorld, int32 *inName)
491 GraphDef* graphDef = World_GetGraphDef(inWorld, inName);
492 if (graphDef) {
493 World_RemoveGraphDef(inWorld, graphDef);
494 if (--graphDef->mRefCount == 0) {
495 GraphDef_DeleteMsg(inWorld, graphDef);
500 void GraphDef_DeleteMsg(World *inWorld, GraphDef *inDef)
502 DeleteGraphDefMsg msg;
503 msg.mDef = inDef;
504 inWorld->hw->mDeleteGraphDefs.Write(msg);
507 GraphDef* GraphDef_Recv(World *inWorld, char *buffer, GraphDef *inList)
510 try {
511 inList = GraphDefLib_Read(inWorld, buffer, inList);
512 } catch (std::exception& exc) {
513 scprintf("exception in GraphDef_Recv: %s\n", exc.what());
514 } catch (...) {
515 scprintf("unknown exception in GraphDef_Recv\n");
518 return inList;
521 GraphDef* GraphDef_LoadGlob(World *inWorld, const char *pattern, GraphDef *inList)
523 SC_GlobHandle* glob = sc_Glob(pattern);
524 if (!glob) return inList;
526 const char* filename;
527 while ((filename = sc_GlobNext(glob)) != 0) {
528 int len = strlen(filename);
529 if (strncmp(filename+len-9, ".scsyndef", 9)==0) {
530 inList = GraphDef_Load(inWorld, filename, inList);
532 // why? <sk>
533 GraphDef_Load(inWorld, filename, inList);
536 sc_GlobFree(glob);
537 return inList;
540 GraphDef* GraphDef_Load(World *inWorld, const char *filename, GraphDef *inList)
542 FILE *file = fopen(filename, "rb");
544 if (!file) {
545 scprintf("*** ERROR: can't fopen '%s'\n", filename);
546 return inList;
549 fseek(file, 0, SEEK_END);
550 int size = ftell(file);
551 char *buffer = (char*)malloc(size);
552 if (!buffer) {
553 scprintf("*** ERROR: can't malloc buffer size %d\n", size);
554 fclose(file);
555 return inList;
557 fseek(file, 0, SEEK_SET);
559 size_t readSize = fread(buffer, 1, size, file);
560 fclose(file);
562 if (readSize!= size) {
563 scprintf("*** ERROR: invalid fread\n", size);
564 free(buffer);
565 return inList;
568 try {
569 inList = GraphDefLib_Read(inWorld, buffer, inList);
570 } catch (std::exception& exc) {
571 scprintf("exception in GrafDef_Load: %s\n", exc.what());
572 scprintf("while reading file '%s'\n", filename);
573 } catch (...) {
574 scprintf("unknown exception in GrafDef_Load\n");
575 scprintf("while reading file '%s'\n", filename);
578 free(buffer);
580 return inList;
583 GraphDef* GraphDef_LoadDir(World *inWorld, char *dirname, GraphDef *inList)
585 SC_DirHandle *dir = sc_OpenDir(dirname);
586 if (!dir) {
587 scprintf("*** ERROR: open directory failed '%s'\n", dirname);
588 return inList;
591 for (;;) {
592 char diritem[MAXPATHLEN];
593 bool skipItem = false;
594 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
595 if (!validItem) break;
596 if (skipItem) continue;
598 if (sc_DirectoryExists(diritem)) {
599 inList = GraphDef_LoadDir(inWorld, diritem, inList);
600 } else {
601 int dnamelen = strlen(diritem);
602 if (strncmp(diritem+dnamelen-9, ".scsyndef", 9) == 0) {
603 inList = GraphDef_Load(inWorld, diritem, inList);
608 sc_CloseDir(dir);
609 return inList;
612 void UnitSpec_Free(UnitSpec *inUnitSpec);
613 void UnitSpec_Free(UnitSpec *inUnitSpec)
615 free(inUnitSpec->mInputSpec);
616 free(inUnitSpec->mOutputSpec);
619 void GraphDef_Free(GraphDef *inGraphDef)
621 if (inGraphDef != inGraphDef->mOriginal) return;
623 for (uint32 i=0; i<inGraphDef->mNumUnitSpecs; ++i) {
624 UnitSpec_Free(inGraphDef->mUnitSpecs + i);
626 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
627 free(inGraphDef->mVariants[i].mInitialControlValues);
629 delete inGraphDef->mParamSpecTable;
630 free(inGraphDef->mParamSpecs);
631 free(inGraphDef->mInitialControlValues);
632 free(inGraphDef->mConstants);
633 free(inGraphDef->mUnitSpecs);
634 free(inGraphDef->mVariants);
635 free(inGraphDef);
638 void NodeDef_Dump(NodeDef *inNodeDef)
640 scprintf("mName '%s'\n", (char*)inNodeDef->mName);
641 scprintf("mHash %d\n", inNodeDef->mHash);
642 scprintf("mAllocSize %lu\n", inNodeDef->mAllocSize);
645 void GraphDef_Dump(GraphDef *inGraphDef)
647 NodeDef_Dump(&inGraphDef->mNodeDef);
649 scprintf("mNumControls %d\n", inGraphDef->mNumControls);
650 scprintf("mNumWires %d\n", inGraphDef->mNumWires);
651 scprintf("mNumUnitSpecs %d\n", inGraphDef->mNumUnitSpecs);
652 scprintf("mNumWireBufs %d\n", inGraphDef->mNumWireBufs);
654 for (uint32 i=0; i<inGraphDef->mNumControls; ++i) {
655 scprintf(" %d mInitialControlValues %g\n", i, inGraphDef->mInitialControlValues[i]);
658 for (uint32 i=0; i<inGraphDef->mNumWires; ++i) {
659 //WireSpec_Dump(inGraphDef->mWireSpec + i);
661 for (uint32 i=0; i<inGraphDef->mNumUnitSpecs; ++i) {
662 //UnitSpec_Dump(inGraphDef->mUnitSpecs + i);
667 SynthBufferAllocator
669 var nextBufIndex = 0;
670 var stack;
671 var refs;
673 *new {
674 ^super.new.init
676 init {
677 refs = Bag.new;
679 alloc { arg count;
680 var bufNumber;
681 if (stack.size > 0, {
682 bufNumber = stack.pop
684 bufNumber = nextBufIndex;
685 nextBufIndex = nextBufIndex + 1;
687 refs.add(bufNumber, count);
688 ^bufNumber
690 release { arg bufNumber;
691 refs.remove(bufNumber);
692 if (refs.includes(bufNumber).not, { stack = stack.add(bufNumber) });
694 numBufs { ^nextBufIndex }
698 struct BufColorAllocator
700 int16 *refs;
701 int16 *stack;
702 int16 stackPtr;
703 int16 nextIndex;
704 int16 refsMaxSize;
705 int16 stackMaxSize;
707 BufColorAllocator();
708 ~BufColorAllocator();
710 uint32 alloc(uint32 count);
711 bool release(int inIndex);
712 int NumBufs() { return nextIndex; }
715 inline BufColorAllocator::BufColorAllocator()
717 refsMaxSize = 32;
718 stackMaxSize = 32;
719 refs = (int16*)calloc(refsMaxSize, sizeof(int16));
720 stack = (int16*)calloc(stackMaxSize, sizeof(int16));
721 stackPtr = 0;
722 nextIndex = 0;
725 inline BufColorAllocator::~BufColorAllocator()
727 free(refs);
728 free(stack);
731 inline uint32 BufColorAllocator::alloc(uint32 count)
733 uint32 outIndex;
734 if (stackPtr) {
735 outIndex = stack[--stackPtr];
736 } else {
737 outIndex = nextIndex++;
739 if (outIndex >= refsMaxSize) {
740 refs = (int16*)realloc(refs, refsMaxSize*2*sizeof(int16));
741 memset(refs + refsMaxSize, 0, refsMaxSize*sizeof(int16));
742 refsMaxSize *= 2;
744 refs[outIndex] = count;
745 return outIndex;
748 inline bool BufColorAllocator::release(int inIndex)
750 if (refs[inIndex] == 0) return false;
751 if (--refs[inIndex] == 0) {
752 if (stackPtr >= stackMaxSize) {
753 stack = (int16*)realloc(stack, stackMaxSize*2*sizeof(int16));
754 memset(stack + stackMaxSize, 0, stackMaxSize*sizeof(int16));
755 stackMaxSize *= 2;
757 stack[stackPtr++] = inIndex;
759 return true;
762 static void ReleaseInputBuffers(GraphDef *inGraphDef, UnitSpec *unitSpec, BufColorAllocator& bufColor)
764 for (int64 i=(int64)(unitSpec->mNumInputs)-1; i>=0; --i) {
765 InputSpec *inputSpec = unitSpec->mInputSpec + i;
766 if (inputSpec->mFromUnitIndex >= 0) {
767 UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex;
768 OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex;
769 inputSpec->mWireIndex = outputSpec->mWireIndex;
770 if (outputSpec->mCalcRate == calc_FullRate) {
772 if (unitSpec->mCalcRate == calc_DemandRate)
773 // we never release any input buffers of demand-rate ugens
774 continue;
776 if (!bufColor.release(outputSpec->mBufferIndex)) {
777 scprintf("buffer coloring error: tried to release output with zero count\n");
778 scprintf("output: %d %s %d\n", inputSpec->mFromUnitIndex,
779 outUnit->mUnitDef->mUnitDefName, inputSpec->mFromOutputIndex);
780 scprintf("input: %s %d\n", unitSpec->mUnitDef->mUnitDefName, i);
781 throw std::runtime_error("buffer coloring error.");
784 } else {
785 inputSpec->mWireIndex = inputSpec->mFromOutputIndex;
790 static void AllocOutputBuffers(UnitSpec *unitSpec, BufColorAllocator& bufColor, int32& wireIndexCtr)
792 //scprintf("AllocOutputBuffers %s numoutputs %d\n", unitSpec->mUnitDef->mUnitDefName, unitSpec->mNumOutputs);
793 for (uint32 i=0; i<unitSpec->mNumOutputs; ++i) {
794 OutputSpec *outputSpec = unitSpec->mOutputSpec + i;
795 outputSpec->mWireIndex = wireIndexCtr++;
796 if (outputSpec->mCalcRate == calc_FullRate) {
797 uint32 bufIndex = bufColor.alloc(outputSpec->mNumConsumers);
798 outputSpec->mBufferIndex = bufIndex;
803 void DoBufferColoring(World *inWorld, GraphDef *inGraphDef)
805 // count consumers of outputs
806 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
807 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
808 for (uint32 i=0; i<unitSpec->mNumInputs; ++i) {
809 InputSpec *inputSpec = unitSpec->mInputSpec + i;
810 if (inputSpec->mFromUnitIndex >= 0) {
811 UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex;
812 OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex;
813 outputSpec->mNumConsumers ++;
818 // buffer coloring
820 BufColorAllocator bufColor;
821 int32 wireIndexCtr = inGraphDef->mNumConstants; // mNumConstants is a uint32, but limited to int32 in OSC
822 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
823 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
824 if (unitSpec->mUnitDef->mFlags & kUnitDef_CantAliasInputsToOutputs) {
825 // set wire index, alloc outputs
826 AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr);
827 // set wire index, release inputs
828 ReleaseInputBuffers(inGraphDef, unitSpec, bufColor);
829 } else {
830 // set wire index, release inputs
831 ReleaseInputBuffers(inGraphDef, unitSpec, bufColor);
832 // set wire index, alloc outputs
833 AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr);
837 inGraphDef->mNumWireBufs = bufColor.NumBufs();
838 if (inWorld->mRunning)
840 // cannot reallocate interconnect buffers while running audio.
841 if (inGraphDef->mNumWireBufs > inWorld->hw->mMaxWireBufs) {
842 throw std::runtime_error("exceeded number of interconnect buffers.");
844 } else {
845 inWorld->hw->mMaxWireBufs = sc_max(inWorld->hw->mMaxWireBufs, inGraphDef->mNumWireBufs);
849 // multiply buf indices by buf length for proper offset
850 int bufLength = inWorld->mBufLength;
851 for (uint32 j=0; j<inGraphDef->mNumUnitSpecs; ++j) {
852 UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j;
853 for (uint32 i=0; i<unitSpec->mNumOutputs; ++i) {
854 OutputSpec *outputSpec = unitSpec->mOutputSpec + i;
855 if (outputSpec->mCalcRate == calc_FullRate) {
856 outputSpec->mBufferIndex *= bufLength;