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; }
void SC_JackDriver::Run() { sc_SetDenormalFlags(); jack_client_t* client = mClient; World* world = mWorld; #ifdef SC_JACK_USE_DLL mDLL.Update(secondsSinceEpoch(getTime())); #if SC_JACK_DEBUG_DLL static int tick = 0; if (++tick >= 10) { tick = 0; scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n", mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(), mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs); } #endif #else HostTime hostTime = getTime(); double hostSecs = secondsSinceEpoch(hostTime); double sampleTime = (double)(jack_frame_time(client) + jack_frames_since_cycle_start(client)); if (mStartHostSecs == 0) { mStartHostSecs = hostSecs; mStartSampleTime = sampleTime; } else { double instSampleRate = (sampleTime - mPrevSampleTime) / (hostSecs - mPrevHostSecs); double smoothSampleRate = mSmoothSampleRate; smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate); if (fabs(smoothSampleRate - mSampleRate) > 10.) { smoothSampleRate = mSampleRate; } mOSCincrement = (int64)(mOSCincrementNumerator / smoothSampleRate); mSmoothSampleRate = smoothSampleRate; #if 0 double avgSampleRate = (sampleTime - mStartSampleTime)/(hostSecs - mStartHostSecs); double jitter = (smoothSampleRate * (hostSecs - mPrevHostSecs)) - (sampleTime - mPrevSampleTime); double drift = (smoothSampleRate - mSampleRate) * (hostSecs - mStartHostSecs); #endif } mPrevHostSecs = hostSecs; mPrevSampleTime = sampleTime; #endif try { mFromEngine.Free(); mToEngine.Perform(); mOscPacketsToEngine.Perform(); int numInputs = mInputList->mSize; int numOutputs = mOutputList->mSize; jack_port_t **inPorts = mInputList->mPorts; jack_port_t **outPorts = mOutputList->mPorts; sc_jack_sample_t **inBuffers = mInputList->mBuffers; sc_jack_sample_t **outBuffers = mOutputList->mBuffers; int numSamples = NumSamplesPerCallback(); int bufFrames = mWorld->mBufLength; int numBufs = numSamples / bufFrames; float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames; float *outBuses = mWorld->mAudioBus; int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs; int32 *outTouched = mWorld->mAudioBusTouched; int minInputs = sc_min(numInputs, (int)mWorld->mNumInputs); int minOutputs = sc_min(numOutputs, (int)mWorld->mNumOutputs); int bufFramePos = 0; // cache I/O buffers for (int i = 0; i < minInputs; ++i) { inBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(inPorts[i], numSamples); } for (int i = 0; i < minOutputs; ++i) { outBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(outPorts[i], numSamples); } // main loop #ifdef SC_JACK_USE_DLL int64 oscTime = mOSCbuftime = (int64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5); // int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate()); int64 oscInc = mOSCincrement = (int64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5); mSmoothSampleRate = mDLL.SampleRate(); double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */; #else int64 oscTime = mOSCbuftime = OSCTime(hostTime) - (int64)(mMaxOutputLatency * kSecondsToOSCunits + .5); int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; #endif for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = mWorld->mBufCounter; int32 *tch; // copy+touch inputs tch = inTouched; for (int k = 0; k < minInputs; ++k) { sc_jack_sample_t *src = inBuffers[k] + bufFramePos; float *dst = inBuses + k * bufFrames; for (int n = 0; n < bufFrames; ++n) { *dst++ = *src++; } *tch++ = bufCounter; } // run engine int64 schedTime; int64 nextTime = oscTime + oscInc; while ((schedTime = mScheduler.NextTime()) <= 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 >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; World_Run(world); // copy touched outputs tch = outTouched; for (int k = 0; k < minOutputs; ++k) { sc_jack_sample_t *dst = outBuffers[k] + bufFramePos; if (*tch++ == bufCounter) { float *src = outBuses + k * bufFrames; for (int n = 0; n < bufFrames; ++n) { *dst++ = *src++; } } else { for (int n = 0; n < bufFrames; ++n) { *dst++ = 0.0f; } } } // advance OSC time mOSCbuftime = oscTime = nextTime; } } catch (std::exception& exc) { scprintf("%s: exception in real time: %s\n", kJackDriverIdent, exc.what()); } catch (...) { scprintf("%s: unknown exception in real time\n", kJackDriverIdent); } double cpuUsage = (double)jack_cpu_load(mClient); mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU); if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) { mPeakCPU = cpuUsage; mPeakCounter = mMaxPeakCounter; } mAudioSync.Signal(); }