void MonitorNode::initialize() { if( ! mWindowSize ) mWindowSize = getFramesPerBlock(); for( size_t ch = 0; ch < getNumChannels(); ch++ ) mRingBuffers.emplace_back( mWindowSize * mRingBufferPaddingFactor ); mCopiedBuffer = Buffer( mWindowSize, getNumChannels() ); }
void Node::setupProcessWithSumming() { CI_ASSERT( getContext() ); mProcessInPlace = false; size_t framesPerBlock = getFramesPerBlock(); mInternalBuffer.setSize( framesPerBlock, mNumChannels ); mSummingBuffer.setSize( framesPerBlock, mNumChannels ); }
void DelayNode::setMaxDelaySeconds( float seconds ) { size_t delayFrames = lroundf( seconds * getSampleRate() ); size_t delayBufferFrames = max( getFramesPerBlock(), delayFrames ) + 1; mDelayBuffer.setSize( delayBufferFrames, getNumChannels() ); mMaxDelaySeconds = seconds; mWriteIndex = 0; }
void Context::addAutoPulledNode( const NodeRef &node ) { mAutoPulledNodes.insert( node ); mAutoPullRequired = true; mAutoPullCacheDirty = true; // if not done already, allocate a buffer for auto-pulling that is large enough for stereo processing size_t framesPerBlock = getFramesPerBlock(); if( mAutoPullBuffer.getNumFrames() < framesPerBlock ) mAutoPullBuffer.setSize( framesPerBlock, 2 ); }
void Context::schedule( double when, const NodeRef &node, bool enable, const std::function<void ()> &func ) { const uint64_t framesPerBlock = (uint64_t)getFramesPerBlock(); uint64_t eventFrameThreshold = timeToFrame( when, getSampleRate() ); // Place the threshold back one block so we can process the block first, guarding against wrap around if( eventFrameThreshold >= framesPerBlock ) eventFrameThreshold -= framesPerBlock; lock_guard<mutex> lock( mMutex ); mScheduledEvents.push_back( ScheduledEvent( eventFrameThreshold, node, enable, func ) ); }
void MonitorNode::initialize() { if( ! mWindowSize ) mWindowSize = getFramesPerBlock(); else if( ! isPowerOf2( mWindowSize ) ) mWindowSize = nextPowerOf2( static_cast<uint32_t>( mWindowSize ) ); for( size_t ch = 0; ch < getNumChannels(); ch++ ) mRingBuffers.emplace_back( mWindowSize * mRingBufferPaddingFactor ); mCopiedBuffer = Buffer( mWindowSize, getNumChannels() ); }
void Node::initializeImpl() { if( mInitialized ) return; if( mProcessInPlace && ! supportsProcessInPlace() ) setupProcessWithSumming(); mProcessFramesRange.first = 0; mProcessFramesRange.second = getFramesPerBlock(); initialize(); mInitialized = true; if( mAutoEnabled ) enable(); }
void Context::cancelScheduledEvents( const NodeRef &node ) { lock_guard<mutex> lock( mMutex ); for( auto eventIt = mScheduledEvents.begin(); eventIt != mScheduledEvents.end(); ++eventIt ) { if( eventIt->mNode == node ) { // reset process frame range to an entire block auto &range = eventIt->mNode->mProcessFramesRange; range.first = 0; range.second = getFramesPerBlock(); eventIt->mNode->mEventScheduled = false; mScheduledEvents.erase( eventIt ); break; } } }
void Context::scheduleEvent( double when, const NodeRef &node, bool callFuncBeforeProcess, const std::function<void ()> &func ) { const uint64_t framesPerBlock = (uint64_t)getFramesPerBlock(); uint64_t eventFrameThreshold = std::max( mNumProcessedFrames.load(), timeToFrame( when, static_cast<double>( getSampleRate() ) ) ); // Place the threshold back one block so we can process the block first, guarding against wrap around if( eventFrameThreshold >= framesPerBlock ) eventFrameThreshold -= framesPerBlock; // TODO: support multiple events, at the moment only supporting one per node. if( node->mEventScheduled ) { cancelScheduledEvents( node ); } lock_guard<mutex> lock( mMutex ); node->mEventScheduled = true; mScheduledEvents.push_back( ScheduledEvent( eventFrameThreshold, node, callFuncBeforeProcess, func ) ); }
void GenPulseNode::initialize() { GenNode::initialize(); mBuffer2.setNumFrames( getFramesPerBlock() ); size_t sampleRate = getSampleRate(); bool needsFill = false; if( ! mWaveTable ) { mWaveTable.reset( new WaveTable2d( sampleRate, DEFAULT_TABLE_SIZE, DEFAULT_BANDLIMITED_TABLES ) ); needsFill = true; } else if( sampleRate != mWaveTable->getSampleRate() ) needsFill = true; if( needsFill ) mWaveTable->fillBandlimited( WaveformType::SAWTOOTH ); }
void Context::postProcessScheduledEvents() { for( auto eventIt = mScheduledEvents.begin(); eventIt != mScheduledEvents.end(); /* */ ) { if( eventIt->mFinished ) { if( ! eventIt->mEnable ) eventIt->mFunc(); // reset process frame range auto &range = eventIt->mNode->mProcessFramesRange; range.first = 0; range.second = getFramesPerBlock(); eventIt = mScheduledEvents.erase( eventIt ); } else ++eventIt; } }
void Context::postProcessScheduledEvents() { for( auto eventIt = mScheduledEvents.begin(); eventIt != mScheduledEvents.end(); /* */ ) { if( eventIt->mProcessingEvent ) { if( ! eventIt->mCallFuncBeforeProcess ) eventIt->mFunc(); // reset process frame range to an entire block auto &range = eventIt->mNode->mProcessFramesRange; range.first = 0; range.second = getFramesPerBlock(); eventIt->mNode->mEventScheduled = false; eventIt = mScheduledEvents.erase( eventIt ); } else ++eventIt; } }
// note: we should be synchronized with mMutex by the OutputDeviceNode impl, so mScheduledEvents is safe to modify void Context::preProcessScheduledEvents() { const uint64_t framesPerBlock = (uint64_t)getFramesPerBlock(); const uint64_t numProcessedFrames = mNumProcessedFrames; for( auto &event : mScheduledEvents ) { if( numProcessedFrames >= event.mEventFrameThreshold ) { event.mProcessingEvent = true; uint64_t frameOffset = numProcessedFrames - event.mEventFrameThreshold; if( event.mCallFuncBeforeProcess ) { event.mNode->mProcessFramesRange.first = size_t( framesPerBlock - frameOffset ); event.mFunc(); } else { // set the process range but don't call its function until postProcess() event.mNode->mProcessFramesRange.second = (size_t)frameOffset; } } } }
void Context::incrementFrameCount() { mNumProcessedFrames += getFramesPerBlock(); }
size_t DeviceManagerPulseAudio::getFramesPerBlockHardware( const DeviceRef &device ) { // TODO: Fix this - a temp solution for now. return getFramesPerBlock( device ); }