Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / scsynth / SC_World.cpp
blob7092ccda87df5de0c6d3f999bcdffe45e55ae21b
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_World.h"
23 #include "SC_WorldOptions.h"
24 #include "SC_HiddenWorld.h"
25 #include "SC_InterfaceTable.h"
26 #include "SC_AllocPool.h"
27 #include "SC_GraphDef.h"
28 #include "SC_UnitDef.h"
29 #include "SC_BufGen.h"
30 #include "SC_Node.h"
31 #include "SC_CoreAudio.h"
32 #include "SC_Group.h"
33 #include "SC_Errors.h"
34 #include <stdio.h>
35 #include "SC_Prototypes.h"
36 #include "SC_Samp.h"
37 #include "SC_DirUtils.h"
38 #include "../../common/SC_SndFileHelpers.hpp"
39 #include "SC_StringParser.h"
40 #ifdef _WIN32
41 # include <direct.h>
42 #else
43 # include <sys/param.h>
44 #endif
46 #include "../supernova/utilities/malloc_aligned.hpp"
48 // undefine the shadowed scfft functions
49 #undef scfft_create
50 #undef scfft_dofft
51 #undef scfft_doifft
52 #undef scfft_destroy
54 #if (_POSIX_MEMLOCK - 0) >= 200112L
55 # include <sys/resource.h>
56 # include <sys/mman.h>
57 #endif
59 #include "server_shm.hpp"
62 InterfaceTable gInterfaceTable;
63 PrintFunc gPrint = 0;
65 extern HashTable<struct UnitDef, Malloc> *gUnitDefLib;
66 extern HashTable<struct BufGen, Malloc> *gBufGenLib;
67 extern HashTable<PlugInCmd, Malloc> *gPlugInCmds;
69 extern "C" {
71 #ifdef NO_LIBSNDFILE
72 struct SF_INFO {};
73 #endif
75 bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg);
76 bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg);
79 bool sc_UseVectorUnit();
80 void sc_SetDenormalFlags();
82 ////////////////////////////////////////////////////////////////////////////////
84 inline void* sc_malloc(size_t size)
86 return nova::malloc_aligned(size);
89 void* sc_dbg_malloc(size_t size, const char* tag, int line)
91 void* ptr = sc_malloc(size);
92 fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu\n", tag, line, ptr, size);
93 #if SC_MEMORY_ALIGNMENT > 1
94 if (((intptr_t)ptr % SC_MEMORY_ALIGNMENT) != 0) {
95 fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu: memory alignment error\n",
96 tag, line, ptr, size);
97 abort();
99 #endif
100 return ptr;
103 inline void sc_free(void* ptr)
105 return nova::free_aligned(ptr);
108 void sc_dbg_free(void* ptr, const char* tag, int line)
110 fprintf(stderr, "sc_dbg_free [%s:%d]: %p\n", tag, line, ptr);
111 sc_free(ptr);
114 inline void* sc_zalloc(size_t n, size_t size)
116 size *= n;
117 if (size) {
118 void* ptr = sc_malloc(size);
119 if (ptr) {
120 memset(ptr, 0, size);
121 return ptr;
124 return 0;
127 void* sc_dbg_zalloc(size_t n, size_t size, const char* tag, int line)
129 void* ptr = sc_zalloc(n, size);
130 fprintf(stderr, "sc_dbg_zalloc [%s:%d]: %p %zu %zu\n", tag, line, ptr, n, size);
131 return ptr;
134 # if SC_DEBUG_MEMORY
135 # define malloc(size) sc_dbg_malloc((size), __FUNCTION__, __LINE__)
136 # define free(ptr) sc_dbg_free((ptr), __FUNCTION__, __LINE__)
137 # define zalloc_(n, size) sc_dbg_zalloc((n), (size), __FUNCTION__, __LINE__)
138 # else
139 # define malloc(size) sc_malloc((size))
140 # define free(ptr) sc_free((ptr))
141 # define zalloc_(n, size) sc_zalloc((n), (size))
142 # endif // SC_DEBUG_MEMORY
144 void* zalloc(size_t n, size_t size)
146 return zalloc_(n, size);
150 ////////////////////////////////////////////////////////////////////////////////
152 static bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd);
153 static void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames);
154 static void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd);
156 void InterfaceTable_Init()
158 InterfaceTable *ft = &gInterfaceTable;
160 ft->mSine = gSine;
161 ft->mCosecant = gInvSine;
162 ft->mSineSize = kSineSize;
163 ft->mSineWavetable = gSineWavetable;
165 ft->fPrint = &scprintf;
167 ft->fRanSeed = &server_timeseed;
169 ft->fNodeEnd = &Node_End;
171 ft->fDefineUnit = &UnitDef_Create;
172 ft->fDefineBufGen = &BufGen_Create;
173 ft->fClearUnitOutputs = &Unit_ZeroOutputs;
175 ft->fNRTAlloc = &malloc;
176 ft->fNRTRealloc = &realloc;
177 ft->fNRTFree = &free;
179 ft->fRTAlloc = &World_Alloc;
180 ft->fRTRealloc = &World_Realloc;
181 ft->fRTFree = &World_Free;
183 ft->fNodeRun = &Node_SetRun;
185 ft->fSendTrigger = &Node_SendTrigger;
186 ft->fSendNodeReply = &Node_SendReply;
189 ft->fDefineUnitCmd = &UnitDef_AddCmd;
190 ft->fDefinePlugInCmd = &PlugIn_DefineCmd;
192 ft->fSendMsgFromRT = &SendMsgFromEngine;
193 ft->fSendMsgToRT = &SendMsgToEngine;
194 #ifdef NO_LIBSNDFILE
195 ft->fSndFileFormatInfoFromStrings = NULL;
196 #else
197 ft->fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
198 #endif
199 ft->fGetNode = &World_GetNode;
200 ft->fGetGraph = &World_GetGraph;
202 ft->fNRTLock = &World_NRTLock;
203 ft->fNRTUnlock = &World_NRTUnlock;
205 ft->mAltivecAvailable = sc_UseVectorUnit();
207 ft->fGroup_DeleteAll = &Group_DeleteAll;
208 ft->fDoneAction = &Unit_DoneAction;
209 ft->fDoAsynchronousCommand = &PerformAsynchronousCommand;
210 ft->fBufAlloc = &bufAlloc;
212 ft->fSCfftCreate = &scfft_create;
213 ft->fSCfftDestroy = &scfft_destroy;
214 ft->fSCfftDoFFT = &scfft_dofft;
215 ft->fSCfftDoIFFT = &scfft_doifft;
217 ft->fGetScopeBuffer = &getScopeBuffer;
218 ft->fPushScopeBuffer = &pushScopeBuffer;
219 ft->fReleaseScopeBuffer = &releaseScopeBuffer;
222 void initialize_library(const char *mUGensPluginPath);
223 void initializeScheduler();
225 static void World_LoadGraphDefs(World* world);
226 void World_LoadGraphDefs(World* world)
228 GraphDef *list = 0;
230 if(getenv("SC_SYNTHDEF_PATH")){
231 if(world->mVerbosity > 0)
232 scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH"));
233 SC_StringParser sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER);
234 while (!sp.AtEnd()) {
235 GraphDef *list = 0;
236 char *path = const_cast<char *>(sp.NextToken());
237 list = GraphDef_LoadDir(world, path, list);
238 GraphDef_Define(world, list);
240 }else{
241 char resourceDir[MAXPATHLEN];
242 if(sc_IsStandAlone())
243 sc_GetResourceDirectory(resourceDir, MAXPATHLEN);
244 else
245 sc_GetUserAppSupportDirectory(resourceDir, MAXPATHLEN);
246 sc_AppendToPath(resourceDir, MAXPATHLEN, "synthdefs");
247 if(world->mVerbosity > 0)
248 scprintf("Loading synthdefs from default path: %s\n", resourceDir);
249 list = GraphDef_LoadDir(world, resourceDir, list);
250 GraphDef_Define(world, list);
255 SC_DLLEXPORT_C World* World_New(WorldOptions *inOptions)
257 #if (_POSIX_MEMLOCK - 0) >= 200112L
258 if (inOptions->mMemoryLocking && inOptions->mRealTime)
260 bool lock_memory = false;
262 rlimit limit;
264 int failure = getrlimit(RLIMIT_MEMLOCK, &limit);
265 if (failure)
266 scprintf("getrlimit failure\n");
267 else
269 if (limit.rlim_cur == RLIM_INFINITY and
270 limit.rlim_max == RLIM_INFINITY)
271 lock_memory = true;
272 else
273 scprintf("memory locking disabled due to resource limiting\n");
275 if (lock_memory)
277 if (mlockall(MCL_FUTURE) != -1)
278 scprintf("memory locking enabled.\n");
282 #endif
284 World *world = 0;
286 try {
287 static bool gLibInitted = false;
288 if (!gLibInitted) {
289 InterfaceTable_Init();
290 initialize_library(inOptions->mUGensPluginPath);
291 initializeScheduler();
292 gLibInitted = true;
295 world = (World*)zalloc(1, sizeof(World));
297 world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld));
299 world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0);
300 world->hw->mQuitProgram = new SC_Semaphore(0);
301 world->hw->mTerminating = false;
303 extern Malloc gMalloc;
305 HiddenWorld *hw = world->hw;
306 hw->mGraphDefLib = new HashTable<struct GraphDef, Malloc>(&gMalloc, inOptions->mMaxGraphDefs, false);
307 hw->mNodeLib = new IntHashTable<Node, AllocPool>(hw->mAllocPool, inOptions->mMaxNodes, false);
308 hw->mUsers = (ReplyAddress*)zalloc(inOptions->mMaxLogins, sizeof(ReplyAddress));
309 hw->mNumUsers = 0;
310 hw->mMaxUsers = inOptions->mMaxLogins;
311 hw->mHiddenID = -8;
312 hw->mRecentID = -8;
315 world->mNumUnits = 0;
316 world->mNumGraphs = 0;
317 world->mNumGroups = 0;
319 world->mBufCounter = 0;
320 world->mBufLength = inOptions->mBufLength;
321 world->mSampleOffset = 0;
322 world->mSubsampleOffset = 0.f;
323 world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels;
324 world->mNumControlBusChannels = inOptions->mNumControlBusChannels;
325 world->mNumInputs = inOptions->mNumInputBusChannels;
326 world->mNumOutputs = inOptions->mNumOutputBusChannels;
328 world->mVerbosity = inOptions->mVerbosity;
329 world->mErrorNotification = 1; // i.e., 0x01 | 0x02
330 world->mLocalErrorNotification = 0;
332 if (inOptions->mSharedMemoryID) {
333 server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID);
334 hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels);
335 world->mControlBus = hw->mShmem->get_control_busses();
336 } else {
337 hw->mShmem = 0;
338 world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float));
341 world->mNumSharedControls = 0;
342 world->mSharedControls = inOptions->mSharedControls;
344 int numsamples = world->mBufLength * world->mNumAudioBusChannels;
345 world->mAudioBus = (float*)zalloc(numsamples, sizeof(float));
347 world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32));
348 world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32));
350 world->mNumSndBufs = inOptions->mNumBuffers;
351 world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
352 world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
353 world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates));
355 GroupNodeDef_Init();
357 int err = Group_New(world, 0, &world->mTopGroup);
358 if (err) throw err;
360 world->mRealTime = inOptions->mRealTime;
362 world->ft = &gInterfaceTable;
364 world->mNumRGens = inOptions->mNumRGens;
365 world->mRGen = new RGen[world->mNumRGens];
366 for (uint32 i=0; i<world->mNumRGens; ++i) {
367 world->mRGen[i].init(server_timeseed());
370 world->mNRTLock = new SC_Lock();
371 world->mDriverLock = new SC_Lock();
373 if (inOptions->mPassword) {
374 strncpy(world->hw->mPassword, inOptions->mPassword, 31);
375 world->hw->mPassword[31] = 0;
376 } else {
377 world->hw->mPassword[0] = 0;
380 #ifdef __APPLE__
381 world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled;
382 world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled;
383 #endif
384 world->hw->mInDeviceName = inOptions->mInDeviceName;
385 world->hw->mOutDeviceName = inOptions->mOutDeviceName;
386 hw->mMaxWireBufs = inOptions->mMaxWireBufs;
387 hw->mWireBufSpace = 0;
389 world->mRendezvous = inOptions->mRendezvous;
391 world->mRestrictedPath = inOptions->mRestrictedPath;
393 if(inOptions->mVerbosity >= 1) {
394 scprintf("Using vector unit: %s\n", sc_UseVectorUnit() ? "yes" : "no");
396 sc_SetDenormalFlags();
398 if (world->mRealTime) {
399 hw->mAudioDriver = SC_NewAudioDriver(world);
400 hw->mAudioDriver->SetPreferredHardwareBufferFrameSize(
401 inOptions->mPreferredHardwareBufferFrameSize
403 hw->mAudioDriver->SetPreferredSampleRate(
404 inOptions->mPreferredSampleRate
407 if (inOptions->mLoadGraphDefs) {
408 World_LoadGraphDefs(world);
411 if (!hw->mAudioDriver->Setup()) {
412 scprintf("could not initialize audio.\n");
413 return 0;
415 if (!hw->mAudioDriver->Start()) {
416 scprintf("start audio failed.\n");
417 return 0;
419 } else {
420 hw->mAudioDriver = 0;
422 } catch (std::exception& exc) {
423 scprintf("Exception in World_New: %s\n", exc.what());
424 World_Cleanup(world);
425 return 0;
426 } catch (...) {
428 return world;
431 SC_DLLEXPORT_C int World_CopySndBuf(World *world, uint32 index, SndBuf *outBuf, bool onlyIfChanged, bool *outDidChange)
433 if (index > world->mNumSndBufs) return kSCErr_IndexOutOfRange;
435 SndBufUpdates *updates = world->mSndBufUpdates + index;
436 bool didChange = updates->reads != updates->writes;
438 if (!onlyIfChanged || didChange)
441 world->mNRTLock->Lock();
443 SndBuf *buf = world->mSndBufsNonRealTimeMirror + index;
445 if (buf->data && buf->samples)
447 uint32 bufSize = buf->samples * sizeof(float);
448 if (buf->samples != outBuf->samples)
450 free(outBuf->data);
451 outBuf->data = (float*)malloc(bufSize);
453 memcpy(outBuf->data, buf->data, bufSize);
454 outBuf->channels = buf->channels;
455 outBuf->samples = buf->samples;
456 outBuf->frames = buf->frames;
457 outBuf->mask = buf->mask;
458 outBuf->mask1 = buf->mask1;
460 else
462 free(outBuf->data);
463 outBuf->data = 0;
464 outBuf->channels = 0;
465 outBuf->samples = 0;
466 outBuf->frames = 0;
467 outBuf->mask = 0;
468 outBuf->mask1 = 0;
471 outBuf->samplerate = buf->samplerate;
472 outBuf->sampledur = buf->sampledur;
473 outBuf->coord = buf->coord;
474 outBuf->sndfile = 0;
476 updates->reads = updates->writes;
478 world->mNRTLock->Unlock();
481 if (outDidChange) *outDidChange = didChange;
483 return kSCErr_None;
486 bool nextOSCPacket(FILE *file, OSC_Packet *packet, int64& outTime)
488 int32 msglen;
489 if (fread(&msglen, 1, sizeof(int32), file) != sizeof(int32))
490 return true;
491 // msglen is in network byte order
492 msglen = OSCint((char*)&msglen);
493 if (msglen > 8192)
494 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
496 size_t read = fread(packet->mData, 1, msglen, file);
497 if (read != msglen)
498 throw std::runtime_error("nextOSCPacket: invalid read of OSC packaet\n");
500 if (strcmp(packet->mData, "#bundle")!=0)
501 throw std::runtime_error("OSC packet not a bundle\n");
503 packet->mSize = msglen;
505 outTime = OSCtime(packet->mData+8);
506 return false;
509 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
511 #ifndef NO_LIBSNDFILE
512 SC_DLLEXPORT_C void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions)
514 if (inOptions->mLoadGraphDefs) {
515 World_LoadGraphDefs(world);
517 int bufLength = world->mBufLength;
518 int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize;
519 if (fileBufFrames <= 0) fileBufFrames = 8192;
520 int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength;
521 fileBufFrames = bufMultiple * bufLength;
523 // batch process non real time audio
524 if (!inOptions->mNonRealTimeOutputFilename)
525 throw std::runtime_error("Non real time output filename is NULL.\n");
527 SF_INFO inputFileInfo, outputFileInfo;
528 float *inputFileBuf = 0;
529 float *outputFileBuf = 0;
530 int numInputChannels = 0;
531 int numOutputChannels;
533 outputFileInfo.samplerate = inOptions->mPreferredSampleRate;
534 numOutputChannels = outputFileInfo.channels = world->mNumOutputs;
535 sndfileFormatInfoFromStrings(&outputFileInfo,
536 inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat);
538 world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo);
539 if (!world->hw->mNRTOutputFile)
540 throw std::runtime_error("Couldn't open non real time output file.\n");
542 outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float));
544 if (inOptions->mNonRealTimeInputFilename) {
545 world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo);
546 if (!world->hw->mNRTInputFile)
547 throw std::runtime_error("Couldn't open non real time input file.\n");
549 inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float));
551 if (world->mNumInputs != (uint32)inputFileInfo.channels)
552 scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");
554 numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it.
556 if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate)
557 scprintf("WARNING: input file sample rate does not equal output sample rate.\n");
559 } else {
560 world->hw->mNRTInputFile = 0;
563 FILE *cmdFile;
564 if (inOptions->mNonRealTimeCmdFilename) {
565 #ifdef _WIN32
566 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb");
567 #else
568 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r");
569 #endif
570 } else cmdFile = stdin;
571 if (!cmdFile)
572 throw std::runtime_error("Couldn't open non real time command file.\n");
574 char msgbuf[8192];
575 OSC_Packet packet;
576 memset(&packet, 0, sizeof(packet));
577 packet.mData = msgbuf;
578 packet.mIsBundle = true;
579 packet.mReplyAddr.mReplyFunc = null_reply_func;
581 int64 schedTime;
582 if (nextOSCPacket(cmdFile, &packet, schedTime))
583 throw std::runtime_error("command file empty.\n");
584 int64 prevTime = schedTime;
586 World_SetSampleRate(world, inOptions->mPreferredSampleRate);
587 World_Start(world);
589 int64 oscTime = 0;
590 double oscToSeconds = 1. / pow(2.,32.);
591 double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds;
592 int64 oscInc = (int64)((double)bufLength / oscToSamples);
594 if(inOptions->mVerbosity >= 0) {
595 printf("start time %g\n", schedTime * oscToSeconds);
598 bool run = true;
599 int inBufStep = numInputChannels * bufLength;
600 int outBufStep = numOutputChannels * bufLength;
601 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufLength;
602 float* outputBuses = world->mAudioBus;
603 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
604 int32* outputTouched = world->mAudioBusTouched;
605 for (; run;) {
606 int bufFramesCalculated = 0;
607 float* inBufPos = inputFileBuf;
608 float* outBufPos = outputFileBuf;
610 if (world->hw->mNRTInputFile) {
611 int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames);
612 if (framesRead < fileBufFrames) {
613 memset(inputFileBuf + framesRead * numInputChannels, 0,
614 (fileBufFrames - framesRead) * numInputChannels * sizeof(float));
618 for (int i=0; i<bufMultiple && run; ++i) {
619 int bufCounter = world->mBufCounter;
621 // deinterleave input to input buses
622 if (inputFileBuf) {
623 float *inBus = inputBuses;
624 for (int j=0; j<numInputChannels; ++j, inBus += bufLength) {
625 float *inFileBufPtr = inBufPos + j;
626 for (int k=0; k<bufLength; ++k) {
627 inBus[k] = *inFileBufPtr;
628 inFileBufPtr += numInputChannels;
630 inputTouched[j] = bufCounter;
634 // execute ready commands
635 int64 nextTime = oscTime + oscInc;
637 while (schedTime <= nextTime) {
638 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
639 float diffTimeFloor = floor(diffTime);
640 world->mSampleOffset = (int)diffTimeFloor;
641 world->mSubsampleOffset = diffTime - diffTimeFloor;
643 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
644 else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1;
647 PerformOSCBundle(world, &packet);
648 if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; }
649 if(inOptions->mVerbosity >= 0) {
650 printf("nextOSCPacket %g\n", schedTime * oscToSeconds);
652 if (schedTime < prevTime) {
653 scprintf("ERROR: Packet time stamps out-of-order.\n");
654 run = false;
655 goto Bail;
657 prevTime = schedTime;
660 World_Run(world);
662 // interleave output to output buffer
663 float *outBus = outputBuses;
664 for (int j=0; j<numOutputChannels; ++j, outBus += bufLength) {
665 float *outFileBufPtr = outBufPos + j;
666 if (outputTouched[j] == bufCounter) {
667 for (int k=0; k<bufLength; ++k) {
668 *outFileBufPtr = outBus[k];
669 outFileBufPtr += numOutputChannels;
671 } else {
672 for (int k=0; k<bufLength; ++k) {
673 *outFileBufPtr = 0.f;
674 outFileBufPtr += numOutputChannels;
678 bufFramesCalculated += bufLength;
679 inBufPos += inBufStep;
680 outBufPos += outBufStep;
681 world->mBufCounter++;
682 oscTime = nextTime;
685 Bail:
686 // write output
687 sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated);
690 if (cmdFile != stdin) fclose(cmdFile);
691 sf_close(world->hw->mNRTOutputFile);
692 world->hw->mNRTOutputFile = 0;
694 if (world->hw->mNRTInputFile) {
695 sf_close(world->hw->mNRTInputFile);
696 world->hw->mNRTInputFile = 0;
699 World_Cleanup(world);
701 #endif // !NO_LIBSNDFILE
703 SC_DLLEXPORT_C void World_WaitForQuit(struct World *inWorld)
705 try {
706 inWorld->hw->mQuitProgram->Acquire();
707 World_Cleanup(inWorld);
708 } catch (std::exception& exc) {
709 scprintf("Exception in World_WaitForQuit: %s\n", exc.what());
710 } catch (...) {
714 void World_SetSampleRate(World *inWorld, double inSampleRate)
716 inWorld->mSampleRate = inSampleRate;
717 Rate_Init(&inWorld->mFullRate, inSampleRate, inWorld->mBufLength);
718 Rate_Init(&inWorld->mBufRate, inSampleRate / inWorld->mBufLength, 1);
721 ////////////////////////////////////////////////////////////////////////////////
723 void* World_Alloc(World *inWorld, size_t inByteSize)
725 return inWorld->hw->mAllocPool->Alloc(inByteSize);
728 void* World_Realloc(World *inWorld, void *inPtr, size_t inByteSize)
730 return inWorld->hw->mAllocPool->Realloc(inPtr, inByteSize);
733 size_t World_TotalFree(World *inWorld)
735 return inWorld->hw->mAllocPool->TotalFree();
738 size_t World_LargestFreeChunk(World *inWorld)
740 return inWorld->hw->mAllocPool->LargestFreeChunk();
743 void World_Free(World *inWorld, void *inPtr)
745 inWorld->hw->mAllocPool->Free(inPtr);
748 ////////////////////////////////////////////////////////////////////////////////
750 int32 *GetKey(GraphDef *inGraphDef)
752 return inGraphDef->mNodeDef.mName;
755 int32 GetHash(GraphDef *inGraphDef)
757 return inGraphDef->mNodeDef.mHash;
760 void World_AddGraphDef(World *inWorld, GraphDef* inGraphDef)
762 bool added = inWorld->hw->mGraphDefLib->Add(inGraphDef);
763 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef->mNodeDef.mName);
764 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
765 GraphDef* var = inGraphDef->mVariants + i;
766 added = inWorld->hw->mGraphDefLib->Add(var);
767 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var->mNodeDef.mName);
771 void World_RemoveGraphDef(World *inWorld, GraphDef* inGraphDef)
773 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
774 GraphDef* var = inGraphDef->mVariants + i;
775 inWorld->hw->mGraphDefLib->Remove(var);
777 inWorld->hw->mGraphDefLib->Remove(inGraphDef);
780 void World_FreeAllGraphDefs(World *inWorld)
782 GrafDefTable* lib = inWorld->hw->mGraphDefLib;
783 int size = lib->TableSize();
784 for (int i=0; i<size; ++i) {
785 GraphDef *def = lib->AtIndex(i);
786 if (def) GraphDef_Free(def);
788 lib->MakeEmpty();
791 GraphDef* World_GetGraphDef(World *inWorld, int32* inKey)
793 return inWorld->hw->mGraphDefLib->Get(inKey);
796 ////////////////////////////////////////////////////////////////////////////////
798 int32 *GetKey(UnitDef *inUnitDef)
800 return inUnitDef->mUnitDefName;
803 int32 GetHash(UnitDef *inUnitDef)
805 return inUnitDef->mHash;
808 bool AddUnitDef(UnitDef* inUnitDef)
810 return gUnitDefLib->Add(inUnitDef);
813 bool RemoveUnitDef(UnitDef* inUnitDef)
815 return gUnitDefLib->Remove(inUnitDef);
818 UnitDef* GetUnitDef(int32* inKey)
820 return gUnitDefLib->Get(inKey);
823 ////////////////////////////////////////////////////////////////////////////////
825 int32 *GetKey(BufGen *inBufGen)
827 return inBufGen->mBufGenName;
830 int32 GetHash(BufGen *inBufGen)
832 return inBufGen->mHash;
835 bool AddBufGen(BufGen* inBufGen)
837 return gBufGenLib->Add(inBufGen);
840 bool RemoveBufGen(BufGen* inBufGen)
842 return gBufGenLib->Remove(inBufGen);
845 BufGen* GetBufGen(int32* inKey)
847 return gBufGenLib->Get(inKey);
850 ////////////////////////////////////////////////////////////////////////////////
852 int32 *GetKey(PlugInCmd *inPlugInCmd)
854 return inPlugInCmd->mCmdName;
857 int32 GetHash(PlugInCmd *inPlugInCmd)
859 return inPlugInCmd->mHash;
862 bool AddPlugInCmd(PlugInCmd* inPlugInCmd)
864 return gPlugInCmds->Add(inPlugInCmd);
867 bool RemovePlugInCmd(PlugInCmd* inPlugInCmd)
869 return gPlugInCmds->Remove(inPlugInCmd);
872 PlugInCmd* GetPlugInCmd(int32* inKey)
874 return gPlugInCmds->Get(inKey);
877 ////////////////////////////////////////////////////////////////////////////////
879 int32 GetKey(Node *inNode)
881 return inNode->mID;
884 int32 GetHash(Node *inNode)
886 return inNode->mHash;
889 bool World_AddNode(World *inWorld, Node* inNode)
891 return inWorld->hw->mNodeLib->Add(inNode);
894 bool World_RemoveNode(World *inWorld, Node* inNode)
896 return inWorld->hw->mNodeLib->Remove(inNode);
899 Node* World_GetNode(World *inWorld, int32 inID)
901 if (inID == -1) inID = inWorld->hw->mRecentID;
902 return inWorld->hw->mNodeLib->Get(inID);
905 Graph* World_GetGraph(World *inWorld, int32 inID)
907 if (inID == -1) inID = inWorld->hw->mRecentID;
908 Node *node = World_GetNode(inWorld, inID);
909 if (!node) return 0;
910 return node->mIsGroup ? 0 : (Graph*)node;
913 Group* World_GetGroup(World *inWorld, int32 inID)
915 Node *node = World_GetNode(inWorld, inID);
916 if (!node) return 0;
917 return node->mIsGroup ? (Group*)node : 0;
920 ////////////////////////////////////////////////////////////////////////////////
922 void World_Run(World *inWorld)
924 // run top group
925 Node *node = (Node*)inWorld->mTopGroup;
926 (*node->mCalcFunc)(node);
929 void World_Start(World *inWorld)
931 inWorld->mBufCounter = 0;
932 for (uint32 i=0; i<inWorld->mNumAudioBusChannels; ++i) inWorld->mAudioBusTouched[i] = -1;
933 for (uint32 i=0; i<inWorld->mNumControlBusChannels; ++i) inWorld->mControlBusTouched[i] = -1;
935 inWorld->hw->mWireBufSpace = (float*)malloc(inWorld->hw->mMaxWireBufs * inWorld->mBufLength * sizeof(float));
937 inWorld->hw->mTriggers.MakeEmpty();
938 inWorld->hw->mNodeMsgs.MakeEmpty();
939 inWorld->hw->mNodeEnds.MakeEmpty();
940 inWorld->mRunning = true;
943 SC_DLLEXPORT_C void World_Cleanup(World *world)
945 if (!world) return;
947 HiddenWorld *hw = world->hw;
949 if (hw && world->mRealTime) hw->mAudioDriver->Stop();
951 world->mRunning = false;
953 if (world->mTopGroup) Group_DeleteAll(world->mTopGroup);
955 world->mDriverLock->Lock(); // never unlock..
956 if (hw) {
957 free(hw->mWireBufSpace);
958 delete hw->mAudioDriver;
959 hw->mAudioDriver = 0;
961 delete world->mNRTLock;
962 delete world->mDriverLock;
963 World_Free(world, world->mTopGroup);
965 for (uint32 i=0; i<world->mNumSndBufs; ++i) {
966 SndBuf *nrtbuf = world->mSndBufsNonRealTimeMirror + i;
967 SndBuf * rtbuf = world->mSndBufs + i;
969 if (nrtbuf->data) free(nrtbuf->data);
970 if (rtbuf->data && rtbuf->data != nrtbuf->data) free(rtbuf->data);
972 #ifndef NO_LIBSNDFILE
973 if (nrtbuf->sndfile) sf_close(nrtbuf->sndfile);
974 if (rtbuf->sndfile && rtbuf->sndfile != nrtbuf->sndfile) sf_close(rtbuf->sndfile);
975 #endif
978 free(world->mSndBufsNonRealTimeMirror);
979 free(world->mSndBufs);
981 free(world->mControlBusTouched);
982 free(world->mAudioBusTouched);
983 if (hw->mShmem) {
984 delete hw->mShmem;
985 } else
986 free(world->mControlBus);
987 free(world->mAudioBus);
988 delete [] world->mRGen;
989 if (hw) {
991 #ifndef NO_LIBSNDFILE
992 if (hw->mNRTInputFile) sf_close(hw->mNRTInputFile);
993 if (hw->mNRTOutputFile) sf_close(hw->mNRTOutputFile);
994 if (hw->mNRTCmdFile) fclose(hw->mNRTCmdFile);
995 #endif
996 free(hw->mUsers);
997 delete hw->mNodeLib;
998 delete hw->mGraphDefLib;
999 delete hw->mQuitProgram;
1000 delete hw->mAllocPool;
1001 free(hw);
1003 free(world);
1007 void World_NRTLock(World *world)
1009 world->mNRTLock->Lock();
1012 void World_NRTUnlock(World *world)
1014 world->mNRTLock->Unlock();
1017 ////////////////////////////////////////////////////////////////////////////////
1019 bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd)
1021 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1023 scope_buffer_writer writer = shm->get_scope_buffer_writer( index, channels, maxFrames );
1025 if( writer.valid() ) {
1026 hnd.internalData = writer.buffer;
1027 hnd.data = writer.data();
1028 hnd.channels = channels;
1029 hnd.maxFrames = maxFrames;
1030 return true;
1032 else {
1033 hnd.internalData = 0;
1034 return false;
1038 void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames)
1040 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1041 writer.push(frames);
1042 hnd.data = writer.data();
1045 void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd)
1047 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1048 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1049 shm->release_scope_buffer_writer( writer );
1052 ////////////////////////////////////////////////////////////////////////////////
1055 inline int32 BUFMASK(int32 x)
1057 return (1 << (31 - CLZ(x))) - 1;
1060 SCErr bufAlloc(SndBuf* buf, int numChannels, int numFrames, double sampleRate)
1062 long numSamples = numFrames * numChannels;
1063 if(numSamples < 1) return kSCErr_Failed;
1064 buf->data = (float*)zalloc(numSamples, sizeof(float));
1065 if (!buf->data) return kSCErr_Failed;
1067 buf->channels = numChannels;
1068 buf->frames = numFrames;
1069 buf->samples = numSamples;
1070 buf->mask = BUFMASK(numSamples); // for delay lines
1071 buf->mask1 = buf->mask - 1; // for oscillators
1072 buf->samplerate = sampleRate;
1073 buf->sampledur = 1. / sampleRate;
1075 return kSCErr_None;
1078 #include "scsynthsend.h"
1080 void TriggerMsg::Perform()
1082 small_scpacket packet;
1083 packet.adds("/tr");
1084 packet.maketags(4);
1085 packet.addtag(',');
1086 packet.addtag('i');
1087 packet.addtag('i');
1088 packet.addtag('f');
1089 packet.addi(mNodeID);
1090 packet.addi(mTriggerID);
1091 packet.addf(mValue);
1093 ReplyAddress *users = mWorld->hw->mUsers;
1094 int numUsers = mWorld->hw->mNumUsers;
1095 for (int i=0; i<numUsers; ++i) {
1096 SendReply(users+i, packet.data(), packet.size());
1100 static void NodeReplyMsg_RTFree(FifoMsg* msg)
1102 //scprintf("NodeReplyMsg_RTFree()\n");
1103 World_Free(msg->mWorld, msg->mData);
1106 void NodeReplyMsg::Perform()
1108 small_scpacket packet;
1109 packet.adds(mCmdName, mCmdNameSize);
1110 packet.maketags(3 + mNumArgs);
1111 packet.addtag(',');
1112 packet.addtag('i');
1113 packet.addi(mNodeID);
1114 packet.addtag('i');
1115 packet.addi(mID);
1116 for(int i=0; i<mNumArgs; ++i) {
1117 packet.addtag('f');
1118 packet.addf(mValues[i]);
1121 ReplyAddress *users = mWorld->hw->mUsers;
1122 int numUsers = mWorld->hw->mNumUsers;
1123 for (int i=0; i<numUsers; ++i) {
1124 SendReply(users+i, packet.data(), packet.size());
1127 // Free memory in realtime thread
1128 FifoMsg msg;
1129 msg.Set(mWorld, NodeReplyMsg_RTFree, 0, mRTMemory);
1130 AudioDriver(mWorld)->SendMsgToEngine(msg);
1134 void NodeEndMsg::Perform()
1136 small_scpacket packet;
1137 switch (mState) {
1138 case kNode_Go :
1139 packet.adds("/n_go");
1140 break;
1141 case kNode_End :
1142 packet.adds("/n_end");
1143 break;
1144 case kNode_On :
1145 packet.adds("/n_on");
1146 break;
1147 case kNode_Off :
1148 packet.adds("/n_off");
1149 break;
1150 case kNode_Move :
1151 packet.adds("/n_move");
1152 break;
1153 case kNode_Info :
1154 packet.adds("/n_info");
1155 break;
1157 if (mIsGroup) {
1158 packet.maketags(8);
1159 packet.addtag(',');
1160 packet.addtag('i');
1161 packet.addtag('i');
1162 packet.addtag('i');
1163 packet.addtag('i');
1164 packet.addtag('i');
1165 packet.addtag('i');
1166 packet.addtag('i');
1167 packet.addi(mNodeID);
1168 packet.addi(mGroupID);
1169 packet.addi(mPrevNodeID);
1170 packet.addi(mNextNodeID);
1171 packet.addi(mIsGroup);
1172 packet.addi(mHeadID);
1173 packet.addi(mTailID);
1174 } else {
1175 packet.maketags(6);
1176 packet.addtag(',');
1177 packet.addtag('i');
1178 packet.addtag('i');
1179 packet.addtag('i');
1180 packet.addtag('i');
1181 packet.addtag('i');
1182 packet.addi(mNodeID);
1183 packet.addi(mGroupID);
1184 packet.addi(mPrevNodeID);
1185 packet.addi(mNextNodeID);
1186 packet.addi(mIsGroup);
1189 ReplyAddress *users = mWorld->hw->mUsers;
1190 int numUsers = mWorld->hw->mNumUsers;
1191 for (int i=0; i<numUsers; ++i) {
1192 SendReply(users+i, packet.data(), packet.size());
1196 void DeleteGraphDefMsg::Perform()
1198 GraphDef_Free(mDef);
1201 void NotifyNoArgs(World *inWorld, char *inString);
1202 void NotifyNoArgs(World *inWorld, char *inString)
1204 small_scpacket packet;
1205 packet.adds(inString);
1207 ReplyAddress *users = inWorld->hw->mUsers;
1208 int numUsers = inWorld->hw->mNumUsers;
1209 for (int i=0; i<numUsers; ++i) {
1210 SendReply(users+i, packet.data(), packet.size());
1215 bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg)
1217 return inWorld->hw->mAudioDriver->SendMsgToEngine(inMsg);
1220 bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg)
1222 return inWorld->hw->mAudioDriver->SendMsgFromEngine(inMsg);
1225 SC_DLLEXPORT_C void SetPrintFunc(PrintFunc func)
1227 gPrint = func;
1231 SC_DLLEXPORT_C int scprintf(const char *fmt, ...)
1233 va_list vargs;
1234 va_start(vargs, fmt);
1236 if (gPrint) return (*gPrint)(fmt, vargs);
1237 else return vprintf(fmt, vargs);