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 #include "../supernova/utilities/malloc_aligned.hpp"
48 // undefine the shadowed scfft functions
54 #if (_POSIX_MEMLOCK - 0) >= 200112L
55 # include <sys/resource.h>
56 # include <sys/mman.h>
59 #include "server_shm.hpp"
62 InterfaceTable gInterfaceTable
;
65 extern HashTable
<struct UnitDef
, Malloc
> *gUnitDefLib
;
66 extern HashTable
<struct BufGen
, Malloc
> *gBufGenLib
;
67 extern HashTable
<PlugInCmd
, Malloc
> *gPlugInCmds
;
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
);
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
);
114 inline void* sc_zalloc(size_t n
, size_t size
)
118 void* ptr
= sc_malloc(size
);
120 memset(ptr
, 0, size
);
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
);
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__)
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
)
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
;
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
;
200 ft
->fSndFileFormatInfoFromStrings
= NULL
;
202 ft
->fSndFileFormatInfoFromStrings
= &sndfileFormatInfoFromStrings
;
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
)
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()) {
241 char *path
= const_cast<char *>(sp
.NextToken());
242 list
= GraphDef_LoadDir(world
, path
, list
);
243 GraphDef_Define(world
, list
);
246 char resourceDir
[MAXPATHLEN
];
247 if(sc_IsStandAlone())
248 sc_GetResourceDirectory(resourceDir
, MAXPATHLEN
);
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;
269 int failure
= getrlimit(RLIMIT_MEMLOCK
, &limit
);
271 scprintf("getrlimit failure\n");
274 if (limit
.rlim_cur
== RLIM_INFINITY
and
275 limit
.rlim_max
== RLIM_INFINITY
)
278 scprintf("memory locking disabled due to resource limiting\n");
282 if (mlockall(MCL_FUTURE
) != -1)
283 scprintf("memory locking enabled.\n");
292 static bool gLibInitted
= false;
294 InterfaceTable_Init();
295 initialize_library(inOptions
->mUGensPluginPath
);
296 initializeScheduler();
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
));
315 hw
->mMaxUsers
= inOptions
->mMaxLogins
;
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();
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
));
362 int err
= Group_New(world
, 0, &world
->mTopGroup
);
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;
382 world
->hw
->mPassword
[0] = 0;
386 world
->hw
->mInputStreamsEnabled
= inOptions
->mInputStreamsEnabled
;
387 world
->hw
->mOutputStreamsEnabled
= inOptions
->mOutputStreamsEnabled
;
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");
420 if (!hw
->mAudioDriver
->Start()) {
421 scprintf("start audio failed.\n");
425 hw
->mAudioDriver
= 0;
427 } catch (std::exception
& exc
) {
428 scprintf("Exception in World_New: %s\n", exc
.what());
429 World_Cleanup(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
)
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
;
469 outBuf
->channels
= 0;
476 outBuf
->samplerate
= buf
->samplerate
;
477 outBuf
->sampledur
= buf
->sampledur
;
478 outBuf
->coord
= buf
->coord
;
481 updates
->reads
= updates
->writes
;
483 world
->mNRTLock
->Unlock();
486 if (outDidChange
) *outDidChange
= didChange
;
491 bool nextOSCPacket(FILE *file
, OSC_Packet
*packet
, int64
& outTime
)
494 if (fread(&msglen
, 1, sizeof(int32
), file
) != sizeof(int32
))
496 // msglen is in network byte order
497 msglen
= OSCint((char*)&msglen
);
499 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
501 size_t read
= fread(packet
->mData
, 1, msglen
, file
);
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);
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");
567 world
->hw
->mNRTInputFile
= 0;
571 if (inOptions
->mNonRealTimeCmdFilename
) {
573 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "rb");
575 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "r");
577 } else cmdFile
= stdin
;
579 throw std::runtime_error("Couldn't open non real time command file.\n");
583 memset(&packet
, 0, sizeof(packet
));
584 packet
.mData
= msgbuf
;
585 packet
.mIsBundle
= true;
586 packet
.mReplyAddr
.mReplyFunc
= null_reply_func
;
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
);
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
);
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
;
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
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");
664 prevTime
= schedTime
;
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
;
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
++;
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
)
713 inWorld
->hw
->mQuitProgram
->Acquire();
714 World_Cleanup(inWorld
);
715 } catch (std::exception
& exc
) {
716 scprintf("Exception in World_WaitForQuit: %s\n", exc
.what());
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
);
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
)
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
);
917 return node
->mIsGroup
? 0 : (Graph
*)node
;
920 Group
* World_GetGroup(World
*inWorld
, int32 inID
)
922 Node
*node
= World_GetNode(inWorld
, inID
);
924 return node
->mIsGroup
? (Group
*)node
: 0;
927 ////////////////////////////////////////////////////////////////////////////////
929 void World_Run(World
*inWorld
)
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
)
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..
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
);
985 free(world
->mSndBufsNonRealTimeMirror
);
986 free(world
->mSndBufs
);
988 free(world
->mControlBusTouched
);
989 free(world
->mAudioBusTouched
);
993 free(world
->mControlBus
);
994 free(world
->mAudioBus
);
995 delete [] world
->mRGen
;
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
);
1004 delete hw
->mNodeLib
;
1005 delete hw
->mGraphDefLib
;
1006 delete hw
->mQuitProgram
;
1007 delete hw
->mAllocPool
;
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
;
1040 hnd
.internalData
= 0;
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
;
1085 #include "scsynthsend.h"
1087 void TriggerMsg::Perform()
1089 small_scpacket packet
;
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
);
1120 packet
.addi(mNodeID
);
1123 for(int i
=0; i
<mNumArgs
; ++i
) {
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
1136 msg
.Set(mWorld
, NodeReplyMsg_RTFree
, 0, mRTMemory
);
1137 AudioDriver(mWorld
)->SendMsgToEngine(msg
);
1141 void NodeEndMsg::Perform()
1143 small_scpacket packet
;
1146 packet
.adds("/n_go");
1149 packet
.adds("/n_end");
1152 packet
.adds("/n_on");
1155 packet
.adds("/n_off");
1158 packet
.adds("/n_move");
1161 packet
.adds("/n_info");
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
);
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
)
1238 SC_DLLEXPORT_C
int scprintf(const char *fmt
, ...)
1241 va_start(vargs
, fmt
);
1243 if (gPrint
) return (*gPrint
)(fmt
, vargs
);
1244 else return vprintf(fmt
, vargs
);