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"
39 # include "../../include/server/SC_ComPort.h"
40 # include "SC_Win32Utils.h"
42 # include "SC_ComPort.h"
44 #include "SC_StringParser.h"
48 # include <sys/param.h>
51 // undefine the shadowed scfft functions
57 #if (_POSIX_MEMLOCK - 0) >= 200112L
58 # include <sys/resource.h>
59 # include <sys/mman.h>
62 #include "server_shm.hpp"
65 InterfaceTable gInterfaceTable
;
68 extern HashTable
<struct UnitDef
, Malloc
> *gUnitDefLib
;
69 extern HashTable
<struct BufGen
, Malloc
> *gBufGenLib
;
70 extern HashTable
<PlugInCmd
, Malloc
> *gPlugInCmds
;
78 int sndfileFormatInfoFromStrings(struct SF_INFO
*info
,
79 const char *headerFormatString
, const char *sampleFormatString
);
81 bool SendMsgToEngine(World
*inWorld
, FifoMsg
& inMsg
);
82 bool SendMsgFromEngine(World
*inWorld
, FifoMsg
& inMsg
);
85 bool sc_UseVectorUnit();
86 void sc_SetDenormalFlags();
88 ////////////////////////////////////////////////////////////////////////////////
93 #define _XOPEN_SOURCE 600
98 #ifndef SC_MEMORY_ALIGNMENT
99 # error SC_MEMORY_ALIGNMENT undefined
101 #define SC_DBUG_MEMORY 0
103 inline void* sc_malloc(size_t size
)
105 #if SC_MEMORY_ALIGNMENT > 1
107 int err
= posix_memalign(&ptr
, SC_MEMORY_ALIGNMENT
, size
);
121 void* sc_dbg_malloc(size_t size
, const char* tag
, int line
)
123 void* ptr
= sc_malloc(size
);
124 fprintf(stderr
, "sc_dbg_malloc [%s:%d] %p %zu\n", tag
, line
, ptr
, size
);
125 #if SC_MEMORY_ALIGNMENT > 1
126 if (((intptr_t)ptr
% SC_MEMORY_ALIGNMENT
) != 0) {
127 fprintf(stderr
, "sc_dbg_malloc [%s:%d] %p %zu: memory alignment error\n",
128 tag
, line
, ptr
, size
);
135 inline void sc_free(void* ptr
)
140 void sc_dbg_free(void* ptr
, const char* tag
, int line
)
142 fprintf(stderr
, "sc_dbg_free [%s:%d]: %p\n", tag
, line
, ptr
);
146 inline void* sc_zalloc(size_t n
, size_t size
)
150 void* ptr
= sc_malloc(size
);
152 memset(ptr
, 0, size
);
159 void* sc_dbg_zalloc(size_t n
, size_t size
, const char* tag
, int line
)
161 void* ptr
= sc_zalloc(n
, size
);
162 fprintf(stderr
, "sc_dbg_zalloc [%s:%d]: %p %zu %zu\n", tag
, line
, ptr
, n
, size
);
167 # define malloc(size) sc_dbg_malloc((size), __FUNCTION__, __LINE__)
168 # define free(ptr) sc_dbg_free((ptr), __FUNCTION__, __LINE__)
169 # define zalloc(n, size) sc_dbg_zalloc((n), (size), __FUNCTION__, __LINE__)
171 # define malloc(size) sc_malloc((size))
172 # define free(ptr) sc_free((ptr))
173 # define zalloc(n, size) sc_zalloc((n), (size))
174 # endif // SC_DEBUG_MEMORY
178 // replacement for calloc.
179 // calloc lazily zeroes memory on first touch. This is good for most purposes, but bad for realtime audio.
180 void *zalloc(size_t n
, size_t size
)
184 void* ptr
= malloc(size
);
186 memset(ptr
, 0, size
);
194 ////////////////////////////////////////////////////////////////////////////////
196 static bool getScopeBuffer(World
*inWorld
, int index
, int channels
, int maxFrames
, ScopeBufferHnd
&hnd
);
197 static void pushScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
, int frames
);
198 static void releaseScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
);
200 void InterfaceTable_Init()
202 InterfaceTable
*ft
= &gInterfaceTable
;
205 ft
->mCosecant
= gInvSine
;
206 ft
->mSineSize
= kSineSize
;
207 ft
->mSineWavetable
= gSineWavetable
;
209 ft
->fPrint
= &scprintf
;
211 ft
->fRanSeed
= &server_timeseed
;
213 ft
->fNodeEnd
= &Node_End
;
215 ft
->fDefineUnit
= &UnitDef_Create
;
216 ft
->fDefineBufGen
= &BufGen_Create
;
217 ft
->fClearUnitOutputs
= &Unit_ZeroOutputs
;
219 ft
->fNRTAlloc
= &malloc
;
220 ft
->fNRTRealloc
= &realloc
;
221 ft
->fNRTFree
= &free
;
223 ft
->fRTAlloc
= &World_Alloc
;
224 ft
->fRTRealloc
= &World_Realloc
;
225 ft
->fRTFree
= &World_Free
;
227 ft
->fNodeRun
= &Node_SetRun
;
229 ft
->fSendTrigger
= &Node_SendTrigger
;
230 ft
->fSendNodeReply
= &Node_SendReply
;
233 ft
->fDefineUnitCmd
= &UnitDef_AddCmd
;
234 ft
->fDefinePlugInCmd
= &PlugIn_DefineCmd
;
236 ft
->fSendMsgFromRT
= &SendMsgFromEngine
;
237 ft
->fSendMsgToRT
= &SendMsgToEngine
;
239 ft
->fSndFileFormatInfoFromStrings
= NULL
;
241 ft
->fSndFileFormatInfoFromStrings
= &sndfileFormatInfoFromStrings
;
243 ft
->fGetNode
= &World_GetNode
;
244 ft
->fGetGraph
= &World_GetGraph
;
246 ft
->fNRTLock
= &World_NRTLock
;
247 ft
->fNRTUnlock
= &World_NRTUnlock
;
249 ft
->mAltivecAvailable
= sc_UseVectorUnit();
251 ft
->fGroup_DeleteAll
= &Group_DeleteAll
;
252 ft
->fDoneAction
= &Unit_DoneAction
;
253 ft
->fDoAsynchronousCommand
= &PerformAsynchronousCommand
;
254 ft
->fBufAlloc
= &bufAlloc
;
256 ft
->fSCfftCreate
= &scfft_create
;
257 ft
->fSCfftDestroy
= &scfft_destroy
;
258 ft
->fSCfftDoFFT
= &scfft_dofft
;
259 ft
->fSCfftDoIFFT
= &scfft_doifft
;
261 ft
->fGetScopeBuffer
= &getScopeBuffer
;
262 ft
->fPushScopeBuffer
= &pushScopeBuffer
;
263 ft
->fReleaseScopeBuffer
= &releaseScopeBuffer
;
266 void initialize_library(const char *mUGensPluginPath
);
267 void initializeScheduler();
269 static void World_LoadGraphDefs(World
* world
);
270 void World_LoadGraphDefs(World
* world
)
274 if(getenv("SC_SYNTHDEF_PATH")){
275 if(world
->mVerbosity
> 0)
276 scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH"));
277 SC_StringParser
sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER
);
278 while (!sp
.AtEnd()) {
280 char *path
= const_cast<char *>(sp
.NextToken());
281 list
= GraphDef_LoadDir(world
, path
, list
);
282 GraphDef_Define(world
, list
);
285 char resourceDir
[MAXPATHLEN
];
286 if(sc_IsStandAlone())
287 sc_GetResourceDirectory(resourceDir
, MAXPATHLEN
);
289 sc_GetUserAppSupportDirectory(resourceDir
, MAXPATHLEN
);
290 sc_AppendToPath(resourceDir
, MAXPATHLEN
, "synthdefs");
291 if(world
->mVerbosity
> 0)
292 scprintf("Loading synthdefs from default path: %s\n", resourceDir
);
293 list
= GraphDef_LoadDir(world
, resourceDir
, list
);
294 GraphDef_Define(world
, list
);
299 SC_DLLEXPORT_C World
* World_New(WorldOptions
*inOptions
)
301 #if (_POSIX_MEMLOCK - 0) >= 200112L
302 if (inOptions
->mMemoryLocking
&& inOptions
->mRealTime
)
304 bool lock_memory
= false;
308 int failure
= getrlimit(RLIMIT_MEMLOCK
, &limit
);
310 scprintf("getrlimit failure\n");
313 if (limit
.rlim_cur
== RLIM_INFINITY
and
314 limit
.rlim_max
== RLIM_INFINITY
)
317 scprintf("memory locking disabled due to resource limiting\n");
321 if (mlockall(MCL_FUTURE
) != -1)
322 scprintf("memory locking enabled.\n");
331 static bool gLibInitted
= false;
333 InterfaceTable_Init();
334 initialize_library(inOptions
->mUGensPluginPath
);
335 initializeScheduler();
339 world
= (World
*)zalloc(1, sizeof(World
));
341 world
->hw
= (HiddenWorld
*)zalloc(1, sizeof(HiddenWorld
));
343 world
->hw
->mAllocPool
= new AllocPool(malloc
, free
, inOptions
->mRealTimeMemorySize
* 1024, 0);
344 world
->hw
->mQuitProgram
= new SC_Semaphore(0);
345 world
->hw
->mTerminating
= false;
347 extern Malloc gMalloc
;
349 HiddenWorld
*hw
= world
->hw
;
350 hw
->mGraphDefLib
= new HashTable
<struct GraphDef
, Malloc
>(&gMalloc
, inOptions
->mMaxGraphDefs
, false);
351 hw
->mNodeLib
= new IntHashTable
<Node
, AllocPool
>(hw
->mAllocPool
, inOptions
->mMaxNodes
, false);
352 hw
->mUsers
= (ReplyAddress
*)zalloc(inOptions
->mMaxLogins
, sizeof(ReplyAddress
));
354 hw
->mMaxUsers
= inOptions
->mMaxLogins
;
359 world
->mNumUnits
= 0;
360 world
->mNumGraphs
= 0;
361 world
->mNumGroups
= 0;
363 world
->mBufCounter
= 0;
364 world
->mBufLength
= inOptions
->mBufLength
;
365 world
->mSampleOffset
= 0;
366 world
->mSubsampleOffset
= 0.f
;
367 world
->mNumAudioBusChannels
= inOptions
->mNumAudioBusChannels
;
368 world
->mNumControlBusChannels
= inOptions
->mNumControlBusChannels
;
369 world
->mNumInputs
= inOptions
->mNumInputBusChannels
;
370 world
->mNumOutputs
= inOptions
->mNumOutputBusChannels
;
372 world
->mVerbosity
= inOptions
->mVerbosity
;
373 world
->mErrorNotification
= 1; // i.e., 0x01 | 0x02
374 world
->mLocalErrorNotification
= 0;
376 if (inOptions
->mSharedMemoryID
) {
377 server_shared_memory_creator::cleanup(inOptions
->mSharedMemoryID
);
378 hw
->mShmem
= new server_shared_memory_creator(inOptions
->mSharedMemoryID
, inOptions
->mNumControlBusChannels
);
379 world
->mControlBus
= hw
->mShmem
->get_control_busses();
381 world
->mControlBus
= (float*)zalloc(world
->mNumControlBusChannels
, sizeof(float));
383 world
->mNumSharedControls
= 0;
384 world
->mSharedControls
= inOptions
->mSharedControls
;
386 int numsamples
= world
->mBufLength
* world
->mNumAudioBusChannels
;
387 world
->mAudioBus
= (float*)zalloc(numsamples
, sizeof(float));
389 world
->mAudioBusTouched
= (int32
*)zalloc(inOptions
->mNumAudioBusChannels
, sizeof(int32
));
390 world
->mControlBusTouched
= (int32
*)zalloc(inOptions
->mNumControlBusChannels
, sizeof(int32
));
392 world
->mNumSndBufs
= inOptions
->mNumBuffers
;
393 world
->mSndBufs
= (SndBuf
*)zalloc(world
->mNumSndBufs
, sizeof(SndBuf
));
394 world
->mSndBufsNonRealTimeMirror
= (SndBuf
*)zalloc(world
->mNumSndBufs
, sizeof(SndBuf
));
395 world
->mSndBufUpdates
= (SndBufUpdates
*)zalloc(world
->mNumSndBufs
, sizeof(SndBufUpdates
));
399 int err
= Group_New(world
, 0, &world
->mTopGroup
);
402 world
->mRealTime
= inOptions
->mRealTime
;
404 world
->ft
= &gInterfaceTable
;
406 world
->mNumRGens
= inOptions
->mNumRGens
;
407 world
->mRGen
= new RGen
[world
->mNumRGens
];
408 for (uint32 i
=0; i
<world
->mNumRGens
; ++i
) {
409 world
->mRGen
[i
].init(server_timeseed());
412 world
->mNRTLock
= new SC_Lock();
413 world
->mDriverLock
= new SC_Lock();
415 if (inOptions
->mPassword
) {
416 strncpy(world
->hw
->mPassword
, inOptions
->mPassword
, 31);
417 world
->hw
->mPassword
[31] = 0;
419 world
->hw
->mPassword
[0] = 0;
423 world
->hw
->mInputStreamsEnabled
= inOptions
->mInputStreamsEnabled
;
424 world
->hw
->mOutputStreamsEnabled
= inOptions
->mOutputStreamsEnabled
;
426 world
->hw
->mInDeviceName
= inOptions
->mInDeviceName
;
427 world
->hw
->mOutDeviceName
= inOptions
->mOutDeviceName
;
428 hw
->mMaxWireBufs
= inOptions
->mMaxWireBufs
;
429 hw
->mWireBufSpace
= 0;
431 world
->mRendezvous
= inOptions
->mRendezvous
;
433 world
->mRestrictedPath
= inOptions
->mRestrictedPath
;
435 if(inOptions
->mVerbosity
>= 1) {
436 scprintf("Using vector unit: %s\n", sc_UseVectorUnit() ? "yes" : "no");
438 sc_SetDenormalFlags();
440 if (world
->mRealTime
) {
441 hw
->mAudioDriver
= SC_NewAudioDriver(world
);
442 hw
->mAudioDriver
->SetPreferredHardwareBufferFrameSize(
443 inOptions
->mPreferredHardwareBufferFrameSize
445 hw
->mAudioDriver
->SetPreferredSampleRate(
446 inOptions
->mPreferredSampleRate
449 if (inOptions
->mLoadGraphDefs
) {
450 World_LoadGraphDefs(world
);
453 if (!hw
->mAudioDriver
->Setup()) {
454 scprintf("could not initialize audio.\n");
457 if (!hw
->mAudioDriver
->Start()) {
458 scprintf("start audio failed.\n");
462 hw
->mAudioDriver
= 0;
464 } catch (std::exception
& exc
) {
465 scprintf("Exception in World_New: %s\n", exc
.what());
466 World_Cleanup(world
);
473 SC_DLLEXPORT_C
int World_CopySndBuf(World
*world
, uint32 index
, SndBuf
*outBuf
, bool onlyIfChanged
, bool *outDidChange
)
475 if (index
> world
->mNumSndBufs
) return kSCErr_IndexOutOfRange
;
477 SndBufUpdates
*updates
= world
->mSndBufUpdates
+ index
;
478 bool didChange
= updates
->reads
!= updates
->writes
;
480 if (!onlyIfChanged
|| didChange
)
483 world
->mNRTLock
->Lock();
485 SndBuf
*buf
= world
->mSndBufsNonRealTimeMirror
+ index
;
487 if (buf
->data
&& buf
->samples
)
489 uint32 bufSize
= buf
->samples
* sizeof(float);
490 if (buf
->samples
!= outBuf
->samples
)
493 outBuf
->data
= (float*)malloc(bufSize
);
495 memcpy(outBuf
->data
, buf
->data
, bufSize
);
496 outBuf
->channels
= buf
->channels
;
497 outBuf
->samples
= buf
->samples
;
498 outBuf
->frames
= buf
->frames
;
499 outBuf
->mask
= buf
->mask
;
500 outBuf
->mask1
= buf
->mask1
;
506 outBuf
->channels
= 0;
513 outBuf
->samplerate
= buf
->samplerate
;
514 outBuf
->sampledur
= buf
->sampledur
;
515 outBuf
->coord
= buf
->coord
;
518 updates
->reads
= updates
->writes
;
520 world
->mNRTLock
->Unlock();
523 if (outDidChange
) *outDidChange
= didChange
;
528 bool nextOSCPacket(FILE *file
, OSC_Packet
*packet
, int64
& outTime
)
531 if (fread(&msglen
, 1, sizeof(int32
), file
) != sizeof(int32
))
533 // msglen is in network byte order
534 msglen
= OSCint((char*)&msglen
);
536 throw std::runtime_error("OSC packet too long. > 8192 bytes\n");
538 size_t read
= fread(packet
->mData
, 1, msglen
, file
);
540 throw std::runtime_error("nextOSCPacket: invalid read of OSC packaet\n");
542 if (strcmp(packet
->mData
, "#bundle")!=0)
543 throw std::runtime_error("OSC packet not a bundle\n");
545 packet
->mSize
= msglen
;
547 outTime
= OSCtime(packet
->mData
+8);
551 void PerformOSCBundle(World
*inWorld
, OSC_Packet
*inPacket
);
553 #ifndef NO_LIBSNDFILE
554 SC_DLLEXPORT_C
void World_NonRealTimeSynthesis(struct World
*world
, WorldOptions
*inOptions
)
556 if (inOptions
->mLoadGraphDefs
) {
557 World_LoadGraphDefs(world
);
559 int bufLength
= world
->mBufLength
;
560 int fileBufFrames
= inOptions
->mPreferredHardwareBufferFrameSize
;
561 if (fileBufFrames
<= 0) fileBufFrames
= 8192;
562 int bufMultiple
= (fileBufFrames
+ bufLength
- 1) / bufLength
;
563 fileBufFrames
= bufMultiple
* bufLength
;
565 // batch process non real time audio
566 if (!inOptions
->mNonRealTimeOutputFilename
)
567 throw std::runtime_error("Non real time output filename is NULL.\n");
569 SF_INFO inputFileInfo
, outputFileInfo
;
570 float *inputFileBuf
= 0;
571 float *outputFileBuf
= 0;
572 int numInputChannels
= 0;
573 int numOutputChannels
;
575 outputFileInfo
.samplerate
= inOptions
->mPreferredSampleRate
;
576 numOutputChannels
= outputFileInfo
.channels
= world
->mNumOutputs
;
577 sndfileFormatInfoFromStrings(&outputFileInfo
,
578 inOptions
->mNonRealTimeOutputHeaderFormat
, inOptions
->mNonRealTimeOutputSampleFormat
);
580 world
->hw
->mNRTOutputFile
= sf_open(inOptions
->mNonRealTimeOutputFilename
, SFM_WRITE
, &outputFileInfo
);
581 if (!world
->hw
->mNRTOutputFile
)
582 throw std::runtime_error("Couldn't open non real time output file.\n");
584 outputFileBuf
= (float*)calloc(1, world
->mNumOutputs
* fileBufFrames
* sizeof(float));
586 if (inOptions
->mNonRealTimeInputFilename
) {
587 world
->hw
->mNRTInputFile
= sf_open(inOptions
->mNonRealTimeInputFilename
, SFM_READ
, &inputFileInfo
);
588 if (!world
->hw
->mNRTInputFile
)
589 throw std::runtime_error("Couldn't open non real time input file.\n");
591 inputFileBuf
= (float*)calloc(1, inputFileInfo
.channels
* fileBufFrames
* sizeof(float));
593 if (world
->mNumInputs
!= (uint32
)inputFileInfo
.channels
)
594 scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");
596 numInputChannels
= world
->mNumInputs
= inputFileInfo
.channels
; // force it.
598 if (inputFileInfo
.samplerate
!= (int)inOptions
->mPreferredSampleRate
)
599 scprintf("WARNING: input file sample rate does not equal output sample rate.\n");
602 world
->hw
->mNRTInputFile
= 0;
606 if (inOptions
->mNonRealTimeCmdFilename
) {
608 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "rb");
610 cmdFile
= fopen(inOptions
->mNonRealTimeCmdFilename
, "r");
612 } else cmdFile
= stdin
;
614 throw std::runtime_error("Couldn't open non real time command file.\n");
618 memset(&packet
, 0, sizeof(packet
));
619 packet
.mData
= msgbuf
;
620 packet
.mIsBundle
= true;
621 packet
.mReplyAddr
.mReplyFunc
= null_reply_func
;
624 if (nextOSCPacket(cmdFile
, &packet
, schedTime
))
625 throw std::runtime_error("command file empty.\n");
626 int64 prevTime
= schedTime
;
628 World_SetSampleRate(world
, inOptions
->mPreferredSampleRate
);
632 double oscToSeconds
= 1. / pow(2.,32.);
633 double oscToSamples
= inOptions
->mPreferredSampleRate
* oscToSeconds
;
634 int64 oscInc
= (int64
)((double)bufLength
/ oscToSamples
);
636 if(inOptions
->mVerbosity
>= 0) {
637 printf("start time %g\n", schedTime
* oscToSeconds
);
641 int inBufStep
= numInputChannels
* bufLength
;
642 int outBufStep
= numOutputChannels
* bufLength
;
643 float* inputBuses
= world
->mAudioBus
+ world
->mNumOutputs
* bufLength
;
644 float* outputBuses
= world
->mAudioBus
;
645 int32
* inputTouched
= world
->mAudioBusTouched
+ world
->mNumOutputs
;
646 int32
* outputTouched
= world
->mAudioBusTouched
;
648 int bufFramesCalculated
= 0;
649 float* inBufPos
= inputFileBuf
;
650 float* outBufPos
= outputFileBuf
;
652 if (world
->hw
->mNRTInputFile
) {
653 int framesRead
= sf_readf_float(world
->hw
->mNRTInputFile
, inputFileBuf
, fileBufFrames
);
654 if (framesRead
< fileBufFrames
) {
655 memset(inputFileBuf
+ framesRead
* numInputChannels
, 0,
656 (fileBufFrames
- framesRead
) * numInputChannels
* sizeof(float));
660 for (int i
=0; i
<bufMultiple
&& run
; ++i
) {
661 int bufCounter
= world
->mBufCounter
;
663 // deinterleave input to input buses
665 float *inBus
= inputBuses
;
666 for (int j
=0; j
<numInputChannels
; ++j
, inBus
+= bufLength
) {
667 float *inFileBufPtr
= inBufPos
+ j
;
668 for (int k
=0; k
<bufLength
; ++k
) {
669 inBus
[k
] = *inFileBufPtr
;
670 inFileBufPtr
+= numInputChannels
;
672 inputTouched
[j
] = bufCounter
;
676 // execute ready commands
677 int64 nextTime
= oscTime
+ oscInc
;
679 while (schedTime
<= nextTime
) {
680 float diffTime
= (float)(schedTime
- oscTime
) * oscToSamples
+ 0.5;
681 float diffTimeFloor
= floor(diffTime
);
682 world
->mSampleOffset
= (int)diffTimeFloor
;
683 world
->mSubsampleOffset
= diffTime
- diffTimeFloor
;
685 if (world
->mSampleOffset
< 0) world
->mSampleOffset
= 0;
686 else if (world
->mSampleOffset
>= bufLength
) world
->mSampleOffset
= bufLength
-1;
689 PerformOSCBundle(world
, &packet
);
690 if (nextOSCPacket(cmdFile
, &packet
, schedTime
)) { run
= false; break; }
691 if(inOptions
->mVerbosity
>= 0) {
692 printf("nextOSCPacket %g\n", schedTime
* oscToSeconds
);
694 if (schedTime
< prevTime
) {
695 scprintf("ERROR: Packet time stamps out-of-order.\n");
699 prevTime
= schedTime
;
704 // interleave output to output buffer
705 float *outBus
= outputBuses
;
706 for (int j
=0; j
<numOutputChannels
; ++j
, outBus
+= bufLength
) {
707 float *outFileBufPtr
= outBufPos
+ j
;
708 if (outputTouched
[j
] == bufCounter
) {
709 for (int k
=0; k
<bufLength
; ++k
) {
710 *outFileBufPtr
= outBus
[k
];
711 outFileBufPtr
+= numOutputChannels
;
714 for (int k
=0; k
<bufLength
; ++k
) {
715 *outFileBufPtr
= 0.f
;
716 outFileBufPtr
+= numOutputChannels
;
720 bufFramesCalculated
+= bufLength
;
721 inBufPos
+= inBufStep
;
722 outBufPos
+= outBufStep
;
723 world
->mBufCounter
++;
729 sf_writef_float(world
->hw
->mNRTOutputFile
, outputFileBuf
, bufFramesCalculated
);
732 if (cmdFile
!= stdin
) fclose(cmdFile
);
733 sf_close(world
->hw
->mNRTOutputFile
);
734 world
->hw
->mNRTOutputFile
= 0;
736 if (world
->hw
->mNRTInputFile
) {
737 sf_close(world
->hw
->mNRTInputFile
);
738 world
->hw
->mNRTInputFile
= 0;
741 World_Cleanup(world
);
743 #endif // !NO_LIBSNDFILE
745 SC_DLLEXPORT_C
int World_OpenUDP(struct World
*inWorld
, int inPort
)
748 new SC_UdpInPort(inWorld
, inPort
);
750 } catch (std::exception
& exc
) {
751 scprintf("Exception in World_OpenUDP: %s\n", exc
.what());
757 SC_DLLEXPORT_C
int World_OpenTCP(struct World
*inWorld
, int inPort
, int inMaxConnections
, int inBacklog
)
760 new SC_TcpInPort(inWorld
, inPort
, inMaxConnections
, inBacklog
);
762 } catch (std::exception
& exc
) {
763 scprintf("Exception in World_OpenTCP: %s\n", exc
.what());
769 SC_DLLEXPORT_C
void World_WaitForQuit(struct World
*inWorld
)
772 inWorld
->hw
->mQuitProgram
->Acquire();
773 World_Cleanup(inWorld
);
774 } catch (std::exception
& exc
) {
775 scprintf("Exception in World_WaitForQuit: %s\n", exc
.what());
780 void World_SetSampleRate(World
*inWorld
, double inSampleRate
)
782 inWorld
->mSampleRate
= inSampleRate
;
783 Rate_Init(&inWorld
->mFullRate
, inSampleRate
, inWorld
->mBufLength
);
784 Rate_Init(&inWorld
->mBufRate
, inSampleRate
/ inWorld
->mBufLength
, 1);
787 ////////////////////////////////////////////////////////////////////////////////
789 void* World_Alloc(World
*inWorld
, size_t inByteSize
)
791 return inWorld
->hw
->mAllocPool
->Alloc(inByteSize
);
794 void* World_Realloc(World
*inWorld
, void *inPtr
, size_t inByteSize
)
796 return inWorld
->hw
->mAllocPool
->Realloc(inPtr
, inByteSize
);
799 size_t World_TotalFree(World
*inWorld
)
801 return inWorld
->hw
->mAllocPool
->TotalFree();
804 size_t World_LargestFreeChunk(World
*inWorld
)
806 return inWorld
->hw
->mAllocPool
->LargestFreeChunk();
809 void World_Free(World
*inWorld
, void *inPtr
)
811 inWorld
->hw
->mAllocPool
->Free(inPtr
);
814 ////////////////////////////////////////////////////////////////////////////////
816 int32
*GetKey(GraphDef
*inGraphDef
)
818 return inGraphDef
->mNodeDef
.mName
;
821 int32
GetHash(GraphDef
*inGraphDef
)
823 return inGraphDef
->mNodeDef
.mHash
;
826 void World_AddGraphDef(World
*inWorld
, GraphDef
* inGraphDef
)
828 bool added
= inWorld
->hw
->mGraphDefLib
->Add(inGraphDef
);
829 if(!added
) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef
->mNodeDef
.mName
);
830 for (uint32 i
=0; i
<inGraphDef
->mNumVariants
; ++i
) {
831 GraphDef
* var
= inGraphDef
->mVariants
+ i
;
832 added
= inWorld
->hw
->mGraphDefLib
->Add(var
);
833 if(!added
) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var
->mNodeDef
.mName
);
837 void World_RemoveGraphDef(World
*inWorld
, GraphDef
* inGraphDef
)
839 for (uint32 i
=0; i
<inGraphDef
->mNumVariants
; ++i
) {
840 GraphDef
* var
= inGraphDef
->mVariants
+ i
;
841 inWorld
->hw
->mGraphDefLib
->Remove(var
);
843 inWorld
->hw
->mGraphDefLib
->Remove(inGraphDef
);
846 void World_FreeAllGraphDefs(World
*inWorld
)
848 GrafDefTable
* lib
= inWorld
->hw
->mGraphDefLib
;
849 int size
= lib
->TableSize();
850 for (int i
=0; i
<size
; ++i
) {
851 GraphDef
*def
= lib
->AtIndex(i
);
852 if (def
) GraphDef_Free(def
);
857 GraphDef
* World_GetGraphDef(World
*inWorld
, int32
* inKey
)
859 return inWorld
->hw
->mGraphDefLib
->Get(inKey
);
862 ////////////////////////////////////////////////////////////////////////////////
864 int32
*GetKey(UnitDef
*inUnitDef
)
866 return inUnitDef
->mUnitDefName
;
869 int32
GetHash(UnitDef
*inUnitDef
)
871 return inUnitDef
->mHash
;
874 bool AddUnitDef(UnitDef
* inUnitDef
)
876 return gUnitDefLib
->Add(inUnitDef
);
879 bool RemoveUnitDef(UnitDef
* inUnitDef
)
881 return gUnitDefLib
->Remove(inUnitDef
);
884 UnitDef
* GetUnitDef(int32
* inKey
)
886 return gUnitDefLib
->Get(inKey
);
889 ////////////////////////////////////////////////////////////////////////////////
891 int32
*GetKey(BufGen
*inBufGen
)
893 return inBufGen
->mBufGenName
;
896 int32
GetHash(BufGen
*inBufGen
)
898 return inBufGen
->mHash
;
901 bool AddBufGen(BufGen
* inBufGen
)
903 return gBufGenLib
->Add(inBufGen
);
906 bool RemoveBufGen(BufGen
* inBufGen
)
908 return gBufGenLib
->Remove(inBufGen
);
911 BufGen
* GetBufGen(int32
* inKey
)
913 return gBufGenLib
->Get(inKey
);
916 ////////////////////////////////////////////////////////////////////////////////
918 int32
*GetKey(PlugInCmd
*inPlugInCmd
)
920 return inPlugInCmd
->mCmdName
;
923 int32
GetHash(PlugInCmd
*inPlugInCmd
)
925 return inPlugInCmd
->mHash
;
928 bool AddPlugInCmd(PlugInCmd
* inPlugInCmd
)
930 return gPlugInCmds
->Add(inPlugInCmd
);
933 bool RemovePlugInCmd(PlugInCmd
* inPlugInCmd
)
935 return gPlugInCmds
->Remove(inPlugInCmd
);
938 PlugInCmd
* GetPlugInCmd(int32
* inKey
)
940 return gPlugInCmds
->Get(inKey
);
943 ////////////////////////////////////////////////////////////////////////////////
945 int32
GetKey(Node
*inNode
)
950 int32
GetHash(Node
*inNode
)
952 return inNode
->mHash
;
955 bool World_AddNode(World
*inWorld
, Node
* inNode
)
957 return inWorld
->hw
->mNodeLib
->Add(inNode
);
960 bool World_RemoveNode(World
*inWorld
, Node
* inNode
)
962 return inWorld
->hw
->mNodeLib
->Remove(inNode
);
965 Node
* World_GetNode(World
*inWorld
, int32 inID
)
967 if (inID
== -1) inID
= inWorld
->hw
->mRecentID
;
968 return inWorld
->hw
->mNodeLib
->Get(inID
);
971 Graph
* World_GetGraph(World
*inWorld
, int32 inID
)
973 if (inID
== -1) inID
= inWorld
->hw
->mRecentID
;
974 Node
*node
= World_GetNode(inWorld
, inID
);
976 return node
->mIsGroup
? 0 : (Graph
*)node
;
979 Group
* World_GetGroup(World
*inWorld
, int32 inID
)
981 Node
*node
= World_GetNode(inWorld
, inID
);
983 return node
->mIsGroup
? (Group
*)node
: 0;
986 ////////////////////////////////////////////////////////////////////////////////
988 void World_Run(World
*inWorld
)
991 Node
*node
= (Node
*)inWorld
->mTopGroup
;
992 (*node
->mCalcFunc
)(node
);
995 void World_Start(World
*inWorld
)
997 inWorld
->mBufCounter
= 0;
998 for (uint32 i
=0; i
<inWorld
->mNumAudioBusChannels
; ++i
) inWorld
->mAudioBusTouched
[i
] = -1;
999 for (uint32 i
=0; i
<inWorld
->mNumControlBusChannels
; ++i
) inWorld
->mControlBusTouched
[i
] = -1;
1001 inWorld
->hw
->mWireBufSpace
= (float*)malloc(inWorld
->hw
->mMaxWireBufs
* inWorld
->mBufLength
* sizeof(float));
1003 inWorld
->hw
->mTriggers
.MakeEmpty();
1004 inWorld
->hw
->mNodeMsgs
.MakeEmpty();
1005 inWorld
->hw
->mNodeEnds
.MakeEmpty();
1006 inWorld
->mRunning
= true;
1009 SC_DLLEXPORT_C
void World_Cleanup(World
*world
)
1013 HiddenWorld
*hw
= world
->hw
;
1015 if (hw
&& world
->mRealTime
) hw
->mAudioDriver
->Stop();
1017 world
->mRunning
= false;
1019 if (world
->mTopGroup
) Group_DeleteAll(world
->mTopGroup
);
1021 world
->mDriverLock
->Lock(); // never unlock..
1023 free(hw
->mWireBufSpace
);
1024 delete hw
->mAudioDriver
;
1025 hw
->mAudioDriver
= 0;
1027 delete world
->mNRTLock
;
1028 delete world
->mDriverLock
;
1029 World_Free(world
, world
->mTopGroup
);
1031 for (uint32 i
=0; i
<world
->mNumSndBufs
; ++i
) {
1032 SndBuf
*nrtbuf
= world
->mSndBufsNonRealTimeMirror
+ i
;
1033 SndBuf
* rtbuf
= world
->mSndBufs
+ i
;
1035 if (nrtbuf
->data
) free(nrtbuf
->data
);
1036 if (rtbuf
->data
&& rtbuf
->data
!= nrtbuf
->data
) free(rtbuf
->data
);
1038 #ifndef NO_LIBSNDFILE
1039 if (nrtbuf
->sndfile
) sf_close(nrtbuf
->sndfile
);
1040 if (rtbuf
->sndfile
&& rtbuf
->sndfile
!= nrtbuf
->sndfile
) sf_close(rtbuf
->sndfile
);
1044 free(world
->mSndBufsNonRealTimeMirror
);
1045 free(world
->mSndBufs
);
1047 free(world
->mControlBusTouched
);
1048 free(world
->mAudioBusTouched
);
1052 free(world
->mControlBus
);
1053 free(world
->mAudioBus
);
1054 delete [] world
->mRGen
;
1057 #ifndef NO_LIBSNDFILE
1058 if (hw
->mNRTInputFile
) sf_close(hw
->mNRTInputFile
);
1059 if (hw
->mNRTOutputFile
) sf_close(hw
->mNRTOutputFile
);
1060 if (hw
->mNRTCmdFile
) fclose(hw
->mNRTCmdFile
);
1063 delete hw
->mNodeLib
;
1064 delete hw
->mGraphDefLib
;
1065 delete hw
->mQuitProgram
;
1066 delete hw
->mAllocPool
;
1073 void World_NRTLock(World
*world
)
1075 world
->mNRTLock
->Lock();
1078 void World_NRTUnlock(World
*world
)
1080 world
->mNRTLock
->Unlock();
1083 ////////////////////////////////////////////////////////////////////////////////
1085 bool getScopeBuffer(World
*inWorld
, int index
, int channels
, int maxFrames
, ScopeBufferHnd
&hnd
)
1087 server_shared_memory_creator
* shm
= inWorld
->hw
->mShmem
;
1089 scope_buffer_writer writer
= shm
->get_scope_buffer_writer( index
, channels
, maxFrames
);
1091 if( writer
.valid() ) {
1092 hnd
.internalData
= writer
.buffer
;
1093 hnd
.data
= writer
.data();
1094 hnd
.channels
= channels
;
1095 hnd
.maxFrames
= maxFrames
;
1099 hnd
.internalData
= 0;
1104 void pushScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
, int frames
)
1106 scope_buffer_writer
writer(reinterpret_cast<scope_buffer
*>(hnd
.internalData
));
1107 writer
.push(frames
);
1108 hnd
.data
= writer
.data();
1111 void releaseScopeBuffer(World
*inWorld
, ScopeBufferHnd
&hnd
)
1113 scope_buffer_writer
writer(reinterpret_cast<scope_buffer
*>(hnd
.internalData
));
1114 server_shared_memory_creator
* shm
= inWorld
->hw
->mShmem
;
1115 shm
->release_scope_buffer_writer( writer
);
1118 ////////////////////////////////////////////////////////////////////////////////
1121 inline int32
BUFMASK(int32 x
)
1123 return (1 << (31 - CLZ(x
))) - 1;
1126 SCErr
bufAlloc(SndBuf
* buf
, int numChannels
, int numFrames
, double sampleRate
)
1128 long numSamples
= numFrames
* numChannels
;
1129 if(numSamples
< 1) return kSCErr_Failed
;
1130 buf
->data
= (float*)zalloc(numSamples
, sizeof(float));
1131 if (!buf
->data
) return kSCErr_Failed
;
1133 buf
->channels
= numChannels
;
1134 buf
->frames
= numFrames
;
1135 buf
->samples
= numSamples
;
1136 buf
->mask
= BUFMASK(numSamples
); // for delay lines
1137 buf
->mask1
= buf
->mask
- 1; // for oscillators
1138 buf
->samplerate
= sampleRate
;
1139 buf
->sampledur
= 1. / sampleRate
;
1144 #ifndef NO_LIBSNDFILE
1145 int sampleFormatFromString(const char* name
);
1146 int sampleFormatFromString(const char* name
)
1148 if (!name
) return SF_FORMAT_PCM_16
;
1150 size_t len
= strlen(name
);
1151 if (len
< 1) return 0;
1153 if (name
[0] == 'u') {
1154 if (len
< 5) return 0;
1155 if (name
[4] == '8') return SF_FORMAT_PCM_U8
; // uint8
1157 } else if (name
[0] == 'i') {
1158 if (len
< 4) return 0;
1159 if (name
[3] == '8') return SF_FORMAT_PCM_S8
; // int8
1160 else if (name
[3] == '1') return SF_FORMAT_PCM_16
; // int16
1161 else if (name
[3] == '2') return SF_FORMAT_PCM_24
; // int24
1162 else if (name
[3] == '3') return SF_FORMAT_PCM_32
; // int32
1163 } else if (name
[0] == 'f') {
1164 return SF_FORMAT_FLOAT
; // float
1165 } else if (name
[0] == 'd') {
1166 return SF_FORMAT_DOUBLE
; // double
1167 } else if (name
[0] == 'm' || name
[0] == 'u') {
1168 return SF_FORMAT_ULAW
; // mulaw ulaw
1169 } else if (name
[0] == 'a') {
1170 return SF_FORMAT_ALAW
; // alaw
1175 int headerFormatFromString(const char *name
);
1176 int headerFormatFromString(const char *name
)
1178 if (!name
) return SF_FORMAT_AIFF
;
1179 if (strcasecmp(name
, "AIFF")==0) return SF_FORMAT_AIFF
;
1180 if (strcasecmp(name
, "AIFC")==0) return SF_FORMAT_AIFF
;
1181 if (strcasecmp(name
, "RIFF")==0) return SF_FORMAT_WAV
;
1182 if (strcasecmp(name
, "WAVEX")==0) return SF_FORMAT_WAVEX
;
1183 if (strcasecmp(name
, "WAVE")==0) return SF_FORMAT_WAV
;
1184 if (strcasecmp(name
, "WAV" )==0) return SF_FORMAT_WAV
;
1185 if (strcasecmp(name
, "Sun" )==0) return SF_FORMAT_AU
;
1186 if (strcasecmp(name
, "IRCAM")==0) return SF_FORMAT_IRCAM
;
1187 if (strcasecmp(name
, "NeXT")==0) return SF_FORMAT_AU
;
1188 if (strcasecmp(name
, "raw")==0) return SF_FORMAT_RAW
;
1189 if (strcasecmp(name
, "MAT4")==0) return SF_FORMAT_MAT4
;
1190 if (strcasecmp(name
, "MAT5")==0) return SF_FORMAT_MAT5
;
1191 if (strcasecmp(name
, "PAF")==0) return SF_FORMAT_PAF
;
1192 if (strcasecmp(name
, "SVX")==0) return SF_FORMAT_SVX
;
1193 if (strcasecmp(name
, "NIST")==0) return SF_FORMAT_NIST
;
1194 if (strcasecmp(name
, "VOC")==0) return SF_FORMAT_VOC
;
1195 if (strcasecmp(name
, "W64")==0) return SF_FORMAT_W64
;
1196 if (strcasecmp(name
, "PVF")==0) return SF_FORMAT_PVF
;
1197 if (strcasecmp(name
, "XI")==0) return SF_FORMAT_XI
;
1198 if (strcasecmp(name
, "HTK")==0) return SF_FORMAT_HTK
;
1199 if (strcasecmp(name
, "SDS")==0) return SF_FORMAT_SDS
;
1200 if (strcasecmp(name
, "AVR")==0) return SF_FORMAT_AVR
;
1201 if (strcasecmp(name
, "SD2")==0) return SF_FORMAT_SD2
;
1202 if (strcasecmp(name
, "FLAC")==0) return SF_FORMAT_FLAC
;
1203 // TODO allow other platforms to know vorbis once libsndfile 1.0.18 is established
1204 #if defined(__APPLE__) || defined(_WIN32) || LIBSNDFILE_1018
1205 if (strcasecmp(name
, "vorbis")==0) return SF_FORMAT_VORBIS
;
1207 if (strcasecmp(name
, "CAF")==0) return SF_FORMAT_CAF
;
1211 int sndfileFormatInfoFromStrings(struct SF_INFO
*info
, const char *headerFormatString
, const char *sampleFormatString
)
1213 int headerFormat
= headerFormatFromString(headerFormatString
);
1214 if (!headerFormat
) return kSCErr_Failed
;
1216 int sampleFormat
= sampleFormatFromString(sampleFormatString
);
1217 if (!sampleFormat
) return kSCErr_Failed
;
1219 info
->format
= (unsigned int)(headerFormat
| sampleFormat
);
1223 #else // NO_LIBSNDFILE
1225 int sndfileFormatInfoFromStrings(struct SF_INFO
*info
, const char *headerFormatString
, const char *sampleFormatString
) {
1226 return kSCErr_Failed
;
1229 #endif // NO_LIBSNDFILE
1231 #include "scsynthsend.h"
1233 void TriggerMsg::Perform()
1235 small_scpacket packet
;
1242 packet
.addi(mNodeID
);
1243 packet
.addi(mTriggerID
);
1244 packet
.addf(mValue
);
1246 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1247 int numUsers
= mWorld
->hw
->mNumUsers
;
1248 for (int i
=0; i
<numUsers
; ++i
) {
1249 SendReply(users
+i
, packet
.data(), packet
.size());
1253 static void NodeReplyMsg_RTFree(FifoMsg
* msg
)
1255 //scprintf("NodeReplyMsg_RTFree()\n");
1256 World_Free(msg
->mWorld
, msg
->mData
);
1259 void NodeReplyMsg::Perform()
1261 small_scpacket packet
;
1262 packet
.adds(mCmdName
, mCmdNameSize
);
1263 packet
.maketags(3 + mNumArgs
);
1266 packet
.addi(mNodeID
);
1269 for(int i
=0; i
<mNumArgs
; ++i
) {
1271 packet
.addf(mValues
[i
]);
1274 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1275 int numUsers
= mWorld
->hw
->mNumUsers
;
1276 for (int i
=0; i
<numUsers
; ++i
) {
1277 SendReply(users
+i
, packet
.data(), packet
.size());
1280 // Free memory in realtime thread
1282 msg
.Set(mWorld
, NodeReplyMsg_RTFree
, 0, mRTMemory
);
1283 AudioDriver(mWorld
)->SendMsgToEngine(msg
);
1287 void NodeEndMsg::Perform()
1289 small_scpacket packet
;
1292 packet
.adds("/n_go");
1295 packet
.adds("/n_end");
1298 packet
.adds("/n_on");
1301 packet
.adds("/n_off");
1304 packet
.adds("/n_move");
1307 packet
.adds("/n_info");
1320 packet
.addi(mNodeID
);
1321 packet
.addi(mGroupID
);
1322 packet
.addi(mPrevNodeID
);
1323 packet
.addi(mNextNodeID
);
1324 packet
.addi(mIsGroup
);
1325 packet
.addi(mHeadID
);
1326 packet
.addi(mTailID
);
1335 packet
.addi(mNodeID
);
1336 packet
.addi(mGroupID
);
1337 packet
.addi(mPrevNodeID
);
1338 packet
.addi(mNextNodeID
);
1339 packet
.addi(mIsGroup
);
1342 ReplyAddress
*users
= mWorld
->hw
->mUsers
;
1343 int numUsers
= mWorld
->hw
->mNumUsers
;
1344 for (int i
=0; i
<numUsers
; ++i
) {
1345 SendReply(users
+i
, packet
.data(), packet
.size());
1349 void DeleteGraphDefMsg::Perform()
1351 GraphDef_Free(mDef
);
1354 void NotifyNoArgs(World
*inWorld
, char *inString
);
1355 void NotifyNoArgs(World
*inWorld
, char *inString
)
1357 small_scpacket packet
;
1358 packet
.adds(inString
);
1360 ReplyAddress
*users
= inWorld
->hw
->mUsers
;
1361 int numUsers
= inWorld
->hw
->mNumUsers
;
1362 for (int i
=0; i
<numUsers
; ++i
) {
1363 SendReply(users
+i
, packet
.data(), packet
.size());
1368 bool SendMsgToEngine(World
*inWorld
, FifoMsg
& inMsg
)
1370 return inWorld
->hw
->mAudioDriver
->SendMsgToEngine(inMsg
);
1373 bool SendMsgFromEngine(World
*inWorld
, FifoMsg
& inMsg
)
1375 return inWorld
->hw
->mAudioDriver
->SendMsgFromEngine(inMsg
);
1378 SC_DLLEXPORT_C
void SetPrintFunc(PrintFunc func
)
1384 SC_DLLEXPORT_C
int scprintf(const char *fmt
, ...)
1387 va_start(vargs
, fmt
);
1389 if (gPrint
) return (*gPrint
)(fmt
, vargs
);
1390 else return vprintf(fmt
, vargs
);