FFT: Prevent user from attempting hops smaller than SC's block size
[supercollider.git] / server / scsynth / SC_World.cpp
blobf449f6dba249ea99c9261355a0118521b8a4f9a6
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 // undefine the shadowed scfft functions
47 #undef scfft_create
48 #undef scfft_dofft
49 #undef scfft_doifft
50 #undef scfft_destroy
52 #if (_POSIX_MEMLOCK - 0) >= 200112L
53 # include <sys/resource.h>
54 # include <sys/mman.h>
55 #endif
57 #include "server_shm.hpp"
60 InterfaceTable gInterfaceTable;
61 PrintFunc gPrint = 0;
63 extern HashTable<struct UnitDef, Malloc> *gUnitDefLib;
64 extern HashTable<struct BufGen, Malloc> *gBufGenLib;
65 extern HashTable<PlugInCmd, Malloc> *gPlugInCmds;
67 extern "C" {
69 #ifdef NO_LIBSNDFILE
70 struct SF_INFO {};
71 #endif
73 bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg);
74 bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg);
77 bool sc_UseVectorUnit();
78 void sc_SetDenormalFlags();
80 ////////////////////////////////////////////////////////////////////////////////
82 #ifdef __linux__
84 #ifndef _XOPEN_SOURCE
85 #define _XOPEN_SOURCE 600
86 #endif
87 #include <stdlib.h>
88 #include <errno.h>
90 #ifndef SC_MEMORY_ALIGNMENT
91 # error SC_MEMORY_ALIGNMENT undefined
92 #endif
93 #define SC_DBUG_MEMORY 0
95 inline void* sc_malloc(size_t size)
97 #if SC_MEMORY_ALIGNMENT > 1
98 void* ptr;
99 int err = posix_memalign(&ptr, SC_MEMORY_ALIGNMENT, size);
100 if (err) {
101 if (err != ENOMEM) {
102 perror("sc_malloc");
103 abort();
105 return 0;
107 return ptr;
108 #else
109 return malloc(size);
110 #endif
113 void* sc_dbg_malloc(size_t size, const char* tag, int line)
115 void* ptr = sc_malloc(size);
116 fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu\n", tag, line, ptr, size);
117 #if SC_MEMORY_ALIGNMENT > 1
118 if (((intptr_t)ptr % SC_MEMORY_ALIGNMENT) != 0) {
119 fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu: memory alignment error\n",
120 tag, line, ptr, size);
121 abort();
123 #endif
124 return ptr;
127 inline void sc_free(void* ptr)
129 free(ptr);
132 void sc_dbg_free(void* ptr, const char* tag, int line)
134 fprintf(stderr, "sc_dbg_free [%s:%d]: %p\n", tag, line, ptr);
135 free(ptr);
138 inline void* sc_zalloc(size_t n, size_t size)
140 size *= n;
141 if (size) {
142 void* ptr = sc_malloc(size);
143 if (ptr) {
144 memset(ptr, 0, size);
145 return ptr;
148 return 0;
151 void* sc_dbg_zalloc(size_t n, size_t size, const char* tag, int line)
153 void* ptr = sc_zalloc(n, size);
154 fprintf(stderr, "sc_dbg_zalloc [%s:%d]: %p %zu %zu\n", tag, line, ptr, n, size);
155 return ptr;
158 # if SC_DEBUG_MEMORY
159 # define malloc(size) sc_dbg_malloc((size), __FUNCTION__, __LINE__)
160 # define free(ptr) sc_dbg_free((ptr), __FUNCTION__, __LINE__)
161 # define zalloc(n, size) sc_dbg_zalloc((n), (size), __FUNCTION__, __LINE__)
162 # else
163 # define malloc(size) sc_malloc((size))
164 # define free(ptr) sc_free((ptr))
165 # define zalloc(n, size) sc_zalloc((n), (size))
166 # endif // SC_DEBUG_MEMORY
168 #endif // __linux__
170 ////////////////////////////////////////////////////////////////////////////////
172 static bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd);
173 static void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames);
174 static void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd);
176 void InterfaceTable_Init()
178 InterfaceTable *ft = &gInterfaceTable;
180 ft->mSine = gSine;
181 ft->mCosecant = gInvSine;
182 ft->mSineSize = kSineSize;
183 ft->mSineWavetable = gSineWavetable;
185 ft->fPrint = &scprintf;
187 ft->fRanSeed = &server_timeseed;
189 ft->fNodeEnd = &Node_End;
191 ft->fDefineUnit = &UnitDef_Create;
192 ft->fDefineBufGen = &BufGen_Create;
193 ft->fClearUnitOutputs = &Unit_ZeroOutputs;
195 ft->fNRTAlloc = &malloc;
196 ft->fNRTRealloc = &realloc;
197 ft->fNRTFree = &free;
199 ft->fRTAlloc = &World_Alloc;
200 ft->fRTRealloc = &World_Realloc;
201 ft->fRTFree = &World_Free;
203 ft->fNodeRun = &Node_SetRun;
205 ft->fSendTrigger = &Node_SendTrigger;
206 ft->fSendNodeReply = &Node_SendReply;
209 ft->fDefineUnitCmd = &UnitDef_AddCmd;
210 ft->fDefinePlugInCmd = &PlugIn_DefineCmd;
212 ft->fSendMsgFromRT = &SendMsgFromEngine;
213 ft->fSendMsgToRT = &SendMsgToEngine;
214 #ifdef NO_LIBSNDFILE
215 ft->fSndFileFormatInfoFromStrings = NULL;
216 #else
217 ft->fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings;
218 #endif
219 ft->fGetNode = &World_GetNode;
220 ft->fGetGraph = &World_GetGraph;
222 ft->fNRTLock = &World_NRTLock;
223 ft->fNRTUnlock = &World_NRTUnlock;
225 ft->mAltivecAvailable = sc_UseVectorUnit();
227 ft->fGroup_DeleteAll = &Group_DeleteAll;
228 ft->fDoneAction = &Unit_DoneAction;
229 ft->fDoAsynchronousCommand = &PerformAsynchronousCommand;
230 ft->fBufAlloc = &bufAlloc;
232 ft->fSCfftCreate = &scfft_create;
233 ft->fSCfftDestroy = &scfft_destroy;
234 ft->fSCfftDoFFT = &scfft_dofft;
235 ft->fSCfftDoIFFT = &scfft_doifft;
237 ft->fGetScopeBuffer = &getScopeBuffer;
238 ft->fPushScopeBuffer = &pushScopeBuffer;
239 ft->fReleaseScopeBuffer = &releaseScopeBuffer;
242 void initialize_library(const char *mUGensPluginPath);
243 void initializeScheduler();
245 static void World_LoadGraphDefs(World* world);
246 void World_LoadGraphDefs(World* world)
248 GraphDef *list = 0;
250 if(getenv("SC_SYNTHDEF_PATH")){
251 if(world->mVerbosity > 0)
252 scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH"));
253 SC_StringParser sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER);
254 while (!sp.AtEnd()) {
255 GraphDef *list = 0;
256 char *path = const_cast<char *>(sp.NextToken());
257 list = GraphDef_LoadDir(world, path, list);
258 GraphDef_Define(world, list);
260 }else{
261 char resourceDir[MAXPATHLEN];
262 if(sc_IsStandAlone())
263 sc_GetResourceDirectory(resourceDir, MAXPATHLEN);
264 else
265 sc_GetUserAppSupportDirectory(resourceDir, MAXPATHLEN);
266 sc_AppendToPath(resourceDir, MAXPATHLEN, "synthdefs");
267 if(world->mVerbosity > 0)
268 scprintf("Loading synthdefs from default path: %s\n", resourceDir);
269 list = GraphDef_LoadDir(world, resourceDir, list);
270 GraphDef_Define(world, list);
275 SC_DLLEXPORT_C World* World_New(WorldOptions *inOptions)
277 #if (_POSIX_MEMLOCK - 0) >= 200112L
278 if (inOptions->mMemoryLocking && inOptions->mRealTime)
280 bool lock_memory = false;
282 rlimit limit;
284 int failure = getrlimit(RLIMIT_MEMLOCK, &limit);
285 if (failure)
286 scprintf("getrlimit failure\n");
287 else
289 if (limit.rlim_cur == RLIM_INFINITY and
290 limit.rlim_max == RLIM_INFINITY)
291 lock_memory = true;
292 else
293 scprintf("memory locking disabled due to resource limiting\n");
295 if (lock_memory)
297 if (mlockall(MCL_FUTURE) != -1)
298 scprintf("memory locking enabled.\n");
302 #endif
304 World *world = 0;
306 try {
307 static bool gLibInitted = false;
308 if (!gLibInitted) {
309 InterfaceTable_Init();
310 initialize_library(inOptions->mUGensPluginPath);
311 initializeScheduler();
312 gLibInitted = true;
315 world = (World*)zalloc(1, sizeof(World));
317 world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld));
319 world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0);
320 world->hw->mQuitProgram = new SC_Semaphore(0);
321 world->hw->mTerminating = false;
323 extern Malloc gMalloc;
325 HiddenWorld *hw = world->hw;
326 hw->mGraphDefLib = new HashTable<struct GraphDef, Malloc>(&gMalloc, inOptions->mMaxGraphDefs, false);
327 hw->mNodeLib = new IntHashTable<Node, AllocPool>(hw->mAllocPool, inOptions->mMaxNodes, false);
328 hw->mUsers = (ReplyAddress*)zalloc(inOptions->mMaxLogins, sizeof(ReplyAddress));
329 hw->mNumUsers = 0;
330 hw->mMaxUsers = inOptions->mMaxLogins;
331 hw->mHiddenID = -8;
332 hw->mRecentID = -8;
335 world->mNumUnits = 0;
336 world->mNumGraphs = 0;
337 world->mNumGroups = 0;
339 world->mBufCounter = 0;
340 world->mBufLength = inOptions->mBufLength;
341 world->mSampleOffset = 0;
342 world->mSubsampleOffset = 0.f;
343 world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels;
344 world->mNumControlBusChannels = inOptions->mNumControlBusChannels;
345 world->mNumInputs = inOptions->mNumInputBusChannels;
346 world->mNumOutputs = inOptions->mNumOutputBusChannels;
348 world->mVerbosity = inOptions->mVerbosity;
349 world->mErrorNotification = 1; // i.e., 0x01 | 0x02
350 world->mLocalErrorNotification = 0;
352 if (inOptions->mSharedMemoryID) {
353 server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID);
354 hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels);
355 world->mControlBus = hw->mShmem->get_control_busses();
356 } else
357 world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float));
359 world->mNumSharedControls = 0;
360 world->mSharedControls = inOptions->mSharedControls;
362 int numsamples = world->mBufLength * world->mNumAudioBusChannels;
363 world->mAudioBus = (float*)zalloc(numsamples, sizeof(float));
365 world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32));
366 world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32));
368 world->mNumSndBufs = inOptions->mNumBuffers;
369 world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
370 world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
371 world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates));
373 GroupNodeDef_Init();
375 int err = Group_New(world, 0, &world->mTopGroup);
376 if (err) throw err;
378 world->mRealTime = inOptions->mRealTime;
380 world->ft = &gInterfaceTable;
382 world->mNumRGens = inOptions->mNumRGens;
383 world->mRGen = new RGen[world->mNumRGens];
384 for (uint32 i=0; i<world->mNumRGens; ++i) {
385 world->mRGen[i].init(server_timeseed());
388 world->mNRTLock = new SC_Lock();
389 world->mDriverLock = new SC_Lock();
391 if (inOptions->mPassword) {
392 strncpy(world->hw->mPassword, inOptions->mPassword, 31);
393 world->hw->mPassword[31] = 0;
394 } else {
395 world->hw->mPassword[0] = 0;
398 #ifdef __APPLE__
399 world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled;
400 world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled;
401 #endif
402 world->hw->mInDeviceName = inOptions->mInDeviceName;
403 world->hw->mOutDeviceName = inOptions->mOutDeviceName;
404 hw->mMaxWireBufs = inOptions->mMaxWireBufs;
405 hw->mWireBufSpace = 0;
407 world->mRendezvous = inOptions->mRendezvous;
409 world->mRestrictedPath = inOptions->mRestrictedPath;
411 if(inOptions->mVerbosity >= 1) {
412 scprintf("Using vector unit: %s\n", sc_UseVectorUnit() ? "yes" : "no");
414 sc_SetDenormalFlags();
416 if (world->mRealTime) {
417 hw->mAudioDriver = SC_NewAudioDriver(world);
418 hw->mAudioDriver->SetPreferredHardwareBufferFrameSize(
419 inOptions->mPreferredHardwareBufferFrameSize
421 hw->mAudioDriver->SetPreferredSampleRate(
422 inOptions->mPreferredSampleRate
425 if (inOptions->mLoadGraphDefs) {
426 World_LoadGraphDefs(world);
429 if (!hw->mAudioDriver->Setup()) {
430 scprintf("could not initialize audio.\n");
431 return 0;
433 if (!hw->mAudioDriver->Start()) {
434 scprintf("start audio failed.\n");
435 return 0;
437 } else {
438 hw->mAudioDriver = 0;
440 } catch (std::exception& exc) {
441 scprintf("Exception in World_New: %s\n", exc.what());
442 World_Cleanup(world);
443 return 0;
444 } catch (...) {
446 return world;
449 SC_DLLEXPORT_C int World_CopySndBuf(World *world, uint32 index, SndBuf *outBuf, bool onlyIfChanged, bool *outDidChange)
451 if (index > world->mNumSndBufs) return kSCErr_IndexOutOfRange;
453 SndBufUpdates *updates = world->mSndBufUpdates + index;
454 bool didChange = updates->reads != updates->writes;
456 if (!onlyIfChanged || didChange)
459 world->mNRTLock->Lock();
461 SndBuf *buf = world->mSndBufsNonRealTimeMirror + index;
463 if (buf->data && buf->samples)
465 uint32 bufSize = buf->samples * sizeof(float);
466 if (buf->samples != outBuf->samples)
468 free(outBuf->data);
469 outBuf->data = (float*)malloc(bufSize);
471 memcpy(outBuf->data, buf->data, bufSize);
472 outBuf->channels = buf->channels;
473 outBuf->samples = buf->samples;
474 outBuf->frames = buf->frames;
475 outBuf->mask = buf->mask;
476 outBuf->mask1 = buf->mask1;
478 else
480 free(outBuf->data);
481 outBuf->data = 0;
482 outBuf->channels = 0;
483 outBuf->samples = 0;
484 outBuf->frames = 0;
485 outBuf->mask = 0;
486 outBuf->mask1 = 0;
489 outBuf->samplerate = buf->samplerate;
490 outBuf->sampledur = buf->sampledur;
491 outBuf->coord = buf->coord;
492 outBuf->sndfile = 0;
494 updates->reads = updates->writes;
496 world->mNRTLock->Unlock();
499 if (outDidChange) *outDidChange = didChange;
501 return kSCErr_None;
504 bool nextOSCPacket(FILE *file, OSC_Packet *packet, int64& outTime)
506 int32 msglen;
507 if (fread(&msglen, 1, sizeof(int32), file) != sizeof(int32))
508 return true;
509 // msglen is in network byte order
510 msglen = OSCint((char*)&msglen);
511 if (msglen > 8192)
512 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
514 size_t read = fread(packet->mData, 1, msglen, file);
515 if (read != msglen)
516 throw std::runtime_error("nextOSCPacket: invalid read of OSC packaet\n");
518 if (strcmp(packet->mData, "#bundle")!=0)
519 throw std::runtime_error("OSC packet not a bundle\n");
521 packet->mSize = msglen;
523 outTime = OSCtime(packet->mData+8);
524 return false;
527 void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket);
529 #ifndef NO_LIBSNDFILE
530 SC_DLLEXPORT_C void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions)
532 if (inOptions->mLoadGraphDefs) {
533 World_LoadGraphDefs(world);
535 int bufLength = world->mBufLength;
536 int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize;
537 if (fileBufFrames <= 0) fileBufFrames = 8192;
538 int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength;
539 fileBufFrames = bufMultiple * bufLength;
541 // batch process non real time audio
542 if (!inOptions->mNonRealTimeOutputFilename)
543 throw std::runtime_error("Non real time output filename is NULL.\n");
545 SF_INFO inputFileInfo, outputFileInfo;
546 float *inputFileBuf = 0;
547 float *outputFileBuf = 0;
548 int numInputChannels = 0;
549 int numOutputChannels;
551 outputFileInfo.samplerate = inOptions->mPreferredSampleRate;
552 numOutputChannels = outputFileInfo.channels = world->mNumOutputs;
553 sndfileFormatInfoFromStrings(&outputFileInfo,
554 inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat);
556 world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo);
557 if (!world->hw->mNRTOutputFile)
558 throw std::runtime_error("Couldn't open non real time output file.\n");
560 outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float));
562 if (inOptions->mNonRealTimeInputFilename) {
563 world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo);
564 if (!world->hw->mNRTInputFile)
565 throw std::runtime_error("Couldn't open non real time input file.\n");
567 inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float));
569 if (world->mNumInputs != (uint32)inputFileInfo.channels)
570 scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");
572 numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it.
574 if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate)
575 scprintf("WARNING: input file sample rate does not equal output sample rate.\n");
577 } else {
578 world->hw->mNRTInputFile = 0;
581 FILE *cmdFile;
582 if (inOptions->mNonRealTimeCmdFilename) {
583 #ifdef _WIN32
584 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb");
585 #else
586 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r");
587 #endif
588 } else cmdFile = stdin;
589 if (!cmdFile)
590 throw std::runtime_error("Couldn't open non real time command file.\n");
592 char msgbuf[8192];
593 OSC_Packet packet;
594 memset(&packet, 0, sizeof(packet));
595 packet.mData = msgbuf;
596 packet.mIsBundle = true;
597 packet.mReplyAddr.mReplyFunc = null_reply_func;
599 int64 schedTime;
600 if (nextOSCPacket(cmdFile, &packet, schedTime))
601 throw std::runtime_error("command file empty.\n");
602 int64 prevTime = schedTime;
604 World_SetSampleRate(world, inOptions->mPreferredSampleRate);
605 World_Start(world);
607 int64 oscTime = 0;
608 double oscToSeconds = 1. / pow(2.,32.);
609 double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds;
610 int64 oscInc = (int64)((double)bufLength / oscToSamples);
612 if(inOptions->mVerbosity >= 0) {
613 printf("start time %g\n", schedTime * oscToSeconds);
616 bool run = true;
617 int inBufStep = numInputChannels * bufLength;
618 int outBufStep = numOutputChannels * bufLength;
619 float* inputBuses = world->mAudioBus + world->mNumOutputs * bufLength;
620 float* outputBuses = world->mAudioBus;
621 int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs;
622 int32* outputTouched = world->mAudioBusTouched;
623 for (; run;) {
624 int bufFramesCalculated = 0;
625 float* inBufPos = inputFileBuf;
626 float* outBufPos = outputFileBuf;
628 if (world->hw->mNRTInputFile) {
629 int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames);
630 if (framesRead < fileBufFrames) {
631 memset(inputFileBuf + framesRead * numInputChannels, 0,
632 (fileBufFrames - framesRead) * numInputChannels * sizeof(float));
636 for (int i=0; i<bufMultiple && run; ++i) {
637 int bufCounter = world->mBufCounter;
639 // deinterleave input to input buses
640 if (inputFileBuf) {
641 float *inBus = inputBuses;
642 for (int j=0; j<numInputChannels; ++j, inBus += bufLength) {
643 float *inFileBufPtr = inBufPos + j;
644 for (int k=0; k<bufLength; ++k) {
645 inBus[k] = *inFileBufPtr;
646 inFileBufPtr += numInputChannels;
648 inputTouched[j] = bufCounter;
652 // execute ready commands
653 int64 nextTime = oscTime + oscInc;
655 while (schedTime <= nextTime) {
656 float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
657 float diffTimeFloor = floor(diffTime);
658 world->mSampleOffset = (int)diffTimeFloor;
659 world->mSubsampleOffset = diffTime - diffTimeFloor;
661 if (world->mSampleOffset < 0) world->mSampleOffset = 0;
662 else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1;
665 PerformOSCBundle(world, &packet);
666 if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; }
667 if(inOptions->mVerbosity >= 0) {
668 printf("nextOSCPacket %g\n", schedTime * oscToSeconds);
670 if (schedTime < prevTime) {
671 scprintf("ERROR: Packet time stamps out-of-order.\n");
672 run = false;
673 goto Bail;
675 prevTime = schedTime;
678 World_Run(world);
680 // interleave output to output buffer
681 float *outBus = outputBuses;
682 for (int j=0; j<numOutputChannels; ++j, outBus += bufLength) {
683 float *outFileBufPtr = outBufPos + j;
684 if (outputTouched[j] == bufCounter) {
685 for (int k=0; k<bufLength; ++k) {
686 *outFileBufPtr = outBus[k];
687 outFileBufPtr += numOutputChannels;
689 } else {
690 for (int k=0; k<bufLength; ++k) {
691 *outFileBufPtr = 0.f;
692 outFileBufPtr += numOutputChannels;
696 bufFramesCalculated += bufLength;
697 inBufPos += inBufStep;
698 outBufPos += outBufStep;
699 world->mBufCounter++;
700 oscTime = nextTime;
703 Bail:
704 // write output
705 sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated);
708 if (cmdFile != stdin) fclose(cmdFile);
709 sf_close(world->hw->mNRTOutputFile);
710 world->hw->mNRTOutputFile = 0;
712 if (world->hw->mNRTInputFile) {
713 sf_close(world->hw->mNRTInputFile);
714 world->hw->mNRTInputFile = 0;
717 World_Cleanup(world);
719 #endif // !NO_LIBSNDFILE
721 SC_DLLEXPORT_C void World_WaitForQuit(struct World *inWorld)
723 try {
724 inWorld->hw->mQuitProgram->Acquire();
725 World_Cleanup(inWorld);
726 } catch (std::exception& exc) {
727 scprintf("Exception in World_WaitForQuit: %s\n", exc.what());
728 } catch (...) {
732 void World_SetSampleRate(World *inWorld, double inSampleRate)
734 inWorld->mSampleRate = inSampleRate;
735 Rate_Init(&inWorld->mFullRate, inSampleRate, inWorld->mBufLength);
736 Rate_Init(&inWorld->mBufRate, inSampleRate / inWorld->mBufLength, 1);
739 ////////////////////////////////////////////////////////////////////////////////
741 void* World_Alloc(World *inWorld, size_t inByteSize)
743 return inWorld->hw->mAllocPool->Alloc(inByteSize);
746 void* World_Realloc(World *inWorld, void *inPtr, size_t inByteSize)
748 return inWorld->hw->mAllocPool->Realloc(inPtr, inByteSize);
751 size_t World_TotalFree(World *inWorld)
753 return inWorld->hw->mAllocPool->TotalFree();
756 size_t World_LargestFreeChunk(World *inWorld)
758 return inWorld->hw->mAllocPool->LargestFreeChunk();
761 void World_Free(World *inWorld, void *inPtr)
763 inWorld->hw->mAllocPool->Free(inPtr);
766 ////////////////////////////////////////////////////////////////////////////////
768 int32 *GetKey(GraphDef *inGraphDef)
770 return inGraphDef->mNodeDef.mName;
773 int32 GetHash(GraphDef *inGraphDef)
775 return inGraphDef->mNodeDef.mHash;
778 void World_AddGraphDef(World *inWorld, GraphDef* inGraphDef)
780 bool added = inWorld->hw->mGraphDefLib->Add(inGraphDef);
781 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef->mNodeDef.mName);
782 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
783 GraphDef* var = inGraphDef->mVariants + i;
784 added = inWorld->hw->mGraphDefLib->Add(var);
785 if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var->mNodeDef.mName);
789 void World_RemoveGraphDef(World *inWorld, GraphDef* inGraphDef)
791 for (uint32 i=0; i<inGraphDef->mNumVariants; ++i) {
792 GraphDef* var = inGraphDef->mVariants + i;
793 inWorld->hw->mGraphDefLib->Remove(var);
795 inWorld->hw->mGraphDefLib->Remove(inGraphDef);
798 void World_FreeAllGraphDefs(World *inWorld)
800 GrafDefTable* lib = inWorld->hw->mGraphDefLib;
801 int size = lib->TableSize();
802 for (int i=0; i<size; ++i) {
803 GraphDef *def = lib->AtIndex(i);
804 if (def) GraphDef_Free(def);
806 lib->MakeEmpty();
809 GraphDef* World_GetGraphDef(World *inWorld, int32* inKey)
811 return inWorld->hw->mGraphDefLib->Get(inKey);
814 ////////////////////////////////////////////////////////////////////////////////
816 int32 *GetKey(UnitDef *inUnitDef)
818 return inUnitDef->mUnitDefName;
821 int32 GetHash(UnitDef *inUnitDef)
823 return inUnitDef->mHash;
826 bool AddUnitDef(UnitDef* inUnitDef)
828 return gUnitDefLib->Add(inUnitDef);
831 bool RemoveUnitDef(UnitDef* inUnitDef)
833 return gUnitDefLib->Remove(inUnitDef);
836 UnitDef* GetUnitDef(int32* inKey)
838 return gUnitDefLib->Get(inKey);
841 ////////////////////////////////////////////////////////////////////////////////
843 int32 *GetKey(BufGen *inBufGen)
845 return inBufGen->mBufGenName;
848 int32 GetHash(BufGen *inBufGen)
850 return inBufGen->mHash;
853 bool AddBufGen(BufGen* inBufGen)
855 return gBufGenLib->Add(inBufGen);
858 bool RemoveBufGen(BufGen* inBufGen)
860 return gBufGenLib->Remove(inBufGen);
863 BufGen* GetBufGen(int32* inKey)
865 return gBufGenLib->Get(inKey);
868 ////////////////////////////////////////////////////////////////////////////////
870 int32 *GetKey(PlugInCmd *inPlugInCmd)
872 return inPlugInCmd->mCmdName;
875 int32 GetHash(PlugInCmd *inPlugInCmd)
877 return inPlugInCmd->mHash;
880 bool AddPlugInCmd(PlugInCmd* inPlugInCmd)
882 return gPlugInCmds->Add(inPlugInCmd);
885 bool RemovePlugInCmd(PlugInCmd* inPlugInCmd)
887 return gPlugInCmds->Remove(inPlugInCmd);
890 PlugInCmd* GetPlugInCmd(int32* inKey)
892 return gPlugInCmds->Get(inKey);
895 ////////////////////////////////////////////////////////////////////////////////
897 int32 GetKey(Node *inNode)
899 return inNode->mID;
902 int32 GetHash(Node *inNode)
904 return inNode->mHash;
907 bool World_AddNode(World *inWorld, Node* inNode)
909 return inWorld->hw->mNodeLib->Add(inNode);
912 bool World_RemoveNode(World *inWorld, Node* inNode)
914 return inWorld->hw->mNodeLib->Remove(inNode);
917 Node* World_GetNode(World *inWorld, int32 inID)
919 if (inID == -1) inID = inWorld->hw->mRecentID;
920 return inWorld->hw->mNodeLib->Get(inID);
923 Graph* World_GetGraph(World *inWorld, int32 inID)
925 if (inID == -1) inID = inWorld->hw->mRecentID;
926 Node *node = World_GetNode(inWorld, inID);
927 if (!node) return 0;
928 return node->mIsGroup ? 0 : (Graph*)node;
931 Group* World_GetGroup(World *inWorld, int32 inID)
933 Node *node = World_GetNode(inWorld, inID);
934 if (!node) return 0;
935 return node->mIsGroup ? (Group*)node : 0;
938 ////////////////////////////////////////////////////////////////////////////////
940 void World_Run(World *inWorld)
942 // run top group
943 Node *node = (Node*)inWorld->mTopGroup;
944 (*node->mCalcFunc)(node);
947 void World_Start(World *inWorld)
949 inWorld->mBufCounter = 0;
950 for (uint32 i=0; i<inWorld->mNumAudioBusChannels; ++i) inWorld->mAudioBusTouched[i] = -1;
951 for (uint32 i=0; i<inWorld->mNumControlBusChannels; ++i) inWorld->mControlBusTouched[i] = -1;
953 inWorld->hw->mWireBufSpace = (float*)malloc(inWorld->hw->mMaxWireBufs * inWorld->mBufLength * sizeof(float));
955 inWorld->hw->mTriggers.MakeEmpty();
956 inWorld->hw->mNodeMsgs.MakeEmpty();
957 inWorld->hw->mNodeEnds.MakeEmpty();
958 inWorld->mRunning = true;
961 SC_DLLEXPORT_C void World_Cleanup(World *world)
963 if (!world) return;
965 HiddenWorld *hw = world->hw;
967 if (hw && world->mRealTime) hw->mAudioDriver->Stop();
969 world->mRunning = false;
971 if (world->mTopGroup) Group_DeleteAll(world->mTopGroup);
973 world->mDriverLock->Lock(); // never unlock..
974 if (hw) {
975 free(hw->mWireBufSpace);
976 delete hw->mAudioDriver;
977 hw->mAudioDriver = 0;
979 delete world->mNRTLock;
980 delete world->mDriverLock;
981 World_Free(world, world->mTopGroup);
983 for (uint32 i=0; i<world->mNumSndBufs; ++i) {
984 SndBuf *nrtbuf = world->mSndBufsNonRealTimeMirror + i;
985 SndBuf * rtbuf = world->mSndBufs + i;
987 if (nrtbuf->data) free(nrtbuf->data);
988 if (rtbuf->data && rtbuf->data != nrtbuf->data) free(rtbuf->data);
990 #ifndef NO_LIBSNDFILE
991 if (nrtbuf->sndfile) sf_close(nrtbuf->sndfile);
992 if (rtbuf->sndfile && rtbuf->sndfile != nrtbuf->sndfile) sf_close(rtbuf->sndfile);
993 #endif
996 free(world->mSndBufsNonRealTimeMirror);
997 free(world->mSndBufs);
999 free(world->mControlBusTouched);
1000 free(world->mAudioBusTouched);
1001 if (hw->mShmem) {
1002 delete hw->mShmem;
1003 } else
1004 free(world->mControlBus);
1005 free(world->mAudioBus);
1006 delete [] world->mRGen;
1007 if (hw) {
1009 #ifndef NO_LIBSNDFILE
1010 if (hw->mNRTInputFile) sf_close(hw->mNRTInputFile);
1011 if (hw->mNRTOutputFile) sf_close(hw->mNRTOutputFile);
1012 if (hw->mNRTCmdFile) fclose(hw->mNRTCmdFile);
1013 #endif
1014 free(hw->mUsers);
1015 delete hw->mNodeLib;
1016 delete hw->mGraphDefLib;
1017 delete hw->mQuitProgram;
1018 delete hw->mAllocPool;
1019 free(hw);
1021 free(world);
1025 void World_NRTLock(World *world)
1027 world->mNRTLock->Lock();
1030 void World_NRTUnlock(World *world)
1032 world->mNRTLock->Unlock();
1035 ////////////////////////////////////////////////////////////////////////////////
1037 bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd)
1039 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1041 scope_buffer_writer writer = shm->get_scope_buffer_writer( index, channels, maxFrames );
1043 if( writer.valid() ) {
1044 hnd.internalData = writer.buffer;
1045 hnd.data = writer.data();
1046 hnd.channels = channels;
1047 hnd.maxFrames = maxFrames;
1048 return true;
1050 else {
1051 hnd.internalData = 0;
1052 return false;
1056 void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames)
1058 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1059 writer.push(frames);
1060 hnd.data = writer.data();
1063 void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd)
1065 scope_buffer_writer writer(reinterpret_cast<scope_buffer*>(hnd.internalData));
1066 server_shared_memory_creator * shm = inWorld->hw->mShmem;
1067 shm->release_scope_buffer_writer( writer );
1070 ////////////////////////////////////////////////////////////////////////////////
1073 inline int32 BUFMASK(int32 x)
1075 return (1 << (31 - CLZ(x))) - 1;
1078 SCErr bufAlloc(SndBuf* buf, int numChannels, int numFrames, double sampleRate)
1080 long numSamples = numFrames * numChannels;
1081 if(numSamples < 1) return kSCErr_Failed;
1082 buf->data = (float*)zalloc(numSamples, sizeof(float));
1083 if (!buf->data) return kSCErr_Failed;
1085 buf->channels = numChannels;
1086 buf->frames = numFrames;
1087 buf->samples = numSamples;
1088 buf->mask = BUFMASK(numSamples); // for delay lines
1089 buf->mask1 = buf->mask - 1; // for oscillators
1090 buf->samplerate = sampleRate;
1091 buf->sampledur = 1. / sampleRate;
1093 return kSCErr_None;
1096 #include "scsynthsend.h"
1098 void TriggerMsg::Perform()
1100 small_scpacket packet;
1101 packet.adds("/tr");
1102 packet.maketags(4);
1103 packet.addtag(',');
1104 packet.addtag('i');
1105 packet.addtag('i');
1106 packet.addtag('f');
1107 packet.addi(mNodeID);
1108 packet.addi(mTriggerID);
1109 packet.addf(mValue);
1111 ReplyAddress *users = mWorld->hw->mUsers;
1112 int numUsers = mWorld->hw->mNumUsers;
1113 for (int i=0; i<numUsers; ++i) {
1114 SendReply(users+i, packet.data(), packet.size());
1118 static void NodeReplyMsg_RTFree(FifoMsg* msg)
1120 //scprintf("NodeReplyMsg_RTFree()\n");
1121 World_Free(msg->mWorld, msg->mData);
1124 void NodeReplyMsg::Perform()
1126 small_scpacket packet;
1127 packet.adds(mCmdName, mCmdNameSize);
1128 packet.maketags(3 + mNumArgs);
1129 packet.addtag(',');
1130 packet.addtag('i');
1131 packet.addi(mNodeID);
1132 packet.addtag('i');
1133 packet.addi(mID);
1134 for(int i=0; i<mNumArgs; ++i) {
1135 packet.addtag('f');
1136 packet.addf(mValues[i]);
1139 ReplyAddress *users = mWorld->hw->mUsers;
1140 int numUsers = mWorld->hw->mNumUsers;
1141 for (int i=0; i<numUsers; ++i) {
1142 SendReply(users+i, packet.data(), packet.size());
1145 // Free memory in realtime thread
1146 FifoMsg msg;
1147 msg.Set(mWorld, NodeReplyMsg_RTFree, 0, mRTMemory);
1148 AudioDriver(mWorld)->SendMsgToEngine(msg);
1152 void NodeEndMsg::Perform()
1154 small_scpacket packet;
1155 switch (mState) {
1156 case kNode_Go :
1157 packet.adds("/n_go");
1158 break;
1159 case kNode_End :
1160 packet.adds("/n_end");
1161 break;
1162 case kNode_On :
1163 packet.adds("/n_on");
1164 break;
1165 case kNode_Off :
1166 packet.adds("/n_off");
1167 break;
1168 case kNode_Move :
1169 packet.adds("/n_move");
1170 break;
1171 case kNode_Info :
1172 packet.adds("/n_info");
1173 break;
1175 if (mIsGroup) {
1176 packet.maketags(8);
1177 packet.addtag(',');
1178 packet.addtag('i');
1179 packet.addtag('i');
1180 packet.addtag('i');
1181 packet.addtag('i');
1182 packet.addtag('i');
1183 packet.addtag('i');
1184 packet.addtag('i');
1185 packet.addi(mNodeID);
1186 packet.addi(mGroupID);
1187 packet.addi(mPrevNodeID);
1188 packet.addi(mNextNodeID);
1189 packet.addi(mIsGroup);
1190 packet.addi(mHeadID);
1191 packet.addi(mTailID);
1192 } else {
1193 packet.maketags(6);
1194 packet.addtag(',');
1195 packet.addtag('i');
1196 packet.addtag('i');
1197 packet.addtag('i');
1198 packet.addtag('i');
1199 packet.addtag('i');
1200 packet.addi(mNodeID);
1201 packet.addi(mGroupID);
1202 packet.addi(mPrevNodeID);
1203 packet.addi(mNextNodeID);
1204 packet.addi(mIsGroup);
1207 ReplyAddress *users = mWorld->hw->mUsers;
1208 int numUsers = mWorld->hw->mNumUsers;
1209 for (int i=0; i<numUsers; ++i) {
1210 SendReply(users+i, packet.data(), packet.size());
1214 void DeleteGraphDefMsg::Perform()
1216 GraphDef_Free(mDef);
1219 void NotifyNoArgs(World *inWorld, char *inString);
1220 void NotifyNoArgs(World *inWorld, char *inString)
1222 small_scpacket packet;
1223 packet.adds(inString);
1225 ReplyAddress *users = inWorld->hw->mUsers;
1226 int numUsers = inWorld->hw->mNumUsers;
1227 for (int i=0; i<numUsers; ++i) {
1228 SendReply(users+i, packet.data(), packet.size());
1233 bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg)
1235 return inWorld->hw->mAudioDriver->SendMsgToEngine(inMsg);
1238 bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg)
1240 return inWorld->hw->mAudioDriver->SendMsgFromEngine(inMsg);
1243 SC_DLLEXPORT_C void SetPrintFunc(PrintFunc func)
1245 gPrint = func;
1249 SC_DLLEXPORT_C int scprintf(const char *fmt, ...)
1251 va_list vargs;
1252 va_start(vargs, fmt);
1254 if (gPrint) return (*gPrint)(fmt, vargs);
1255 else return vprintf(fmt, vargs);