Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / scsynth / SC_World.cpp
blob4b88242a8417a3a80f2cb16bbad6e2f15bb66785
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);
149 void zfree(void * ptr)
151 return free(ptr);
155 ////////////////////////////////////////////////////////////////////////////////
157 static bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd);
158 static void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames);
159 static void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd);
161 void InterfaceTable_Init()
163 InterfaceTable *ft = &gInterfaceTable;
165 ft->mSine = gSine;
166 ft->mCosecant = gInvSine;
167 ft->mSineSize = kSineSize;
168 ft->mSineWavetable = gSineWavetable;
170 ft->fPrint = &scprintf;
172 ft->fRanSeed = &server_timeseed;
174 ft->fNodeEnd = &Node_End;
176 ft->fDefineUnit = &UnitDef_Create;
177 ft->fDefineBufGen = &BufGen_Create;
178 ft->fClearUnitOutputs = &Unit_ZeroOutputs;
180 ft->fNRTAlloc = &malloc;
181 ft->fNRTRealloc = &realloc;
182 ft->fNRTFree = &free;
184 ft->fRTAlloc = &World_Alloc;
185 ft->fRTRealloc = &World_Realloc;
186 ft->fRTFree = &World_Free;
188 ft->fNodeRun = &Node_SetRun;
190 ft->fSendTrigger = &Node_SendTrigger;
191 ft->fSendNodeReply = &Node_SendReply;
194 ft->fDefineUnitCmd = &UnitDef_AddCmd;
195 ft->fDefinePlugInCmd = &PlugIn_DefineCmd;
197 ft->fSendMsgFromRT = &SendMsgFromEngine;
198 ft->fSendMsgToRT = &SendMsgToEngine;
199 #ifdef NO_LIBSNDFILE
200 ft->fSndFileFormatInfoFromStrings = NULL;
201 #else
202 ft->fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
203 #endif
204 ft->fGetNode = &World_GetNode;
205 ft->fGetGraph = &World_GetGraph;
207 ft->fNRTLock = &World_NRTLock;
208 ft->fNRTUnlock = &World_NRTUnlock;
210 ft->mAltivecAvailable = sc_UseVectorUnit();
212 ft->fGroup_DeleteAll = &Group_DeleteAll;
213 ft->fDoneAction = &Unit_DoneAction;
214 ft->fDoAsynchronousCommand = &PerformAsynchronousCommand;
215 ft->fBufAlloc = &bufAlloc;
217 ft->fSCfftCreate = &scfft_create;
218 ft->fSCfftDestroy = &scfft_destroy;
219 ft->fSCfftDoFFT = &scfft_dofft;
220 ft->fSCfftDoIFFT = &scfft_doifft;
222 ft->fGetScopeBuffer = &getScopeBuffer;
223 ft->fPushScopeBuffer = &pushScopeBuffer;
224 ft->fReleaseScopeBuffer = &releaseScopeBuffer;
227 void initialize_library(const char *mUGensPluginPath);
228 void initializeScheduler();
230 static void World_LoadGraphDefs(World* world);
231 void World_LoadGraphDefs(World* world)
233 GraphDef *list = 0;
235 if(getenv("SC_SYNTHDEF_PATH")){
236 if(world->mVerbosity > 0)
237 scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH"));
238 SC_StringParser sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER);
239 while (!sp.AtEnd()) {
240 GraphDef *list = 0;
241 char *path = const_cast<char *>(sp.NextToken());
242 list = GraphDef_LoadDir(world, path, list);
243 GraphDef_Define(world, list);
245 }else{
246 char resourceDir[MAXPATHLEN];
247 if(sc_IsStandAlone())
248 sc_GetResourceDirectory(resourceDir, MAXPATHLEN);
249 else
250 sc_GetUserAppSupportDirectory(resourceDir, MAXPATHLEN);
251 sc_AppendToPath(resourceDir, MAXPATHLEN, "synthdefs");
252 if(world->mVerbosity > 0)
253 scprintf("Loading synthdefs from default path: %s\n", resourceDir);
254 list = GraphDef_LoadDir(world, resourceDir, list);
255 GraphDef_Define(world, list);
260 SC_DLLEXPORT_C World* World_New(WorldOptions *inOptions)
262 #if (_POSIX_MEMLOCK - 0) >= 200112L
263 if (inOptions->mMemoryLocking && inOptions->mRealTime)
265 bool lock_memory = false;
267 rlimit limit;
269 int failure = getrlimit(RLIMIT_MEMLOCK, &limit);
270 if (failure)
271 scprintf("getrlimit failure\n");
272 else
274 if (limit.rlim_cur == RLIM_INFINITY and
275 limit.rlim_max == RLIM_INFINITY)
276 lock_memory = true;
277 else
278 scprintf("memory locking disabled due to resource limiting\n");
280 if (lock_memory)
282 if (mlockall(MCL_FUTURE) != -1)
283 scprintf("memory locking enabled.\n");
287 #endif
289 World *world = 0;
291 try {
292 static bool gLibInitted = false;
293 if (!gLibInitted) {
294 InterfaceTable_Init();
295 initialize_library(inOptions->mUGensPluginPath);
296 initializeScheduler();
297 gLibInitted = true;
300 world = (World*)zalloc(1, sizeof(World));
302 world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld));
304 world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0);
305 world->hw->mQuitProgram = new SC_Semaphore(0);
306 world->hw->mTerminating = false;
308 extern Malloc gMalloc;
310 HiddenWorld *hw = world->hw;
311 hw->mGraphDefLib = new HashTable<struct GraphDef, Malloc>(&gMalloc, inOptions->mMaxGraphDefs, false);
312 hw->mNodeLib = new IntHashTable<Node, AllocPool>(hw->mAllocPool, inOptions->mMaxNodes, false);
313 hw->mUsers = (ReplyAddress*)zalloc(inOptions->mMaxLogins, sizeof(ReplyAddress));
314 hw->mNumUsers = 0;
315 hw->mMaxUsers = inOptions->mMaxLogins;
316 hw->mHiddenID = -8;
317 hw->mRecentID = -8;
320 world->mNumUnits = 0;
321 world->mNumGraphs = 0;
322 world->mNumGroups = 0;
324 world->mBufCounter = 0;
325 world->mBufLength = inOptions->mBufLength;
326 world->mSampleOffset = 0;
327 world->mSubsampleOffset = 0.f;
328 world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels;
329 world->mNumControlBusChannels = inOptions->mNumControlBusChannels;
330 world->mNumInputs = inOptions->mNumInputBusChannels;
331 world->mNumOutputs = inOptions->mNumOutputBusChannels;
333 world->mVerbosity = inOptions->mVerbosity;
334 world->mErrorNotification = 1; // i.e., 0x01 | 0x02
335 world->mLocalErrorNotification = 0;
337 if (inOptions->mSharedMemoryID) {
338 server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID);
339 hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels);
340 world->mControlBus = hw->mShmem->get_control_busses();
341 } else {
342 hw->mShmem = 0;
343 world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float));
346 world->mNumSharedControls = 0;
347 world->mSharedControls = inOptions->mSharedControls;
349 int numsamples = world->mBufLength * world->mNumAudioBusChannels;
350 world->mAudioBus = (float*)zalloc(numsamples, sizeof(float));
352 world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32));
353 world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32));
355 world->mNumSndBufs = inOptions->mNumBuffers;
356 world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
357 world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
358 world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates));
360 GroupNodeDef_Init();
362 int err = Group_New(world, 0, &world->mTopGroup);
363 if (err) throw err;
365 world->mRealTime = inOptions->mRealTime;
367 world->ft = &gInterfaceTable;
369 world->mNumRGens = inOptions->mNumRGens;
370 world->mRGen = new RGen[world->mNumRGens];
371 for (uint32 i=0; i<world->mNumRGens; ++i) {
372 world->mRGen[i].init(server_timeseed());
375 world->mNRTLock = new SC_Lock();
376 world->mDriverLock = new SC_Lock();
378 if (inOptions->mPassword) {
379 strncpy(world->hw->mPassword, inOptions->mPassword, 31);
380 world->hw->mPassword[31] = 0;
381 } else {
382 world->hw->mPassword[0] = 0;
385 #ifdef __APPLE__
386 world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled;
387 world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled;
388 #endif
389 world->hw->mInDeviceName = inOptions->mInDeviceName;
390 world->hw->mOutDeviceName = inOptions->mOutDeviceName;
391 hw->mMaxWireBufs = inOptions->mMaxWireBufs;
392 hw->mWireBufSpace = 0;
394 world->mRendezvous = inOptions->mRendezvous;
396 world->mRestrictedPath = inOptions->mRestrictedPath;
398 if(inOptions->mVerbosity >= 1) {
399 scprintf("Using vector unit: %s\n", sc_UseVectorUnit() ? "yes" : "no");
401 sc_SetDenormalFlags();
403 if (world->mRealTime) {
404 hw->mAudioDriver = SC_NewAudioDriver(world);
405 hw->mAudioDriver->SetPreferredHardwareBufferFrameSize(
406 inOptions->mPreferredHardwareBufferFrameSize
408 hw->mAudioDriver->SetPreferredSampleRate(
409 inOptions->mPreferredSampleRate
412 if (inOptions->mLoadGraphDefs) {
413 World_LoadGraphDefs(world);
416 if (!hw->mAudioDriver->Setup()) {
417 scprintf("could not initialize audio.\n");
418 return 0;
420 if (!hw->mAudioDriver->Start()) {
421 scprintf("start audio failed.\n");
422 return 0;
424 } else {
425 hw->mAudioDriver = 0;
427 } catch (std::exception& exc) {
428 scprintf("Exception in World_New: %s\n", exc.what());
429 World_Cleanup(world);
430 return 0;
431 } catch (...) {
433 return world;
436 SC_DLLEXPORT_C int World_CopySndBuf(World *world, uint32 index, SndBuf *outBuf, bool onlyIfChanged, bool *outDidChange)
438 if (index > world->mNumSndBufs) return kSCErr_IndexOutOfRange;
440 SndBufUpdates *updates = world->mSndBufUpdates + index;
441 bool didChange = updates->reads != updates->writes;
443 if (!onlyIfChanged || didChange)
446 world->mNRTLock->Lock();
448 SndBuf *buf = world->mSndBufsNonRealTimeMirror + index;
450 if (buf->data && buf->samples)
452 uint32 bufSize = buf->samples * sizeof(float);
453 if (buf->samples != outBuf->samples)
455 free(outBuf->data);
456 outBuf->data = (float*)malloc(bufSize);
458 memcpy(outBuf->data, buf->data, bufSize);
459 outBuf->channels = buf->channels;
460 outBuf->samples = buf->samples;
461 outBuf->frames = buf->frames;
462 outBuf->mask = buf->mask;
463 outBuf->mask1 = buf->mask1;
465 else
467 free(outBuf->data);
468 outBuf->data = 0;
469 outBuf->channels = 0;
470 outBuf->samples = 0;
471 outBuf->frames = 0;
472 outBuf->mask = 0;
473 outBuf->mask1 = 0;
476 outBuf->samplerate = buf->samplerate;
477 outBuf->sampledur = buf->sampledur;
478 outBuf->coord = buf->coord;
479 outBuf->sndfile = 0;
481 updates->reads = updates->writes;
483 world->mNRTLock->Unlock();
486 if (outDidChange) *outDidChange = didChange;
488 return kSCErr_None;
491 bool nextOSCPacket(FILE *file, OSC_Packet *packet, int64& outTime)
493 int32 msglen;
494 if (fread(&msglen, 1, sizeof(int32), file) != sizeof(int32))
495 return true;
496 // msglen is in network byte order
497 msglen = OSCint((char*)&msglen);
498 if (msglen > 8192)
499 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
501 size_t read = fread(packet->mData, 1, msglen, file);
502 if (read != msglen)
503 throw std::runtime_error("nextOSCPacket: invalid read of OSC packaet\n");
505 if (strcmp(packet->mData, "#bundle")!=0)
506 throw std::runtime_error("OSC packet not a bundle\n");
508 packet->mSize = msglen;
510 outTime = OSCtime(packet->mData+8);
511 return false;
514 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
516 #ifndef NO_LIBSNDFILE
517 SC_DLLEXPORT_C void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions)
519 if (inOptions->mLoadGraphDefs) {
520 World_LoadGraphDefs(world);
522 int bufLength = world->mBufLength;
523 int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize;
524 if (fileBufFrames <= 0) fileBufFrames = 8192;
525 int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength;
526 fileBufFrames = bufMultiple * bufLength;
528 // batch process non real time audio
529 if (!inOptions->mNonRealTimeOutputFilename)
530 throw std::runtime_error("Non real time output filename is NULL.\n");
532 SF_INFO inputFileInfo, outputFileInfo;
533 float *inputFileBuf = 0;
534 float *outputFileBuf = 0;
535 int numInputChannels = 0;
536 int numOutputChannels;
538 outputFileInfo.samplerate = inOptions->mPreferredSampleRate;
539 numOutputChannels = outputFileInfo.channels = world->mNumOutputs;
540 sndfileFormatInfoFromStrings(&outputFileInfo,
541 inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat);
543 world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo);
544 sf_command(world->hw->mNRTOutputFile, SFC_SET_CLIPPING, NULL, SF_TRUE);
546 if (!world->hw->mNRTOutputFile)
547 throw std::runtime_error("Couldn't open non real time output file.\n");
549 outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float));
551 if (inOptions->mNonRealTimeInputFilename) {
552 world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo);
553 if (!world->hw->mNRTInputFile)
554 throw std::runtime_error("Couldn't open non real time input file.\n");
556 inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float));
558 if (world->mNumInputs != (uint32)inputFileInfo.channels)
559 scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");
561 numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it.
563 if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate)
564 scprintf("WARNING: input file sample rate does not equal output sample rate.\n");
566 } else {
567 world->hw->mNRTInputFile = 0;
570 FILE *cmdFile;
571 if (inOptions->mNonRealTimeCmdFilename) {
572 #ifdef _WIN32
573 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb");
574 #else
575 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r");
576 #endif
577 } else cmdFile = stdin;
578 if (!cmdFile)
579 throw std::runtime_error("Couldn't open non real time command file.\n");
581 char msgbuf[8192];
582 OSC_Packet packet;
583 memset(&packet, 0, sizeof(packet));
584 packet.mData = msgbuf;
585 packet.mIsBundle = true;
586 packet.mReplyAddr.mReplyFunc = null_reply_func;
588 int64 schedTime;
589 if (nextOSCPacket(cmdFile, &packet, schedTime))
590 throw std::runtime_error("command file empty.\n");
591 int64 prevTime = schedTime;
593 World_SetSampleRate(world, inOptions->mPreferredSampleRate);
594 World_Start(world);
596 int64 oscTime = 0;
597 double oscToSeconds = 1. / pow(2.,32.);
598 double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds;
599 int64 oscInc = (int64)((double)bufLength / oscToSamples);
601 if(inOptions->mVerbosity >= 0) {
602 printf("start time %g\n", schedTime * oscToSeconds);
605 bool run = true;
606 int inBufStep = numInputChannels * bufLength;
607 int outBufStep = numOutputChannels * bufLength;
608 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufLength;
609 float* outputBuses = world->mAudioBus;
610 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
611 int32* outputTouched = world->mAudioBusTouched;
612 for (; run;) {
613 int bufFramesCalculated = 0;
614 float* inBufPos = inputFileBuf;
615 float* outBufPos = outputFileBuf;
617 if (world->hw->mNRTInputFile) {
618 int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames);
619 if (framesRead < fileBufFrames) {
620 memset(inputFileBuf + framesRead * numInputChannels, 0,
621 (fileBufFrames - framesRead) * numInputChannels * sizeof(float));
625 for (int i=0; i<bufMultiple && run; ++i) {
626 int bufCounter = world->mBufCounter;
628 // deinterleave input to input buses
629 if (inputFileBuf) {
630 float *inBus = inputBuses;
631 for (int j=0; j<numInputChannels; ++j, inBus += bufLength) {
632 float *inFileBufPtr = inBufPos + j;
633 for (int k=0; k<bufLength; ++k) {
634 inBus[k] = *inFileBufPtr;
635 inFileBufPtr += numInputChannels;
637 inputTouched[j] = bufCounter;
641 // execute ready commands
642 int64 nextTime = oscTime + oscInc;
644 while (schedTime <= nextTime) {
645 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
646 float diffTimeFloor = floor(diffTime);
647 world->mSampleOffset = (int)diffTimeFloor;
648 world->mSubsampleOffset = diffTime - diffTimeFloor;
650 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
651 else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1;
654 PerformOSCBundle(world, &packet);
655 if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; }
656 if(inOptions->mVerbosity >= 0) {
657 printf("nextOSCPacket %g\n", schedTime * oscToSeconds);
659 if (schedTime < prevTime) {
660 scprintf("ERROR: Packet time stamps out-of-order.\n");
661 run = false;
662 goto Bail;
664 prevTime = schedTime;
667 World_Run(world);
669 // interleave output to output buffer
670 float *outBus = outputBuses;
671 for (int j=0; j<numOutputChannels; ++j, outBus += bufLength) {
672 float *outFileBufPtr = outBufPos + j;
673 if (outputTouched[j] == bufCounter) {
674 for (int k=0; k<bufLength; ++k) {
675 *outFileBufPtr = outBus[k];
676 outFileBufPtr += numOutputChannels;
678 } else {
679 for (int k=0; k<bufLength; ++k) {
680 *outFileBufPtr = 0.f;
681 outFileBufPtr += numOutputChannels;
685 bufFramesCalculated += bufLength;
686 inBufPos += inBufStep;
687 outBufPos += outBufStep;
688 world->mBufCounter++;
689 oscTime = nextTime;
692 Bail:
693 // write output
694 sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated);
697 if (cmdFile != stdin) fclose(cmdFile);
698 sf_close(world->hw->mNRTOutputFile);
699 world->hw->mNRTOutputFile = 0;
701 if (world->hw->mNRTInputFile) {
702 sf_close(world->hw->mNRTInputFile);
703 world->hw->mNRTInputFile = 0;
706 World_Cleanup(world);
708 #endif // !NO_LIBSNDFILE
710 SC_DLLEXPORT_C void World_WaitForQuit(struct World *inWorld)
712 try {
713 inWorld->hw->mQuitProgram->Acquire();
714 World_Cleanup(inWorld);
715 } catch (std::exception& exc) {
716 scprintf("Exception in World_WaitForQuit: %s\n", exc.what());
717 } catch (...) {
721 void World_SetSampleRate(World *inWorld, double inSampleRate)
723 inWorld->mSampleRate = inSampleRate;
724 Rate_Init(&inWorld->mFullRate, inSampleRate, inWorld->mBufLength);
725 Rate_Init(&inWorld->mBufRate, inSampleRate / inWorld->mBufLength, 1);
728 ////////////////////////////////////////////////////////////////////////////////
730 void* World_Alloc(World *inWorld, size_t inByteSize)
732 return inWorld->hw->mAllocPool->Alloc(inByteSize);
735 void* World_Realloc(World *inWorld, void *inPtr, size_t inByteSize)
737 return inWorld->hw->mAllocPool->Realloc(inPtr, inByteSize);
740 size_t World_TotalFree(World *inWorld)
742 return inWorld->hw->mAllocPool->TotalFree();
745 size_t World_LargestFreeChunk(World *inWorld)
747 return inWorld->hw->mAllocPool->LargestFreeChunk();
750 void World_Free(World *inWorld, void *inPtr)
752 inWorld->hw->mAllocPool->Free(inPtr);
755 ////////////////////////////////////////////////////////////////////////////////
757 int32 *GetKey(GraphDef *inGraphDef)
759 return inGraphDef->mNodeDef.mName;
762 int32 GetHash(GraphDef *inGraphDef)
764 return inGraphDef->mNodeDef.mHash;
767 void World_AddGraphDef(World *inWorld, GraphDef* inGraphDef)
769 bool added = inWorld->hw->mGraphDefLib->Add(inGraphDef);
770 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef->mNodeDef.mName);
771 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
772 GraphDef* var = inGraphDef->mVariants + i;
773 added = inWorld->hw->mGraphDefLib->Add(var);
774 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var->mNodeDef.mName);
778 void World_RemoveGraphDef(World *inWorld, GraphDef* inGraphDef)
780 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
781 GraphDef* var = inGraphDef->mVariants + i;
782 inWorld->hw->mGraphDefLib->Remove(var);
784 inWorld->hw->mGraphDefLib->Remove(inGraphDef);
787 void World_FreeAllGraphDefs(World *inWorld)
789 GrafDefTable* lib = inWorld->hw->mGraphDefLib;
790 int size = lib->TableSize();
791 for (int i=0; i<size; ++i) {
792 GraphDef *def = lib->AtIndex(i);
793 if (def) GraphDef_Free(def);
795 lib->MakeEmpty();
798 GraphDef* World_GetGraphDef(World *inWorld, int32* inKey)
800 return inWorld->hw->mGraphDefLib->Get(inKey);
803 ////////////////////////////////////////////////////////////////////////////////
805 int32 *GetKey(UnitDef *inUnitDef)
807 return inUnitDef->mUnitDefName;
810 int32 GetHash(UnitDef *inUnitDef)
812 return inUnitDef->mHash;
815 bool AddUnitDef(UnitDef* inUnitDef)
817 return gUnitDefLib->Add(inUnitDef);
820 bool RemoveUnitDef(UnitDef* inUnitDef)
822 return gUnitDefLib->Remove(inUnitDef);
825 UnitDef* GetUnitDef(int32* inKey)
827 return gUnitDefLib->Get(inKey);
830 ////////////////////////////////////////////////////////////////////////////////
832 int32 *GetKey(BufGen *inBufGen)
834 return inBufGen->mBufGenName;
837 int32 GetHash(BufGen *inBufGen)
839 return inBufGen->mHash;
842 bool AddBufGen(BufGen* inBufGen)
844 return gBufGenLib->Add(inBufGen);
847 bool RemoveBufGen(BufGen* inBufGen)
849 return gBufGenLib->Remove(inBufGen);
852 BufGen* GetBufGen(int32* inKey)
854 return gBufGenLib->Get(inKey);
857 ////////////////////////////////////////////////////////////////////////////////
859 int32 *GetKey(PlugInCmd *inPlugInCmd)
861 return inPlugInCmd->mCmdName;
864 int32 GetHash(PlugInCmd *inPlugInCmd)
866 return inPlugInCmd->mHash;
869 bool AddPlugInCmd(PlugInCmd* inPlugInCmd)
871 return gPlugInCmds->Add(inPlugInCmd);
874 bool RemovePlugInCmd(PlugInCmd* inPlugInCmd)
876 return gPlugInCmds->Remove(inPlugInCmd);
879 PlugInCmd* GetPlugInCmd(int32* inKey)
881 return gPlugInCmds->Get(inKey);
884 ////////////////////////////////////////////////////////////////////////////////
886 int32 GetKey(Node *inNode)
888 return inNode->mID;
891 int32 GetHash(Node *inNode)
893 return inNode->mHash;
896 bool World_AddNode(World *inWorld, Node* inNode)
898 return inWorld->hw->mNodeLib->Add(inNode);
901 bool World_RemoveNode(World *inWorld, Node* inNode)
903 return inWorld->hw->mNodeLib->Remove(inNode);
906 Node* World_GetNode(World *inWorld, int32 inID)
908 if (inID == -1) inID = inWorld->hw->mRecentID;
909 return inWorld->hw->mNodeLib->Get(inID);
912 Graph* World_GetGraph(World *inWorld, int32 inID)
914 if (inID == -1) inID = inWorld->hw->mRecentID;
915 Node *node = World_GetNode(inWorld, inID);
916 if (!node) return 0;
917 return node->mIsGroup ? 0 : (Graph*)node;
920 Group* World_GetGroup(World *inWorld, int32 inID)
922 Node *node = World_GetNode(inWorld, inID);
923 if (!node) return 0;
924 return node->mIsGroup ? (Group*)node : 0;
927 ////////////////////////////////////////////////////////////////////////////////
929 void World_Run(World *inWorld)
931 // run top group
932 Node *node = (Node*)inWorld->mTopGroup;
933 (*node->mCalcFunc)(node);
936 void World_Start(World *inWorld)
938 inWorld->mBufCounter = 0;
939 for (uint32 i=0; i<inWorld->mNumAudioBusChannels; ++i) inWorld->mAudioBusTouched[i] = -1;
940 for (uint32 i=0; i<inWorld->mNumControlBusChannels; ++i) inWorld->mControlBusTouched[i] = -1;
942 inWorld->hw->mWireBufSpace = (float*)sc_malloc(inWorld->hw->mMaxWireBufs * inWorld->mBufLength * sizeof(float));
944 inWorld->hw->mTriggers.MakeEmpty();
945 inWorld->hw->mNodeMsgs.MakeEmpty();
946 inWorld->hw->mNodeEnds.MakeEmpty();
947 inWorld->mRunning = true;
950 SC_DLLEXPORT_C void World_Cleanup(World *world)
952 if (!world) return;
954 HiddenWorld *hw = world->hw;
956 if (hw && world->mRealTime) hw->mAudioDriver->Stop();
958 world->mRunning = false;
960 if (world->mTopGroup) Group_DeleteAll(world->mTopGroup);
962 world->mDriverLock->Lock(); // never unlock..
963 if (hw) {
964 sc_free(hw->mWireBufSpace);
965 delete hw->mAudioDriver;
966 hw->mAudioDriver = 0;
968 delete world->mNRTLock;
969 delete world->mDriverLock;
970 World_Free(world, world->mTopGroup);
972 for (uint32 i=0; i<world->mNumSndBufs; ++i) {
973 SndBuf *nrtbuf = world->mSndBufsNonRealTimeMirror + i;
974 SndBuf * rtbuf = world->mSndBufs + i;
976 if (nrtbuf->data) free(nrtbuf->data);
977 if (rtbuf->data && rtbuf->data != nrtbuf->data) free(rtbuf->data);
979 #ifndef NO_LIBSNDFILE
980 if (nrtbuf->sndfile) sf_close(nrtbuf->sndfile);
981 if (rtbuf->sndfile && rtbuf->sndfile != nrtbuf->sndfile) sf_close(rtbuf->sndfile);
982 #endif
985 free(world->mSndBufsNonRealTimeMirror);
986 free(world->mSndBufs);
988 free(world->mControlBusTouched);
989 free(world->mAudioBusTouched);
990 if (hw->mShmem) {
991 delete hw->mShmem;
992 } else
993 free(world->mControlBus);
994 free(world->mAudioBus);
995 delete [] world->mRGen;
996 if (hw) {
998 #ifndef NO_LIBSNDFILE
999 if (hw->mNRTInputFile) sf_close(hw->mNRTInputFile);
1000 if (hw->mNRTOutputFile) sf_close(hw->mNRTOutputFile);
1001 if (hw->mNRTCmdFile) fclose(hw->mNRTCmdFile);
1002 #endif
1003 free(hw->mUsers);
1004 delete hw->mNodeLib;
1005 delete hw->mGraphDefLib;
1006 delete hw->mQuitProgram;
1007 delete hw->mAllocPool;
1008 free(hw);
1010 free(world);
1014 void World_NRTLock(World *world)
1016 world->mNRTLock->Lock();
1019 void World_NRTUnlock(World *world)
1021 world->mNRTLock->Unlock();
1024 ////////////////////////////////////////////////////////////////////////////////
1026 bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd)
1028 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1030 scope_buffer_writer writer = shm->get_scope_buffer_writer( index, channels, maxFrames );
1032 if( writer.valid() ) {
1033 hnd.internalData = writer.buffer;
1034 hnd.data = writer.data();
1035 hnd.channels = channels;
1036 hnd.maxFrames = maxFrames;
1037 return true;
1039 else {
1040 hnd.internalData = 0;
1041 return false;
1045 void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames)
1047 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1048 writer.push(frames);
1049 hnd.data = writer.data();
1052 void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd)
1054 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1055 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1056 shm->release_scope_buffer_writer( writer );
1059 ////////////////////////////////////////////////////////////////////////////////
1062 inline int32 BUFMASK(int32 x)
1064 return (1 << (31 - CLZ(x))) - 1;
1067 SCErr bufAlloc(SndBuf* buf, int numChannels, int numFrames, double sampleRate)
1069 long numSamples = numFrames * numChannels;
1070 if(numSamples < 1) return kSCErr_Failed;
1071 buf->data = (float*)zalloc(numSamples, sizeof(float));
1072 if (!buf->data) return kSCErr_Failed;
1074 buf->channels = numChannels;
1075 buf->frames = numFrames;
1076 buf->samples = numSamples;
1077 buf->mask = BUFMASK(numSamples); // for delay lines
1078 buf->mask1 = buf->mask - 1; // for oscillators
1079 buf->samplerate = sampleRate;
1080 buf->sampledur = 1. / sampleRate;
1082 return kSCErr_None;
1085 #include "scsynthsend.h"
1087 void TriggerMsg::Perform()
1089 small_scpacket packet;
1090 packet.adds("/tr");
1091 packet.maketags(4);
1092 packet.addtag(',');
1093 packet.addtag('i');
1094 packet.addtag('i');
1095 packet.addtag('f');
1096 packet.addi(mNodeID);
1097 packet.addi(mTriggerID);
1098 packet.addf(mValue);
1100 ReplyAddress *users = mWorld->hw->mUsers;
1101 int numUsers = mWorld->hw->mNumUsers;
1102 for (int i=0; i<numUsers; ++i) {
1103 SendReply(users+i, packet.data(), packet.size());
1107 static void NodeReplyMsg_RTFree(FifoMsg* msg)
1109 //scprintf("NodeReplyMsg_RTFree()\n");
1110 World_Free(msg->mWorld, msg->mData);
1113 void NodeReplyMsg::Perform()
1115 small_scpacket packet;
1116 packet.adds(mCmdName, mCmdNameSize);
1117 packet.maketags(3 + mNumArgs);
1118 packet.addtag(',');
1119 packet.addtag('i');
1120 packet.addi(mNodeID);
1121 packet.addtag('i');
1122 packet.addi(mID);
1123 for(int i=0; i<mNumArgs; ++i) {
1124 packet.addtag('f');
1125 packet.addf(mValues[i]);
1128 ReplyAddress *users = mWorld->hw->mUsers;
1129 int numUsers = mWorld->hw->mNumUsers;
1130 for (int i=0; i<numUsers; ++i) {
1131 SendReply(users+i, packet.data(), packet.size());
1134 // Free memory in realtime thread
1135 FifoMsg msg;
1136 msg.Set(mWorld, NodeReplyMsg_RTFree, 0, mRTMemory);
1137 AudioDriver(mWorld)->SendMsgToEngine(msg);
1141 void NodeEndMsg::Perform()
1143 small_scpacket packet;
1144 switch (mState) {
1145 case kNode_Go :
1146 packet.adds("/n_go");
1147 break;
1148 case kNode_End :
1149 packet.adds("/n_end");
1150 break;
1151 case kNode_On :
1152 packet.adds("/n_on");
1153 break;
1154 case kNode_Off :
1155 packet.adds("/n_off");
1156 break;
1157 case kNode_Move :
1158 packet.adds("/n_move");
1159 break;
1160 case kNode_Info :
1161 packet.adds("/n_info");
1162 break;
1164 if (mIsGroup) {
1165 packet.maketags(8);
1166 packet.addtag(',');
1167 packet.addtag('i');
1168 packet.addtag('i');
1169 packet.addtag('i');
1170 packet.addtag('i');
1171 packet.addtag('i');
1172 packet.addtag('i');
1173 packet.addtag('i');
1174 packet.addi(mNodeID);
1175 packet.addi(mGroupID);
1176 packet.addi(mPrevNodeID);
1177 packet.addi(mNextNodeID);
1178 packet.addi(mIsGroup);
1179 packet.addi(mHeadID);
1180 packet.addi(mTailID);
1181 } else {
1182 packet.maketags(6);
1183 packet.addtag(',');
1184 packet.addtag('i');
1185 packet.addtag('i');
1186 packet.addtag('i');
1187 packet.addtag('i');
1188 packet.addtag('i');
1189 packet.addi(mNodeID);
1190 packet.addi(mGroupID);
1191 packet.addi(mPrevNodeID);
1192 packet.addi(mNextNodeID);
1193 packet.addi(mIsGroup);
1196 ReplyAddress *users = mWorld->hw->mUsers;
1197 int numUsers = mWorld->hw->mNumUsers;
1198 for (int i=0; i<numUsers; ++i) {
1199 SendReply(users+i, packet.data(), packet.size());
1203 void DeleteGraphDefMsg::Perform()
1205 GraphDef_Free(mDef);
1208 void NotifyNoArgs(World *inWorld, char *inString);
1209 void NotifyNoArgs(World *inWorld, char *inString)
1211 small_scpacket packet;
1212 packet.adds(inString);
1214 ReplyAddress *users = inWorld->hw->mUsers;
1215 int numUsers = inWorld->hw->mNumUsers;
1216 for (int i=0; i<numUsers; ++i) {
1217 SendReply(users+i, packet.data(), packet.size());
1222 bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg)
1224 return inWorld->hw->mAudioDriver->SendMsgToEngine(inMsg);
1227 bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg)
1229 return inWorld->hw->mAudioDriver->SendMsgFromEngine(inMsg);
1232 SC_DLLEXPORT_C void SetPrintFunc(PrintFunc func)
1234 gPrint = func;
1238 SC_DLLEXPORT_C int scprintf(const char *fmt, ...)
1240 va_list vargs;
1241 va_start(vargs, fmt);
1243 if (gPrint) return (*gPrint)(fmt, vargs);
1244 else return vprintf(fmt, vargs);