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
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"
31 #include "SC_CoreAudio.h"
33 #include "SC_Errors.h"
35 #include "SC_Prototypes.h"
37 #include "SC_DirUtils.h"
38 #include "../../common/SC_SndFileHelpers.hpp"
39 #include "SC_StringParser.h"
43 # include <sys/param.h>
46 // undefine the shadowed scfft functions
52 #if (_POSIX_MEMLOCK - 0) >= 200112L
53 # include <sys/resource.h>
54 # include <sys/mman.h>
57 #include "server_shm.hpp"
60 InterfaceTable gInterfaceTable
;
63 extern HashTable
<struct UnitDef
, Malloc
> *gUnitDefLib
;
64 extern HashTable
<struct BufGen
, Malloc
> *gBufGenLib
;
65 extern HashTable
<PlugInCmd
, Malloc
> *gPlugInCmds
;
73 bool SendMsgToEngine(World
*inWorld
, FifoMsg
& inMsg
);
74 bool SendMsgFromEngine(World
*inWorld
, FifoMsg
& inMsg
);
77 bool sc_UseVectorUnit();
78 void sc_SetDenormalFlags();
80 ////////////////////////////////////////////////////////////////////////////////
85 #define _XOPEN_SOURCE 600
90 #ifndef SC_MEMORY_ALIGNMENT
91 # error SC_MEMORY_ALIGNMENT undefined
93 #define SC_DBUG_MEMORY 0
95 inline void* sc_malloc(size_t size
)
97 #if SC_MEMORY_ALIGNMENT > 1
99 int err
= posix_memalign(&ptr
, SC_MEMORY_ALIGNMENT
, size
);
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
);
127 inline void sc_free(void* 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
);
138 inline void* sc_zalloc(size_t n
, size_t size
)
142 void* ptr
= sc_malloc(size
);
144 memset(ptr
, 0, size
);
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
);
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__)
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
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
;
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
;
215 ft
->fSndFileFormatInfoFromStrings
= NULL
;
217 ft
->fSndFileFormatInfoFromStrings
= &sndfileFormatInfoFromStrings
;
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
)
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()) {
256 char *path
= const_cast<char *>(sp
.NextToken());
257 list
= GraphDef_LoadDir(world
, path
, list
);
258 GraphDef_Define(world
, list
);
261 char resourceDir
[MAXPATHLEN
];
262 if(sc_IsStandAlone())
263 sc_GetResourceDirectory(resourceDir
, MAXPATHLEN
);
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;
284 int failure
= getrlimit(RLIMIT_MEMLOCK
, &limit
);
286 scprintf("getrlimit failure\n");
289 if (limit
.rlim_cur
== RLIM_INFINITY
and
290 limit
.rlim_max
== RLIM_INFINITY
)
293 scprintf("memory locking disabled due to resource limiting\n");
297 if (mlockall(MCL_FUTURE
) != -1)
298 scprintf("memory locking enabled.\n");
307 static bool gLibInitted
= false;
309 InterfaceTable_Init();
310 initialize_library(inOptions
->mUGensPluginPath
);
311 initializeScheduler();
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
));
330 hw
->mMaxUsers
= inOptions
->mMaxLogins
;
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();
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
));
375 int err
= Group_New(world
, 0, &world
->mTopGroup
);
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;
395 world
->hw
->mPassword
[0] = 0;
399 world
->hw
->mInputStreamsEnabled
= inOptions
->mInputStreamsEnabled
;
400 world
->hw
->mOutputStreamsEnabled
= inOptions
->mOutputStreamsEnabled
;
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");
433 if (!hw
->mAudioDriver
->Start()) {
434 scprintf("start audio failed.\n");
438 hw
->mAudioDriver
= 0;
440 } catch (std::exception
& exc
) {
441 scprintf("Exception in World_New: %s\n", exc
.what());
442 World_Cleanup(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
)
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
;
482 outBuf
->channels
= 0;
489 outBuf
->samplerate
= buf
->samplerate
;
490 outBuf
->sampledur
= buf
->sampledur
;
491 outBuf
->coord
= buf
->coord
;
494 updates
->reads
= updates
->writes
;
496 world
->mNRTLock
->Unlock();
499 if (outDidChange
) *outDidChange
= didChange
;
504 bool nextOSCPacket(FILE *file
, OSC_Packet
*packet
, int64
& outTime
)
507 if (fread(&msglen
, 1, sizeof(int32
), file
) != sizeof(int32
))
509 // msglen is in network byte order
510 msglen
= OSCint((char*)&msglen
);
512 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
514 size_t read
= fread(packet
->mData
, 1, msglen
, file
);
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);
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");
578 world
->hw
->mNRTInputFile
= 0;
582 if (inOptions
->mNonRealTimeCmdFilename
) {
584 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "rb");
586 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "r");
588 } else cmdFile
= stdin
;
590 throw std::runtime_error("Couldn't open non real time command file.\n");
594 memset(&packet
, 0, sizeof(packet
));
595 packet
.mData
= msgbuf
;
596 packet
.mIsBundle
= true;
597 packet
.mReplyAddr
.mReplyFunc
= null_reply_func
;
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
);
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
);
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
;
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
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");
675 prevTime
= schedTime
;
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
;
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
++;
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
)
724 inWorld
->hw
->mQuitProgram
->Acquire();
725 World_Cleanup(inWorld
);
726 } catch (std::exception
& exc
) {
727 scprintf("Exception in World_WaitForQuit: %s\n", exc
.what());
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
);
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
)
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
);
928 return node
->mIsGroup
? 0 : (Graph
*)node
;
931 Group
* World_GetGroup(World
*inWorld
, int32 inID
)
933 Node
*node
= World_GetNode(inWorld
, inID
);
935 return node
->mIsGroup
? (Group
*)node
: 0;
938 ////////////////////////////////////////////////////////////////////////////////
940 void World_Run(World
*inWorld
)
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
)
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..
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
);
996 free(world
->mSndBufsNonRealTimeMirror
);
997 free(world
->mSndBufs
);
999 free(world
->mControlBusTouched
);
1000 free(world
->mAudioBusTouched
);
1004 free(world
->mControlBus
);
1005 free(world
->mAudioBus
);
1006 delete [] world
->mRGen
;
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
);
1015 delete hw
->mNodeLib
;
1016 delete hw
->mGraphDefLib
;
1017 delete hw
->mQuitProgram
;
1018 delete hw
->mAllocPool
;
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
;
1051 hnd
.internalData
= 0;
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
;
1096 #include "scsynthsend.h"
1098 void TriggerMsg::Perform()
1100 small_scpacket packet
;
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
);
1131 packet
.addi(mNodeID
);
1134 for(int i
=0; i
<mNumArgs
; ++i
) {
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
1147 msg
.Set(mWorld
, NodeReplyMsg_RTFree
, 0, mRTMemory
);
1148 AudioDriver(mWorld
)->SendMsgToEngine(msg
);
1152 void NodeEndMsg::Perform()
1154 small_scpacket packet
;
1157 packet
.adds("/n_go");
1160 packet
.adds("/n_end");
1163 packet
.adds("/n_on");
1166 packet
.adds("/n_off");
1169 packet
.adds("/n_move");
1172 packet
.adds("/n_info");
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
);
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
)
1249 SC_DLLEXPORT_C
int scprintf(const char *fmt
, ...)
1252 va_start(vargs
, fmt
);
1254 if (gPrint
) return (*gPrint
)(fmt
, vargs
);
1255 else return vprintf(fmt
, vargs
);