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
);
150 ////////////////////////////////////////////////////////////////////////////////
152 static bool getScopeBuffer(World
*inWorld
, int index
, int channels
, int maxFrames
, ScopeBufferHnd
&hnd
);
153 static void pushScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
, int frames
);
154 static void releaseScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
);
156 void InterfaceTable_Init()
158 InterfaceTable
*ft
= &gInterfaceTable
;
161 ft
->mCosecant
= gInvSine
;
162 ft
->mSineSize
= kSineSize
;
163 ft
->mSineWavetable
= gSineWavetable
;
165 ft
->fPrint
= &scprintf
;
167 ft
->fRanSeed
= &server_timeseed
;
169 ft
->fNodeEnd
= &Node_End
;
171 ft
->fDefineUnit
= &UnitDef_Create
;
172 ft
->fDefineBufGen
= &BufGen_Create
;
173 ft
->fClearUnitOutputs
= &Unit_ZeroOutputs
;
175 ft
->fNRTAlloc
= &malloc
;
176 ft
->fNRTRealloc
= &realloc
;
177 ft
->fNRTFree
= &free
;
179 ft
->fRTAlloc
= &World_Alloc
;
180 ft
->fRTRealloc
= &World_Realloc
;
181 ft
->fRTFree
= &World_Free
;
183 ft
->fNodeRun
= &Node_SetRun
;
185 ft
->fSendTrigger
= &Node_SendTrigger
;
186 ft
->fSendNodeReply
= &Node_SendReply
;
189 ft
->fDefineUnitCmd
= &UnitDef_AddCmd
;
190 ft
->fDefinePlugInCmd
= &PlugIn_DefineCmd
;
192 ft
->fSendMsgFromRT
= &SendMsgFromEngine
;
193 ft
->fSendMsgToRT
= &SendMsgToEngine
;
195 ft
->fSndFileFormatInfoFromStrings
= NULL
;
197 ft
->fSndFileFormatInfoFromStrings
= &sndfileFormatInfoFromStrings
;
199 ft
->fGetNode
= &World_GetNode
;
200 ft
->fGetGraph
= &World_GetGraph
;
202 ft
->fNRTLock
= &World_NRTLock
;
203 ft
->fNRTUnlock
= &World_NRTUnlock
;
205 ft
->mAltivecAvailable
= sc_UseVectorUnit();
207 ft
->fGroup_DeleteAll
= &Group_DeleteAll
;
208 ft
->fDoneAction
= &Unit_DoneAction
;
209 ft
->fDoAsynchronousCommand
= &PerformAsynchronousCommand
;
210 ft
->fBufAlloc
= &bufAlloc
;
212 ft
->fSCfftCreate
= &scfft_create
;
213 ft
->fSCfftDestroy
= &scfft_destroy
;
214 ft
->fSCfftDoFFT
= &scfft_dofft
;
215 ft
->fSCfftDoIFFT
= &scfft_doifft
;
217 ft
->fGetScopeBuffer
= &getScopeBuffer
;
218 ft
->fPushScopeBuffer
= &pushScopeBuffer
;
219 ft
->fReleaseScopeBuffer
= &releaseScopeBuffer
;
222 void initialize_library(const char *mUGensPluginPath
);
223 void initializeScheduler();
225 static void World_LoadGraphDefs(World
* world
);
226 void World_LoadGraphDefs(World
* world
)
230 if(getenv("SC_SYNTHDEF_PATH")){
231 if(world
->mVerbosity
> 0)
232 scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH"));
233 SC_StringParser
sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER
);
234 while (!sp
.AtEnd()) {
236 char *path
= const_cast<char *>(sp
.NextToken());
237 list
= GraphDef_LoadDir(world
, path
, list
);
238 GraphDef_Define(world
, list
);
241 char resourceDir
[MAXPATHLEN
];
242 if(sc_IsStandAlone())
243 sc_GetResourceDirectory(resourceDir
, MAXPATHLEN
);
245 sc_GetUserAppSupportDirectory(resourceDir
, MAXPATHLEN
);
246 sc_AppendToPath(resourceDir
, MAXPATHLEN
, "synthdefs");
247 if(world
->mVerbosity
> 0)
248 scprintf("Loading synthdefs from default path: %s\n", resourceDir
);
249 list
= GraphDef_LoadDir(world
, resourceDir
, list
);
250 GraphDef_Define(world
, list
);
255 SC_DLLEXPORT_C World
* World_New(WorldOptions
*inOptions
)
257 #if (_POSIX_MEMLOCK - 0) >= 200112L
258 if (inOptions
->mMemoryLocking
&& inOptions
->mRealTime
)
260 bool lock_memory
= false;
264 int failure
= getrlimit(RLIMIT_MEMLOCK
, &limit
);
266 scprintf("getrlimit failure\n");
269 if (limit
.rlim_cur
== RLIM_INFINITY
and
270 limit
.rlim_max
== RLIM_INFINITY
)
273 scprintf("memory locking disabled due to resource limiting\n");
277 if (mlockall(MCL_FUTURE
) != -1)
278 scprintf("memory locking enabled.\n");
287 static bool gLibInitted
= false;
289 InterfaceTable_Init();
290 initialize_library(inOptions
->mUGensPluginPath
);
291 initializeScheduler();
295 world
= (World
*)zalloc(1, sizeof(World
));
297 world
->hw
= (HiddenWorld
*)zalloc(1, sizeof(HiddenWorld
));
299 world
->hw
->mAllocPool
= new AllocPool(malloc
, free
, inOptions
->mRealTimeMemorySize
* 1024, 0);
300 world
->hw
->mQuitProgram
= new SC_Semaphore(0);
301 world
->hw
->mTerminating
= false;
303 extern Malloc gMalloc
;
305 HiddenWorld
*hw
= world
->hw
;
306 hw
->mGraphDefLib
= new HashTable
<struct GraphDef
, Malloc
>(&gMalloc
, inOptions
->mMaxGraphDefs
, false);
307 hw
->mNodeLib
= new IntHashTable
<Node
, AllocPool
>(hw
->mAllocPool
, inOptions
->mMaxNodes
, false);
308 hw
->mUsers
= (ReplyAddress
*)zalloc(inOptions
->mMaxLogins
, sizeof(ReplyAddress
));
310 hw
->mMaxUsers
= inOptions
->mMaxLogins
;
315 world
->mNumUnits
= 0;
316 world
->mNumGraphs
= 0;
317 world
->mNumGroups
= 0;
319 world
->mBufCounter
= 0;
320 world
->mBufLength
= inOptions
->mBufLength
;
321 world
->mSampleOffset
= 0;
322 world
->mSubsampleOffset
= 0.f
;
323 world
->mNumAudioBusChannels
= inOptions
->mNumAudioBusChannels
;
324 world
->mNumControlBusChannels
= inOptions
->mNumControlBusChannels
;
325 world
->mNumInputs
= inOptions
->mNumInputBusChannels
;
326 world
->mNumOutputs
= inOptions
->mNumOutputBusChannels
;
328 world
->mVerbosity
= inOptions
->mVerbosity
;
329 world
->mErrorNotification
= 1; // i.e., 0x01 | 0x02
330 world
->mLocalErrorNotification
= 0;
332 if (inOptions
->mSharedMemoryID
) {
333 server_shared_memory_creator::cleanup(inOptions
->mSharedMemoryID
);
334 hw
->mShmem
= new server_shared_memory_creator(inOptions
->mSharedMemoryID
, inOptions
->mNumControlBusChannels
);
335 world
->mControlBus
= hw
->mShmem
->get_control_busses();
338 world
->mControlBus
= (float*)zalloc(world
->mNumControlBusChannels
, sizeof(float));
341 world
->mNumSharedControls
= 0;
342 world
->mSharedControls
= inOptions
->mSharedControls
;
344 int numsamples
= world
->mBufLength
* world
->mNumAudioBusChannels
;
345 world
->mAudioBus
= (float*)zalloc(numsamples
, sizeof(float));
347 world
->mAudioBusTouched
= (int32
*)zalloc(inOptions
->mNumAudioBusChannels
, sizeof(int32
));
348 world
->mControlBusTouched
= (int32
*)zalloc(inOptions
->mNumControlBusChannels
, sizeof(int32
));
350 world
->mNumSndBufs
= inOptions
->mNumBuffers
;
351 world
->mSndBufs
= (SndBuf
*)zalloc(world
->mNumSndBufs
, sizeof(SndBuf
));
352 world
->mSndBufsNonRealTimeMirror
= (SndBuf
*)zalloc(world
->mNumSndBufs
, sizeof(SndBuf
));
353 world
->mSndBufUpdates
= (SndBufUpdates
*)zalloc(world
->mNumSndBufs
, sizeof(SndBufUpdates
));
357 int err
= Group_New(world
, 0, &world
->mTopGroup
);
360 world
->mRealTime
= inOptions
->mRealTime
;
362 world
->ft
= &gInterfaceTable
;
364 world
->mNumRGens
= inOptions
->mNumRGens
;
365 world
->mRGen
= new RGen
[world
->mNumRGens
];
366 for (uint32 i
=0; i
<world
->mNumRGens
; ++i
) {
367 world
->mRGen
[i
].init(server_timeseed());
370 world
->mNRTLock
= new SC_Lock();
371 world
->mDriverLock
= new SC_Lock();
373 if (inOptions
->mPassword
) {
374 strncpy(world
->hw
->mPassword
, inOptions
->mPassword
, 31);
375 world
->hw
->mPassword
[31] = 0;
377 world
->hw
->mPassword
[0] = 0;
381 world
->hw
->mInputStreamsEnabled
= inOptions
->mInputStreamsEnabled
;
382 world
->hw
->mOutputStreamsEnabled
= inOptions
->mOutputStreamsEnabled
;
384 world
->hw
->mInDeviceName
= inOptions
->mInDeviceName
;
385 world
->hw
->mOutDeviceName
= inOptions
->mOutDeviceName
;
386 hw
->mMaxWireBufs
= inOptions
->mMaxWireBufs
;
387 hw
->mWireBufSpace
= 0;
389 world
->mRendezvous
= inOptions
->mRendezvous
;
391 world
->mRestrictedPath
= inOptions
->mRestrictedPath
;
393 if(inOptions
->mVerbosity
>= 1) {
394 scprintf("Using vector unit: %s\n", sc_UseVectorUnit() ? "yes" : "no");
396 sc_SetDenormalFlags();
398 if (world
->mRealTime
) {
399 hw
->mAudioDriver
= SC_NewAudioDriver(world
);
400 hw
->mAudioDriver
->SetPreferredHardwareBufferFrameSize(
401 inOptions
->mPreferredHardwareBufferFrameSize
403 hw
->mAudioDriver
->SetPreferredSampleRate(
404 inOptions
->mPreferredSampleRate
407 if (inOptions
->mLoadGraphDefs
) {
408 World_LoadGraphDefs(world
);
411 if (!hw
->mAudioDriver
->Setup()) {
412 scprintf("could not initialize audio.\n");
415 if (!hw
->mAudioDriver
->Start()) {
416 scprintf("start audio failed.\n");
420 hw
->mAudioDriver
= 0;
422 } catch (std::exception
& exc
) {
423 scprintf("Exception in World_New: %s\n", exc
.what());
424 World_Cleanup(world
);
431 SC_DLLEXPORT_C
int World_CopySndBuf(World
*world
, uint32 index
, SndBuf
*outBuf
, bool onlyIfChanged
, bool *outDidChange
)
433 if (index
> world
->mNumSndBufs
) return kSCErr_IndexOutOfRange
;
435 SndBufUpdates
*updates
= world
->mSndBufUpdates
+ index
;
436 bool didChange
= updates
->reads
!= updates
->writes
;
438 if (!onlyIfChanged
|| didChange
)
441 world
->mNRTLock
->Lock();
443 SndBuf
*buf
= world
->mSndBufsNonRealTimeMirror
+ index
;
445 if (buf
->data
&& buf
->samples
)
447 uint32 bufSize
= buf
->samples
* sizeof(float);
448 if (buf
->samples
!= outBuf
->samples
)
451 outBuf
->data
= (float*)malloc(bufSize
);
453 memcpy(outBuf
->data
, buf
->data
, bufSize
);
454 outBuf
->channels
= buf
->channels
;
455 outBuf
->samples
= buf
->samples
;
456 outBuf
->frames
= buf
->frames
;
457 outBuf
->mask
= buf
->mask
;
458 outBuf
->mask1
= buf
->mask1
;
464 outBuf
->channels
= 0;
471 outBuf
->samplerate
= buf
->samplerate
;
472 outBuf
->sampledur
= buf
->sampledur
;
473 outBuf
->coord
= buf
->coord
;
476 updates
->reads
= updates
->writes
;
478 world
->mNRTLock
->Unlock();
481 if (outDidChange
) *outDidChange
= didChange
;
486 bool nextOSCPacket(FILE *file
, OSC_Packet
*packet
, int64
& outTime
)
489 if (fread(&msglen
, 1, sizeof(int32
), file
) != sizeof(int32
))
491 // msglen is in network byte order
492 msglen
= OSCint((char*)&msglen
);
494 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
496 size_t read
= fread(packet
->mData
, 1, msglen
, file
);
498 throw std::runtime_error("nextOSCPacket: invalid read of OSC packaet\n");
500 if (strcmp(packet
->mData
, "#bundle")!=0)
501 throw std::runtime_error("OSC packet not a bundle\n");
503 packet
->mSize
= msglen
;
505 outTime
= OSCtime(packet
->mData
+8);
509 void PerformOSCBundle(World
*inWorld
, OSC_Packet
*inPacket
);
511 #ifndef NO_LIBSNDFILE
512 SC_DLLEXPORT_C
void World_NonRealTimeSynthesis(struct World
*world
, WorldOptions
*inOptions
)
514 if (inOptions
->mLoadGraphDefs
) {
515 World_LoadGraphDefs(world
);
517 int bufLength
= world
->mBufLength
;
518 int fileBufFrames
= inOptions
->mPreferredHardwareBufferFrameSize
;
519 if (fileBufFrames
<= 0) fileBufFrames
= 8192;
520 int bufMultiple
= (fileBufFrames
+ bufLength
- 1) / bufLength
;
521 fileBufFrames
= bufMultiple
* bufLength
;
523 // batch process non real time audio
524 if (!inOptions
->mNonRealTimeOutputFilename
)
525 throw std::runtime_error("Non real time output filename is NULL.\n");
527 SF_INFO inputFileInfo
, outputFileInfo
;
528 float *inputFileBuf
= 0;
529 float *outputFileBuf
= 0;
530 int numInputChannels
= 0;
531 int numOutputChannels
;
533 outputFileInfo
.samplerate
= inOptions
->mPreferredSampleRate
;
534 numOutputChannels
= outputFileInfo
.channels
= world
->mNumOutputs
;
535 sndfileFormatInfoFromStrings(&outputFileInfo
,
536 inOptions
->mNonRealTimeOutputHeaderFormat
, inOptions
->mNonRealTimeOutputSampleFormat
);
538 world
->hw
->mNRTOutputFile
= sf_open(inOptions
->mNonRealTimeOutputFilename
, SFM_WRITE
, &outputFileInfo
);
539 if (!world
->hw
->mNRTOutputFile
)
540 throw std::runtime_error("Couldn't open non real time output file.\n");
542 outputFileBuf
= (float*)calloc(1, world
->mNumOutputs
* fileBufFrames
* sizeof(float));
544 if (inOptions
->mNonRealTimeInputFilename
) {
545 world
->hw
->mNRTInputFile
= sf_open(inOptions
->mNonRealTimeInputFilename
, SFM_READ
, &inputFileInfo
);
546 if (!world
->hw
->mNRTInputFile
)
547 throw std::runtime_error("Couldn't open non real time input file.\n");
549 inputFileBuf
= (float*)calloc(1, inputFileInfo
.channels
* fileBufFrames
* sizeof(float));
551 if (world
->mNumInputs
!= (uint32
)inputFileInfo
.channels
)
552 scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");
554 numInputChannels
= world
->mNumInputs
= inputFileInfo
.channels
; // force it.
556 if (inputFileInfo
.samplerate
!= (int)inOptions
->mPreferredSampleRate
)
557 scprintf("WARNING: input file sample rate does not equal output sample rate.\n");
560 world
->hw
->mNRTInputFile
= 0;
564 if (inOptions
->mNonRealTimeCmdFilename
) {
566 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "rb");
568 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "r");
570 } else cmdFile
= stdin
;
572 throw std::runtime_error("Couldn't open non real time command file.\n");
576 memset(&packet
, 0, sizeof(packet
));
577 packet
.mData
= msgbuf
;
578 packet
.mIsBundle
= true;
579 packet
.mReplyAddr
.mReplyFunc
= null_reply_func
;
582 if (nextOSCPacket(cmdFile
, &packet
, schedTime
))
583 throw std::runtime_error("command file empty.\n");
584 int64 prevTime
= schedTime
;
586 World_SetSampleRate(world
, inOptions
->mPreferredSampleRate
);
590 double oscToSeconds
= 1. / pow(2.,32.);
591 double oscToSamples
= inOptions
->mPreferredSampleRate
* oscToSeconds
;
592 int64 oscInc
= (int64
)((double)bufLength
/ oscToSamples
);
594 if(inOptions
->mVerbosity
>= 0) {
595 printf("start time %g\n", schedTime
* oscToSeconds
);
599 int inBufStep
= numInputChannels
* bufLength
;
600 int outBufStep
= numOutputChannels
* bufLength
;
601 float* inputBuses
= world
->mAudioBus
+ world
->mNumOutputs
* bufLength
;
602 float* outputBuses
= world
->mAudioBus
;
603 int32
* inputTouched
= world
->mAudioBusTouched
+ world
->mNumOutputs
;
604 int32
* outputTouched
= world
->mAudioBusTouched
;
606 int bufFramesCalculated
= 0;
607 float* inBufPos
= inputFileBuf
;
608 float* outBufPos
= outputFileBuf
;
610 if (world
->hw
->mNRTInputFile
) {
611 int framesRead
= sf_readf_float(world
->hw
->mNRTInputFile
, inputFileBuf
, fileBufFrames
);
612 if (framesRead
< fileBufFrames
) {
613 memset(inputFileBuf
+ framesRead
* numInputChannels
, 0,
614 (fileBufFrames
- framesRead
) * numInputChannels
* sizeof(float));
618 for (int i
=0; i
<bufMultiple
&& run
; ++i
) {
619 int bufCounter
= world
->mBufCounter
;
621 // deinterleave input to input buses
623 float *inBus
= inputBuses
;
624 for (int j
=0; j
<numInputChannels
; ++j
, inBus
+= bufLength
) {
625 float *inFileBufPtr
= inBufPos
+ j
;
626 for (int k
=0; k
<bufLength
; ++k
) {
627 inBus
[k
] = *inFileBufPtr
;
628 inFileBufPtr
+= numInputChannels
;
630 inputTouched
[j
] = bufCounter
;
634 // execute ready commands
635 int64 nextTime
= oscTime
+ oscInc
;
637 while (schedTime
<= nextTime
) {
638 float diffTime
= (float)(schedTime
- oscTime
) * oscToSamples
+ 0.5;
639 float diffTimeFloor
= floor(diffTime
);
640 world
->mSampleOffset
= (int)diffTimeFloor
;
641 world
->mSubsampleOffset
= diffTime
- diffTimeFloor
;
643 if (world
->mSampleOffset
< 0) world
->mSampleOffset
= 0;
644 else if (world
->mSampleOffset
>= bufLength
) world
->mSampleOffset
= bufLength
-1;
647 PerformOSCBundle(world
, &packet
);
648 if (nextOSCPacket(cmdFile
, &packet
, schedTime
)) { run
= false; break; }
649 if(inOptions
->mVerbosity
>= 0) {
650 printf("nextOSCPacket %g\n", schedTime
* oscToSeconds
);
652 if (schedTime
< prevTime
) {
653 scprintf("ERROR: Packet time stamps out-of-order.\n");
657 prevTime
= schedTime
;
662 // interleave output to output buffer
663 float *outBus
= outputBuses
;
664 for (int j
=0; j
<numOutputChannels
; ++j
, outBus
+= bufLength
) {
665 float *outFileBufPtr
= outBufPos
+ j
;
666 if (outputTouched
[j
] == bufCounter
) {
667 for (int k
=0; k
<bufLength
; ++k
) {
668 *outFileBufPtr
= outBus
[k
];
669 outFileBufPtr
+= numOutputChannels
;
672 for (int k
=0; k
<bufLength
; ++k
) {
673 *outFileBufPtr
= 0.f
;
674 outFileBufPtr
+= numOutputChannels
;
678 bufFramesCalculated
+= bufLength
;
679 inBufPos
+= inBufStep
;
680 outBufPos
+= outBufStep
;
681 world
->mBufCounter
++;
687 sf_writef_float(world
->hw
->mNRTOutputFile
, outputFileBuf
, bufFramesCalculated
);
690 if (cmdFile
!= stdin
) fclose(cmdFile
);
691 sf_close(world
->hw
->mNRTOutputFile
);
692 world
->hw
->mNRTOutputFile
= 0;
694 if (world
->hw
->mNRTInputFile
) {
695 sf_close(world
->hw
->mNRTInputFile
);
696 world
->hw
->mNRTInputFile
= 0;
699 World_Cleanup(world
);
701 #endif // !NO_LIBSNDFILE
703 SC_DLLEXPORT_C
void World_WaitForQuit(struct World
*inWorld
)
706 inWorld
->hw
->mQuitProgram
->Acquire();
707 World_Cleanup(inWorld
);
708 } catch (std::exception
& exc
) {
709 scprintf("Exception in World_WaitForQuit: %s\n", exc
.what());
714 void World_SetSampleRate(World
*inWorld
, double inSampleRate
)
716 inWorld
->mSampleRate
= inSampleRate
;
717 Rate_Init(&inWorld
->mFullRate
, inSampleRate
, inWorld
->mBufLength
);
718 Rate_Init(&inWorld
->mBufRate
, inSampleRate
/ inWorld
->mBufLength
, 1);
721 ////////////////////////////////////////////////////////////////////////////////
723 void* World_Alloc(World
*inWorld
, size_t inByteSize
)
725 return inWorld
->hw
->mAllocPool
->Alloc(inByteSize
);
728 void* World_Realloc(World
*inWorld
, void *inPtr
, size_t inByteSize
)
730 return inWorld
->hw
->mAllocPool
->Realloc(inPtr
, inByteSize
);
733 size_t World_TotalFree(World
*inWorld
)
735 return inWorld
->hw
->mAllocPool
->TotalFree();
738 size_t World_LargestFreeChunk(World
*inWorld
)
740 return inWorld
->hw
->mAllocPool
->LargestFreeChunk();
743 void World_Free(World
*inWorld
, void *inPtr
)
745 inWorld
->hw
->mAllocPool
->Free(inPtr
);
748 ////////////////////////////////////////////////////////////////////////////////
750 int32
*GetKey(GraphDef
*inGraphDef
)
752 return inGraphDef
->mNodeDef
.mName
;
755 int32
GetHash(GraphDef
*inGraphDef
)
757 return inGraphDef
->mNodeDef
.mHash
;
760 void World_AddGraphDef(World
*inWorld
, GraphDef
* inGraphDef
)
762 bool added
= inWorld
->hw
->mGraphDefLib
->Add(inGraphDef
);
763 if(!added
) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef
->mNodeDef
.mName
);
764 for (uint32 i
=0; i
<inGraphDef
->mNumVariants
; ++i
) {
765 GraphDef
* var
= inGraphDef
->mVariants
+ i
;
766 added
= inWorld
->hw
->mGraphDefLib
->Add(var
);
767 if(!added
) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var
->mNodeDef
.mName
);
771 void World_RemoveGraphDef(World
*inWorld
, GraphDef
* inGraphDef
)
773 for (uint32 i
=0; i
<inGraphDef
->mNumVariants
; ++i
) {
774 GraphDef
* var
= inGraphDef
->mVariants
+ i
;
775 inWorld
->hw
->mGraphDefLib
->Remove(var
);
777 inWorld
->hw
->mGraphDefLib
->Remove(inGraphDef
);
780 void World_FreeAllGraphDefs(World
*inWorld
)
782 GrafDefTable
* lib
= inWorld
->hw
->mGraphDefLib
;
783 int size
= lib
->TableSize();
784 for (int i
=0; i
<size
; ++i
) {
785 GraphDef
*def
= lib
->AtIndex(i
);
786 if (def
) GraphDef_Free(def
);
791 GraphDef
* World_GetGraphDef(World
*inWorld
, int32
* inKey
)
793 return inWorld
->hw
->mGraphDefLib
->Get(inKey
);
796 ////////////////////////////////////////////////////////////////////////////////
798 int32
*GetKey(UnitDef
*inUnitDef
)
800 return inUnitDef
->mUnitDefName
;
803 int32
GetHash(UnitDef
*inUnitDef
)
805 return inUnitDef
->mHash
;
808 bool AddUnitDef(UnitDef
* inUnitDef
)
810 return gUnitDefLib
->Add(inUnitDef
);
813 bool RemoveUnitDef(UnitDef
* inUnitDef
)
815 return gUnitDefLib
->Remove(inUnitDef
);
818 UnitDef
* GetUnitDef(int32
* inKey
)
820 return gUnitDefLib
->Get(inKey
);
823 ////////////////////////////////////////////////////////////////////////////////
825 int32
*GetKey(BufGen
*inBufGen
)
827 return inBufGen
->mBufGenName
;
830 int32
GetHash(BufGen
*inBufGen
)
832 return inBufGen
->mHash
;
835 bool AddBufGen(BufGen
* inBufGen
)
837 return gBufGenLib
->Add(inBufGen
);
840 bool RemoveBufGen(BufGen
* inBufGen
)
842 return gBufGenLib
->Remove(inBufGen
);
845 BufGen
* GetBufGen(int32
* inKey
)
847 return gBufGenLib
->Get(inKey
);
850 ////////////////////////////////////////////////////////////////////////////////
852 int32
*GetKey(PlugInCmd
*inPlugInCmd
)
854 return inPlugInCmd
->mCmdName
;
857 int32
GetHash(PlugInCmd
*inPlugInCmd
)
859 return inPlugInCmd
->mHash
;
862 bool AddPlugInCmd(PlugInCmd
* inPlugInCmd
)
864 return gPlugInCmds
->Add(inPlugInCmd
);
867 bool RemovePlugInCmd(PlugInCmd
* inPlugInCmd
)
869 return gPlugInCmds
->Remove(inPlugInCmd
);
872 PlugInCmd
* GetPlugInCmd(int32
* inKey
)
874 return gPlugInCmds
->Get(inKey
);
877 ////////////////////////////////////////////////////////////////////////////////
879 int32
GetKey(Node
*inNode
)
884 int32
GetHash(Node
*inNode
)
886 return inNode
->mHash
;
889 bool World_AddNode(World
*inWorld
, Node
* inNode
)
891 return inWorld
->hw
->mNodeLib
->Add(inNode
);
894 bool World_RemoveNode(World
*inWorld
, Node
* inNode
)
896 return inWorld
->hw
->mNodeLib
->Remove(inNode
);
899 Node
* World_GetNode(World
*inWorld
, int32 inID
)
901 if (inID
== -1) inID
= inWorld
->hw
->mRecentID
;
902 return inWorld
->hw
->mNodeLib
->Get(inID
);
905 Graph
* World_GetGraph(World
*inWorld
, int32 inID
)
907 if (inID
== -1) inID
= inWorld
->hw
->mRecentID
;
908 Node
*node
= World_GetNode(inWorld
, inID
);
910 return node
->mIsGroup
? 0 : (Graph
*)node
;
913 Group
* World_GetGroup(World
*inWorld
, int32 inID
)
915 Node
*node
= World_GetNode(inWorld
, inID
);
917 return node
->mIsGroup
? (Group
*)node
: 0;
920 ////////////////////////////////////////////////////////////////////////////////
922 void World_Run(World
*inWorld
)
925 Node
*node
= (Node
*)inWorld
->mTopGroup
;
926 (*node
->mCalcFunc
)(node
);
929 void World_Start(World
*inWorld
)
931 inWorld
->mBufCounter
= 0;
932 for (uint32 i
=0; i
<inWorld
->mNumAudioBusChannels
; ++i
) inWorld
->mAudioBusTouched
[i
] = -1;
933 for (uint32 i
=0; i
<inWorld
->mNumControlBusChannels
; ++i
) inWorld
->mControlBusTouched
[i
] = -1;
935 inWorld
->hw
->mWireBufSpace
= (float*)malloc(inWorld
->hw
->mMaxWireBufs
* inWorld
->mBufLength
* sizeof(float));
937 inWorld
->hw
->mTriggers
.MakeEmpty();
938 inWorld
->hw
->mNodeMsgs
.MakeEmpty();
939 inWorld
->hw
->mNodeEnds
.MakeEmpty();
940 inWorld
->mRunning
= true;
943 SC_DLLEXPORT_C
void World_Cleanup(World
*world
)
947 HiddenWorld
*hw
= world
->hw
;
949 if (hw
&& world
->mRealTime
) hw
->mAudioDriver
->Stop();
951 world
->mRunning
= false;
953 if (world
->mTopGroup
) Group_DeleteAll(world
->mTopGroup
);
955 world
->mDriverLock
->Lock(); // never unlock..
957 free(hw
->mWireBufSpace
);
958 delete hw
->mAudioDriver
;
959 hw
->mAudioDriver
= 0;
961 delete world
->mNRTLock
;
962 delete world
->mDriverLock
;
963 World_Free(world
, world
->mTopGroup
);
965 for (uint32 i
=0; i
<world
->mNumSndBufs
; ++i
) {
966 SndBuf
*nrtbuf
= world
->mSndBufsNonRealTimeMirror
+ i
;
967 SndBuf
* rtbuf
= world
->mSndBufs
+ i
;
969 if (nrtbuf
->data
) free(nrtbuf
->data
);
970 if (rtbuf
->data
&& rtbuf
->data
!= nrtbuf
->data
) free(rtbuf
->data
);
972 #ifndef NO_LIBSNDFILE
973 if (nrtbuf
->sndfile
) sf_close(nrtbuf
->sndfile
);
974 if (rtbuf
->sndfile
&& rtbuf
->sndfile
!= nrtbuf
->sndfile
) sf_close(rtbuf
->sndfile
);
978 free(world
->mSndBufsNonRealTimeMirror
);
979 free(world
->mSndBufs
);
981 free(world
->mControlBusTouched
);
982 free(world
->mAudioBusTouched
);
986 free(world
->mControlBus
);
987 free(world
->mAudioBus
);
988 delete [] world
->mRGen
;
991 #ifndef NO_LIBSNDFILE
992 if (hw
->mNRTInputFile
) sf_close(hw
->mNRTInputFile
);
993 if (hw
->mNRTOutputFile
) sf_close(hw
->mNRTOutputFile
);
994 if (hw
->mNRTCmdFile
) fclose(hw
->mNRTCmdFile
);
998 delete hw
->mGraphDefLib
;
999 delete hw
->mQuitProgram
;
1000 delete hw
->mAllocPool
;
1007 void World_NRTLock(World
*world
)
1009 world
->mNRTLock
->Lock();
1012 void World_NRTUnlock(World
*world
)
1014 world
->mNRTLock
->Unlock();
1017 ////////////////////////////////////////////////////////////////////////////////
1019 bool getScopeBuffer(World
*inWorld
, int index
, int channels
, int maxFrames
, ScopeBufferHnd
&hnd
)
1021 server_shared_memory_creator
* shm
= inWorld
->hw
->mShmem
;
1023 scope_buffer_writer writer
= shm
->get_scope_buffer_writer( index
, channels
, maxFrames
);
1025 if( writer
.valid() ) {
1026 hnd
.internalData
= writer
.buffer
;
1027 hnd
.data
= writer
.data();
1028 hnd
.channels
= channels
;
1029 hnd
.maxFrames
= maxFrames
;
1033 hnd
.internalData
= 0;
1038 void pushScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
, int frames
)
1040 scope_buffer_writer
writer(reinterpret_cast<scope_buffer
*>(hnd
.internalData
));
1041 writer
.push(frames
);
1042 hnd
.data
= writer
.data();
1045 void releaseScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
)
1047 scope_buffer_writer
writer(reinterpret_cast<scope_buffer
*>(hnd
.internalData
));
1048 server_shared_memory_creator
* shm
= inWorld
->hw
->mShmem
;
1049 shm
->release_scope_buffer_writer( writer
);
1052 ////////////////////////////////////////////////////////////////////////////////
1055 inline int32
BUFMASK(int32 x
)
1057 return (1 << (31 - CLZ(x
))) - 1;
1060 SCErr
bufAlloc(SndBuf
* buf
, int numChannels
, int numFrames
, double sampleRate
)
1062 long numSamples
= numFrames
* numChannels
;
1063 if(numSamples
< 1) return kSCErr_Failed
;
1064 buf
->data
= (float*)zalloc(numSamples
, sizeof(float));
1065 if (!buf
->data
) return kSCErr_Failed
;
1067 buf
->channels
= numChannels
;
1068 buf
->frames
= numFrames
;
1069 buf
->samples
= numSamples
;
1070 buf
->mask
= BUFMASK(numSamples
); // for delay lines
1071 buf
->mask1
= buf
->mask
- 1; // for oscillators
1072 buf
->samplerate
= sampleRate
;
1073 buf
->sampledur
= 1. / sampleRate
;
1078 #include "scsynthsend.h"
1080 void TriggerMsg::Perform()
1082 small_scpacket packet
;
1089 packet
.addi(mNodeID
);
1090 packet
.addi(mTriggerID
);
1091 packet
.addf(mValue
);
1093 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1094 int numUsers
= mWorld
->hw
->mNumUsers
;
1095 for (int i
=0; i
<numUsers
; ++i
) {
1096 SendReply(users
+i
, packet
.data(), packet
.size());
1100 static void NodeReplyMsg_RTFree(FifoMsg
* msg
)
1102 //scprintf("NodeReplyMsg_RTFree()\n");
1103 World_Free(msg
->mWorld
, msg
->mData
);
1106 void NodeReplyMsg::Perform()
1108 small_scpacket packet
;
1109 packet
.adds(mCmdName
, mCmdNameSize
);
1110 packet
.maketags(3 + mNumArgs
);
1113 packet
.addi(mNodeID
);
1116 for(int i
=0; i
<mNumArgs
; ++i
) {
1118 packet
.addf(mValues
[i
]);
1121 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1122 int numUsers
= mWorld
->hw
->mNumUsers
;
1123 for (int i
=0; i
<numUsers
; ++i
) {
1124 SendReply(users
+i
, packet
.data(), packet
.size());
1127 // Free memory in realtime thread
1129 msg
.Set(mWorld
, NodeReplyMsg_RTFree
, 0, mRTMemory
);
1130 AudioDriver(mWorld
)->SendMsgToEngine(msg
);
1134 void NodeEndMsg::Perform()
1136 small_scpacket packet
;
1139 packet
.adds("/n_go");
1142 packet
.adds("/n_end");
1145 packet
.adds("/n_on");
1148 packet
.adds("/n_off");
1151 packet
.adds("/n_move");
1154 packet
.adds("/n_info");
1167 packet
.addi(mNodeID
);
1168 packet
.addi(mGroupID
);
1169 packet
.addi(mPrevNodeID
);
1170 packet
.addi(mNextNodeID
);
1171 packet
.addi(mIsGroup
);
1172 packet
.addi(mHeadID
);
1173 packet
.addi(mTailID
);
1182 packet
.addi(mNodeID
);
1183 packet
.addi(mGroupID
);
1184 packet
.addi(mPrevNodeID
);
1185 packet
.addi(mNextNodeID
);
1186 packet
.addi(mIsGroup
);
1189 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1190 int numUsers
= mWorld
->hw
->mNumUsers
;
1191 for (int i
=0; i
<numUsers
; ++i
) {
1192 SendReply(users
+i
, packet
.data(), packet
.size());
1196 void DeleteGraphDefMsg::Perform()
1198 GraphDef_Free(mDef
);
1201 void NotifyNoArgs(World
*inWorld
, char *inString
);
1202 void NotifyNoArgs(World
*inWorld
, char *inString
)
1204 small_scpacket packet
;
1205 packet
.adds(inString
);
1207 ReplyAddress
*users
= inWorld
->hw
->mUsers
;
1208 int numUsers
= inWorld
->hw
->mNumUsers
;
1209 for (int i
=0; i
<numUsers
; ++i
) {
1210 SendReply(users
+i
, packet
.data(), packet
.size());
1215 bool SendMsgToEngine(World
*inWorld
, FifoMsg
& inMsg
)
1217 return inWorld
->hw
->mAudioDriver
->SendMsgToEngine(inMsg
);
1220 bool SendMsgFromEngine(World
*inWorld
, FifoMsg
& inMsg
)
1222 return inWorld
->hw
->mAudioDriver
->SendMsgFromEngine(inMsg
);
1225 SC_DLLEXPORT_C
void SetPrintFunc(PrintFunc func
)
1231 SC_DLLEXPORT_C
int scprintf(const char *fmt
, ...)
1234 va_start(vargs
, fmt
);
1236 if (gPrint
) return (*gPrint
)(fmt
, vargs
);
1237 else return vprintf(fmt
, vargs
);