void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) { lockInputFrames(); f_cnt_t frames = m_inputBufferFrames[ m_inputBufferWrite ]; int size = m_inputBufferSize[ m_inputBufferWrite ]; sampleFrame * buf = m_inputBuffer[ m_inputBufferWrite ]; if( frames + _frames > size ) { size = qMax( size * 2, frames + _frames ); sampleFrame * ab = new sampleFrame[ size ]; memcpy( ab, buf, frames * sizeof( sampleFrame ) ); delete [] buf; m_inputBufferSize[ m_inputBufferWrite ] = size; m_inputBuffer[ m_inputBufferWrite ] = ab; buf = ab; } memcpy( &buf[ frames ], _ab, _frames * sizeof( sampleFrame ) ); m_inputBufferFrames[ m_inputBufferWrite ] += _frames; unlockInputFrames(); }
void Mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames ) { lockInputFrames(); f_cnt_t frames = m_inputBufferFrames[ m_inputBufferWrite ]; int size = m_inputBufferSize[ m_inputBufferWrite ]; sampleFrame * buf = m_inputBuffer[ m_inputBufferWrite ]; if( frames + _frames > size ) { size = qMax( size * 2, frames + _frames ); sampleFrame * ab = CPU::allocFrames( size ); CPU::memCpy( ab, buf, frames * sizeof( sampleFrame ) ); CPU::freeFrames( buf ); m_inputBufferSize[ m_inputBufferWrite ] = size; m_inputBuffer[ m_inputBufferWrite ] = ab; buf = ab; } CPU::memCpy( &buf[ frames ], _ab, _frames * sizeof( sampleFrame ) ); m_inputBufferFrames[ m_inputBufferWrite ] += _frames; unlockInputFrames(); }
const surroundSampleFrame * Mixer::renderNextBuffer() { m_profiler.startPeriod(); static Song::PlayPos last_metro_pos = -1; Song *song = Engine::getSong(); Song::PlayModes currentPlayMode = song->playMode(); Song::PlayPos p = song->getPlayPos( currentPlayMode ); bool playModeSupportsMetronome = currentPlayMode == Song::Mode_PlayPattern || currentPlayMode == Song::Mode_PlaySong || currentPlayMode == Song::Mode_PlayBB; if( playModeSupportsMetronome && m_metronomeActive && !song->isExporting() && p != last_metro_pos ) { tick_t ticksPerTact = MidiTime::ticksPerTact(); if ( p.getTicks() % (ticksPerTact / 1 ) == 0 ) { addPlayHandle( new SamplePlayHandle( "misc/metronome02.ogg" ) ); } else if ( p.getTicks() % (ticksPerTact / song->getTimeSigModel().getNumerator() ) == 0 ) { addPlayHandle( new SamplePlayHandle( "misc/metronome01.ogg" ) ); } last_metro_pos = p; } lockInputFrames(); // swap buffer m_inputBufferWrite = ( m_inputBufferWrite + 1 ) % 2; m_inputBufferRead = ( m_inputBufferRead + 1 ) % 2; // clear new write buffer m_inputBufferFrames[ m_inputBufferWrite ] = 0; unlockInputFrames(); // remove all play-handles that have to be deleted and delete // them if they still exist... // maybe this algorithm could be optimized... lockPlayHandleRemoval(); ConstPlayHandleList::Iterator it_rem = m_playHandlesToRemove.begin(); while( it_rem != m_playHandlesToRemove.end() ) { PlayHandleList::Iterator it = qFind( m_playHandles.begin(), m_playHandles.end(), *it_rem ); if( it != m_playHandles.end() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } else delete *it; m_playHandles.erase( it ); } it_rem = m_playHandlesToRemove.erase( it_rem ); } unlockPlayHandleRemoval(); // now we have to make sure no other thread does anything bad // while we're acting... lock(); // rotate buffers m_writeBuffer = ( m_writeBuffer + 1 ) % m_poolDepth; m_readBuffer = ( m_readBuffer + 1 ) % m_poolDepth; m_writeBuf = m_bufferPool[m_writeBuffer]; m_readBuf = m_bufferPool[m_readBuffer]; // clear last audio-buffer clearAudioBuffer( m_writeBuf, m_framesPerPeriod ); // prepare master mix (clear internal buffers etc.) FxMixer * fxMixer = Engine::fxMixer(); fxMixer->prepareMasterMix(); // create play-handles for new notes, samples etc. song->processNextBuffer(); // add all play-handles that have to be added m_playHandleMutex.lock(); m_playHandles += m_newPlayHandles; m_newPlayHandles.clear(); m_playHandleMutex.unlock(); // STAGE 1: run and render all play handles lockPlayHandleRemoval(); MixerWorkerThread::fillJobQueue<PlayHandleList>( m_playHandles ); MixerWorkerThread::startAndWaitForJobs(); // removed all play handles which are done for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ) { if( ( *it )->affinityMatters() && ( *it )->affinity() != QThread::currentThread() ) { ++it; continue; } if( ( *it )->isFinished() ) { ( *it )->audioPort()->removePlayHandle( ( *it ) ); if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) { NotePlayHandleManager::release( (NotePlayHandle*) *it ); } else delete *it; it = m_playHandles.erase( it ); } else { ++it; } } unlockPlayHandleRemoval(); // STAGE 2: process effects of all instrument- and sampletracks MixerWorkerThread::fillJobQueue<QVector<AudioPort *> >( m_audioPorts ); MixerWorkerThread::startAndWaitForJobs(); // STAGE 3: do master mix in FX mixer fxMixer->masterMix( m_writeBuf ); unlock(); emit nextAudioBuffer(); // and trigger LFOs EnvelopeAndLfoParameters::instances()->trigger(); Controller::triggerFrameCounter(); AutomatableModel::incrementPeriodCounter(); // refresh buffer pool BufferManager::refresh(); m_profiler.finishPeriod( processingSampleRate(), m_framesPerPeriod ); return m_readBuf; }
sampleFrameA * Mixer::renderNextBuffer() { MicroTimer timer; static song::playPos last_metro_pos = -1; FxMixer * fxm = engine::fxMixer(); song::playPos p = engine::getSong()->getPlayPos( song::Mode_PlayPattern ); if( engine::getSong()->playMode() == song::Mode_PlayPattern && engine::getPianoRoll()->isRecording() == true && p != last_metro_pos && p.getTicks() % (DefaultTicksPerTact / 4 ) == 0 ) { addPlayHandle( new samplePlayHandle( "misc/metronome01.ogg" ) ); last_metro_pos = p; } lockInputFrames(); // swap buffer m_inputBufferWrite = ( m_inputBufferWrite + 1 ) % 2; m_inputBufferRead = ( m_inputBufferRead + 1 ) % 2; // clear new write buffer m_inputBufferFrames[ m_inputBufferWrite ] = 0; unlockInputFrames(); // now we have to make sure no other thread does anything bad // while we're acting... lock(); // remove all play-handles that have to be deleted and delete // them if they still exist... // maybe this algorithm could be optimized... ConstPlayHandleList::Iterator it_rem = m_playHandlesToRemove.begin(); while( it_rem != m_playHandlesToRemove.end() ) { PlayHandleList::Iterator it = qFind( m_playHandles.begin(), m_playHandles.end(), *it_rem ); if( it != m_playHandles.end() ) { delete *it; m_playHandles.erase( it ); } it_rem = m_playHandlesToRemove.erase( it_rem ); } // rotate buffers m_writeBuffer = ( m_writeBuffer + 1 ) % m_poolDepth; m_readBuffer = ( m_readBuffer + 1 ) % m_poolDepth; m_writeBuf = m_bufferPool[m_writeBuffer]; m_readBuf = m_bufferPool[m_readBuffer]; // clear last audio-buffer clearAudioBuffer( m_writeBuf, m_framesPerPeriod ); // prepare master mix (clear internal buffers etc.) fxm->prepareMasterMix(); // create play-handles for new notes, samples etc. engine::getSong()->processNextBuffer(); // STAGE 1: run and render all play handles MixerWorkerThread::fillJobQueue<PlayHandleList>( m_playHandles ); MixerWorkerThread::startAndWaitForJobs(); // removed all play handles which are done for( PlayHandleList::Iterator it = m_playHandles.begin(); it != m_playHandles.end(); ) { if( ( *it )->affinityMatters() && ( *it )->affinity() != QThread::currentThread() ) { ++it; continue; } if( ( *it )->done() ) { delete *it; it = m_playHandles.erase( it ); } else { ++it; } } // STAGE 2: process effects of all instrument- and sampletracks MixerWorkerThread::fillJobQueue<QVector<AudioPort *> >( m_audioPorts ); MixerWorkerThread::startAndWaitForJobs(); // STAGE 3: do master mix in FX mixer fxm->masterMix( m_writeBuf ); unlock(); emit nextAudioBuffer(); // and trigger LFOs EnvelopeAndLfoParameters::instances()->trigger(); Controller::triggerFrameCounter(); const float new_cpu_load = timer.elapsed() / 10000.0f * processingSampleRate() / m_framesPerPeriod; m_cpuLoad = tLimit( (int) ( new_cpu_load * 0.1f + m_cpuLoad * 0.9f ), 0, 100 ); return m_readBuf; }