void World_WaitForQuit(struct World *inWorld, bool unload_plugins) { try { inWorld->hw->mQuitProgram->wait(); World_Cleanup(inWorld, unload_plugins); } catch (std::exception& exc) { scprintf("Exception in World_WaitForQuit: %s\n", exc.what()); } catch (...) { } }
void World_WaitForQuit(struct World *inWorld) { try { inWorld->hw->mQuitProgram->Acquire(); World_Cleanup(inWorld); } catch (std::exception& exc) { scprintf("Exception in World_WaitForQuit: %s\n", exc.what()); } catch (...) { } }
void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions) { if (inOptions->mLoadGraphDefs) { World_LoadGraphDefs(world); } int bufLength = world->mBufLength; int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize; if (fileBufFrames <= 0) fileBufFrames = 8192; int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength; fileBufFrames = bufMultiple * bufLength; // batch process non real time audio if (!inOptions->mNonRealTimeOutputFilename) throw std::runtime_error("Non real time output filename is NULL.\n"); SF_INFO inputFileInfo, outputFileInfo; float *inputFileBuf = 0; float *outputFileBuf = 0; int numInputChannels = 0; int numOutputChannels; outputFileInfo.samplerate = inOptions->mPreferredSampleRate; numOutputChannels = outputFileInfo.channels = world->mNumOutputs; sndfileFormatInfoFromStrings(&outputFileInfo, inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat); world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo); sf_command(world->hw->mNRTOutputFile, SFC_SET_CLIPPING, NULL, SF_TRUE); if (!world->hw->mNRTOutputFile) throw std::runtime_error("Couldn't open non real time output file.\n"); outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float)); if (inOptions->mNonRealTimeInputFilename) { world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo); if (!world->hw->mNRTInputFile) throw std::runtime_error("Couldn't open non real time input file.\n"); inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float)); if (world->mNumInputs != (uint32)inputFileInfo.channels) scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n"); numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it. if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate) scprintf("WARNING: input file sample rate does not equal output sample rate.\n"); } else { world->hw->mNRTInputFile = 0; } FILE *cmdFile; if (inOptions->mNonRealTimeCmdFilename) { #ifdef _WIN32 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb"); #else cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r"); #endif } else cmdFile = stdin; if (!cmdFile) throw std::runtime_error("Couldn't open non real time command file.\n"); OSC_Packet packet; memset(&packet, 0, sizeof(packet)); packet.mData = (char *)malloc(8192); packet.mIsBundle = true; packet.mReplyAddr.mReplyFunc = null_reply_func; int64 schedTime; if (nextOSCPacket(cmdFile, &packet, schedTime)) throw std::runtime_error("command file empty.\n"); int64 prevTime = schedTime; World_SetSampleRate(world, inOptions->mPreferredSampleRate); World_Start(world); int64 oscTime = 0; double oscToSeconds = 1. / pow(2.,32.); double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds; int64 oscInc = (int64)((double)bufLength / oscToSamples); if(inOptions->mVerbosity >= 0) { printf("start time %g\n", schedTime * oscToSeconds); } bool run = true; int inBufStep = numInputChannels * bufLength; int outBufStep = numOutputChannels * bufLength; float* inputBuses = world->mAudioBus + world->mNumOutputs * bufLength; float* outputBuses = world->mAudioBus; int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs; int32* outputTouched = world->mAudioBusTouched; for (; run;) { int bufFramesCalculated = 0; float* inBufPos = inputFileBuf; float* outBufPos = outputFileBuf; if (world->hw->mNRTInputFile) { int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames); if (framesRead < fileBufFrames) { memset(inputFileBuf + framesRead * numInputChannels, 0, (fileBufFrames - framesRead) * numInputChannels * sizeof(float)); } } for (int i=0; i<bufMultiple && run; ++i) { int bufCounter = world->mBufCounter; // deinterleave input to input buses if (inputFileBuf) { float *inBus = inputBuses; for (int j=0; j<numInputChannels; ++j, inBus += bufLength) { float *inFileBufPtr = inBufPos + j; for (int k=0; k<bufLength; ++k) { inBus[k] = *inFileBufPtr; inFileBufPtr += numInputChannels; } inputTouched[j] = bufCounter; } } // execute ready commands int64 nextTime = oscTime + oscInc; while (schedTime <= nextTime) { float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5; float diffTimeFloor = floor(diffTime); world->mSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1; PerformOSCBundle(world, &packet); if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; } if(inOptions->mVerbosity >= 0) { printf("nextOSCPacket %g\n", schedTime * oscToSeconds); } if (schedTime < prevTime) { scprintf("ERROR: Packet time stamps out-of-order.\n"); run = false; goto Bail; } prevTime = schedTime; } World_Run(world); // interleave output to output buffer float *outBus = outputBuses; for (int j=0; j<numOutputChannels; ++j, outBus += bufLength) { float *outFileBufPtr = outBufPos + j; if (outputTouched[j] == bufCounter) { for (int k=0; k<bufLength; ++k) { *outFileBufPtr = outBus[k]; outFileBufPtr += numOutputChannels; } } else { for (int k=0; k<bufLength; ++k) { *outFileBufPtr = 0.f; outFileBufPtr += numOutputChannels; } } } bufFramesCalculated += bufLength; inBufPos += inBufStep; outBufPos += outBufStep; world->mBufCounter++; oscTime = nextTime; } Bail: // write output sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated); } if (cmdFile != stdin) fclose(cmdFile); sf_close(world->hw->mNRTOutputFile); world->hw->mNRTOutputFile = 0; if (world->hw->mNRTInputFile) { sf_close(world->hw->mNRTInputFile); world->hw->mNRTInputFile = 0; } free(packet.mData); World_Cleanup(world,true); }
World* World_New(WorldOptions *inOptions) { #if (_POSIX_MEMLOCK - 0) >= 200112L if (inOptions->mMemoryLocking && inOptions->mRealTime) { bool lock_memory = false; rlimit limit; int failure = getrlimit(RLIMIT_MEMLOCK, &limit); if (failure) scprintf("getrlimit failure\n"); else { if (limit.rlim_cur == RLIM_INFINITY and limit.rlim_max == RLIM_INFINITY) lock_memory = true; else scprintf("memory locking disabled due to resource limiting\n"); if (lock_memory) { if (mlockall(MCL_FUTURE) != -1) scprintf("memory locking enabled.\n"); } } } #endif World *world = 0; try { static bool gLibInitted = false; if (!gLibInitted) { InterfaceTable_Init(); initialize_library(inOptions->mUGensPluginPath); initializeScheduler(); gLibInitted = true; } world = (World*)zalloc(1, sizeof(World)); world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld)); world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0); world->hw->mQuitProgram = new boost::sync::semaphore(0); world->hw->mTerminating = false; HiddenWorld *hw = world->hw; hw->mGraphDefLib = new HashTable<struct GraphDef, Malloc>(&gMalloc, inOptions->mMaxGraphDefs, false); hw->mNodeLib = new IntHashTable<Node, AllocPool>(hw->mAllocPool, inOptions->mMaxNodes, false); hw->mUsers = new Clients(); hw->mMaxUsers = inOptions->mMaxLogins; hw->mAvailableClientIDs = new ClientIDs(); for (int i = 0; i<hw->mMaxUsers; i++) { hw->mAvailableClientIDs->push_back(i); } hw->mClientIDdict = new ClientIDDict(); hw->mHiddenID = -8; hw->mRecentID = -8; world->mNumUnits = 0; world->mNumGraphs = 0; world->mNumGroups = 0; world->mBufCounter = 0; world->mBufLength = inOptions->mBufLength; world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels; world->mNumControlBusChannels = inOptions->mNumControlBusChannels; world->mNumInputs = inOptions->mNumInputBusChannels; world->mNumOutputs = inOptions->mNumOutputBusChannels; world->mVerbosity = inOptions->mVerbosity; world->mErrorNotification = 1; // i.e., 0x01 | 0x02 world->mLocalErrorNotification = 0; if (inOptions->mSharedMemoryID) { server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID); hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels); world->mControlBus = hw->mShmem->get_control_busses(); } else { hw->mShmem = 0; world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float)); } world->mNumSharedControls = 0; world->mSharedControls = inOptions->mSharedControls; int numsamples = world->mBufLength * world->mNumAudioBusChannels; world->mAudioBus = (float*)zalloc(numsamples, sizeof(float)); world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32)); world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32)); world->mNumSndBufs = inOptions->mNumBuffers; world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf)); world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf)); world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates)); GroupNodeDef_Init(); int err = Group_New(world, 0, &world->mTopGroup); if (err) throw err; world->mRealTime = inOptions->mRealTime; world->ft = &gInterfaceTable; world->mNumRGens = inOptions->mNumRGens; world->mRGen = new RGen[world->mNumRGens]; for (uint32 i=0; i<world->mNumRGens; ++i) { world->mRGen[i].init(server_timeseed()); } world->mNRTLock = new SC_Lock(); world->mDriverLock = new SC_Lock(); if (inOptions->mPassword) { strncpy(world->hw->mPassword, inOptions->mPassword, 31); world->hw->mPassword[31] = 0; } else { world->hw->mPassword[0] = 0; } #ifdef __APPLE__ world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled; world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled; #endif world->hw->mInDeviceName = inOptions->mInDeviceName; world->hw->mOutDeviceName = inOptions->mOutDeviceName; hw->mMaxWireBufs = inOptions->mMaxWireBufs; hw->mWireBufSpace = 0; world->mRendezvous = inOptions->mRendezvous; world->mRestrictedPath = inOptions->mRestrictedPath; sc_SetDenormalFlags(); if (world->mRealTime) { hw->mAudioDriver = SC_NewAudioDriver(world); hw->mAudioDriver->SetPreferredHardwareBufferFrameSize( inOptions->mPreferredHardwareBufferFrameSize ); hw->mAudioDriver->SetPreferredSampleRate( inOptions->mPreferredSampleRate ); if (inOptions->mLoadGraphDefs) { World_LoadGraphDefs(world); } if (!hw->mAudioDriver->Setup()) { scprintf("could not initialize audio.\n"); return 0; } if (!hw->mAudioDriver->Start()) { scprintf("start audio failed.\n"); return 0; } #ifdef __APPLE__ SC::Apple::disableAppNap(); #endif } else { hw->mAudioDriver = 0; } if (!scsynth::asioThreadStarted()){ scsynth::startAsioThread(); } } catch (std::exception& exc) { scprintf("Exception in World_New: %s\n", exc.what()); World_Cleanup(world,true); return 0; } catch (...) { } return world; }
int main(int argc, char* argv[]) { setlinebuf(stdout); #ifdef _WIN32 #ifdef SC_WIN32_STATIC_PTHREADS // initialize statically linked pthreads library pthread_win32_process_attach_np(); #endif // initialize winsock WSAData wsaData; int nCode; if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) { scprintf( "WSAStartup() failed with error code %d.\n", nCode ); return 1; } #endif int udpPortNum = -1; int tcpPortNum = -1; WorldOptions options = kDefaultWorldOptions; for (int i=1; i<argc;) { if (argv[i][0] != '-' || argv[i][1] == 0 || strchr("utaioczblndpmwZrNSDIOMHvRUhPL", argv[i][1]) == 0) { scprintf("ERROR: Invalid option %s\n", argv[i]); Usage(); } int j = i; switch (argv[j][1]) { case 'u' : checkNumArgs(2); udpPortNum = atoi(argv[j+1]); break; case 't' : checkNumArgs(2); tcpPortNum = atoi(argv[j+1]); break; case 'a' : checkNumArgs(2); options.mNumAudioBusChannels = atoi(argv[j+1]); break; case 'i' : checkNumArgs(2); options.mNumInputBusChannels = atoi(argv[j+1]); break; case 'o' : checkNumArgs(2); options.mNumOutputBusChannels = atoi(argv[j+1]); break; case 'c' : checkNumArgs(2); options.mNumControlBusChannels = atoi(argv[j+1]); break; case 'z' : checkNumArgs(2); options.mBufLength = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'Z' : checkNumArgs(2); options.mPreferredHardwareBufferFrameSize = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'b' : checkNumArgs(2); options.mNumBuffers = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'l' : checkNumArgs(2); options.mMaxLogins = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'n' : checkNumArgs(2); options.mMaxNodes = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'd' : checkNumArgs(2); options.mMaxGraphDefs = NEXTPOWEROFTWO(atoi(argv[j+1])); break; case 'p' : checkNumArgs(2); options.mPassword = argv[j+1]; break; case 'm' : checkNumArgs(2); options.mRealTimeMemorySize = atoi(argv[j+1]); break; case 'w' : checkNumArgs(2); options.mMaxWireBufs = atoi(argv[j+1]); break; case 'r' : checkNumArgs(2); options.mNumRGens = atoi(argv[j+1]); break; case 'S' : checkNumArgs(2); options.mPreferredSampleRate = (uint32)atof(argv[j+1]); break; case 'D' : checkNumArgs(2); options.mLoadGraphDefs = atoi(argv[j+1]); break; case 'N' : #ifdef NO_LIBSNDFILE scprintf("NRT mode not supported: scsynth compiled without libsndfile\n"); exit(0); #endif // -N cmd-filename input-filename output-filename sample-rate header-format sample-format checkNumArgs(7); options.mRealTime = false; options.mNonRealTimeCmdFilename = strcmp(argv[j+1], "_") ? argv[j+1] : 0; options.mNonRealTimeInputFilename = strcmp(argv[j+2], "_") ? argv[j+2] : 0; options.mNonRealTimeOutputFilename = argv[j+3]; options.mPreferredSampleRate = (uint32)atof(argv[j+4]); options.mNonRealTimeOutputHeaderFormat = argv[j+5]; options.mNonRealTimeOutputSampleFormat = argv[j+6]; break; #ifdef __APPLE__ case 'I' : checkNumArgs(2); options.mInputStreamsEnabled = argv[j+1]; break; case 'O' : checkNumArgs(2); options.mOutputStreamsEnabled = argv[j+1]; break; case 'M': #endif case 'H' : checkNumArgs(2); options.mInDeviceName = argv[j+1]; #ifdef __APPLE__ if (i+1>argc || argv[j+2][0]=='-') { options.mOutDeviceName = options.mInDeviceName; } else { // If there's a second argument then the user wants separate I/O devices options.mOutDeviceName = argv[j+2]; ++i; } #else options.mOutDeviceName = options.mInDeviceName; // Non-Mac platforms always use same device #endif break; case 'L' : checkNumArgs(1); #if (_POSIX_MEMLOCK - 0) >= 200112L options.mMemoryLocking = true; #else options.mMemoryLocking = false; #endif break; case 'v' : checkNumArgs(2); options.mVerbosity = atoi(argv[j+1]); break; case 'R' : checkNumArgs(2); options.mRendezvous = atoi(argv[j+1]) > 0; break; case 'U' : checkNumArgs(2); options.mUGensPluginPath = argv[j+1]; break; case 'P' : checkNumArgs(2); options.mRestrictedPath = argv[j+1]; break; case 'h': default: Usage(); } } if (udpPortNum == -1 && tcpPortNum == -1 && options.mRealTime) { scprintf("ERROR: There must be a -u and/or a -t options, or -N for nonrealtime.\n"); Usage(); } if (options.mNumInputBusChannels + options.mNumOutputBusChannels > options.mNumAudioBusChannels) { scprintf("ERROR: number of audio bus channels < inputs + outputs.\n"); Usage(); } struct World *world = World_New(&options); if (!world) return 1; if (!options.mRealTime) { #ifdef NO_LIBSNDFILE return 1; #else int exitCode = 0; try { World_NonRealTimeSynthesis(world, &options); } catch (std::exception& exc) { scprintf("%s\n", exc.what()); exitCode = 1; } return exitCode; #endif } if (udpPortNum >= 0) { if (!World_OpenUDP(world, udpPortNum)) { World_Cleanup(world); return 1; } } if (tcpPortNum >= 0) { if (!World_OpenTCP(world, tcpPortNum, options.mMaxLogins, 8)) { World_Cleanup(world); return 1; } } if(options.mVerbosity >=0){ #ifdef NDEBUG scprintf("SuperCollider 3 server ready.\n"); #else scprintf("SuperCollider 3 server ready (debug build).\n"); #endif } fflush(stdout); World_WaitForQuit(world); #ifdef _WIN32 // clean up winsock WSACleanup(); #ifdef SC_WIN32_STATIC_PTHREADS // clean up statically linked pthreads pthread_win32_process_detach_np(); #endif // SC_WIN32_STATIC_PTHREADS #endif // _WIN32 return 0; }