Esempio n. 1
0
Mixer::Mixer() :
	m_framesPerPeriod( qBound<int>( 32,
					configManager::inst()->value( "mixer", "framesperaudiobuffer" ).toInt(),
					DEFAULT_BUFFER_SIZE ) ),
	m_workingBuf( NULL ),
	m_inputBufferRead( 0 ),
	m_inputBufferWrite( 1 ),
	m_readBuf( NULL ),
	m_writeBuf( NULL ),
	m_cpuLoad( 0 ),
	m_workers(),
	m_numWorkers( QThread::idealThreadCount()-1 ),
	m_queueReadyWaitCond(),
	m_masterGain( 1.0f ),
	m_audioOutputContext( NULL ),
	m_defaultAudioOutputContext( NULL ),
	m_globalMutex( QMutex::Recursive )
{
	for( int i = 0; i < 2; ++i )
	{
		m_inputBufferFrames[i] = 0;
		m_inputBufferSize[i] = DEFAULT_BUFFER_SIZE * 100;
		m_inputBuffer[i] = CPU::allocFrames(
						DEFAULT_BUFFER_SIZE * 100 );
		clearAudioBuffer( m_inputBuffer[i], m_inputBufferSize[i] );
	}

	m_workingBuf = CPU::allocFrames( m_framesPerPeriod );
	for( Uint8 i = 0; i < 3; i++ )
	{
		m_readBuf = CPU::allocFrames( m_framesPerPeriod );
		clearAudioBuffer( m_readBuf, m_framesPerPeriod );
		m_bufferPool.push_back( m_readBuf );
	}

	for( int i = 0; i < m_numWorkers+1; ++i )
	{
		MixerWorkerThread * wt = new MixerWorkerThread( this );
		if( i < m_numWorkers )
		{
			wt->start( QThread::TimeCriticalPriority );
		}
		m_workers.push_back( wt );
	}

	m_poolDepth = 2;
	m_readBuffer = 0;
	m_writeBuffer = 1;

	// initialize default AudioOutputContext
	m_defaultAudioOutputContext = new AudioOutputContext( this, NULL,
							AudioOutputContext::QualitySettings::Preset_Draft );
	m_audioOutputContext = m_defaultAudioOutputContext;
}
Esempio n. 2
0
Mixer::Mixer( bool renderOnly ) :
	m_framesPerPeriod( DEFAULT_BUFFER_SIZE ),
	m_workingBuf( NULL ),
	m_inputBufferRead( 0 ),
	m_inputBufferWrite( 1 ),
	m_readBuf( NULL ),
	m_writeBuf( NULL ),
	m_workers(),
	m_numWorkers( QThread::idealThreadCount()-1 ),
	m_queueReadyWaitCond(),
	m_qualitySettings( qualitySettings::Mode_Draft ),
	m_masterGain( 1.0f ),
	m_audioDev( NULL ),
	m_oldAudioDev( NULL ),
	m_globalMutex( QMutex::Recursive ),
	m_profiler(),
	m_metronomeActive(false)
{
	for( int i = 0; i < 2; ++i )
	{
		m_inputBufferFrames[i] = 0;
		m_inputBufferSize[i] = DEFAULT_BUFFER_SIZE * 100;
		m_inputBuffer[i] = new sampleFrame[ DEFAULT_BUFFER_SIZE * 100 ];
		clearAudioBuffer( m_inputBuffer[i], m_inputBufferSize[i] );
	}

	// determine FIFO size and number of frames per period
	int fifoSize = 1;

	// if not only rendering (that is, using the GUI), load the buffer
	// size from user configuration
	if( renderOnly == false )
	{
		m_framesPerPeriod = 
			( fpp_t ) ConfigManager::inst()->
				value( "mixer", "framesperaudiobuffer" ).toInt();

		// if the value read from user configuration is not set or
		// lower than the minimum allowed, use the default value and
		// save it to the configuration
		if( m_framesPerPeriod < MINIMUM_BUFFER_SIZE )
		{
			ConfigManager::inst()->setValue( "mixer",
						"framesperaudiobuffer",
						QString::number( DEFAULT_BUFFER_SIZE ) );

			m_framesPerPeriod = DEFAULT_BUFFER_SIZE;
		}
		else if( m_framesPerPeriod > DEFAULT_BUFFER_SIZE )
		{
			fifoSize = m_framesPerPeriod / DEFAULT_BUFFER_SIZE;
			m_framesPerPeriod = DEFAULT_BUFFER_SIZE;
		}
	}

	// allocte the FIFO from the determined size
	m_fifo = new fifo( fifoSize );

	// now that framesPerPeriod is fixed initialize global BufferManager
	BufferManager::init( m_framesPerPeriod );

	m_workingBuf = (sampleFrame*) MemoryHelper::alignedMalloc( m_framesPerPeriod *
							sizeof( sampleFrame ) );
	for( int i = 0; i < 3; i++ )
	{
		m_readBuf = (surroundSampleFrame*)
			MemoryHelper::alignedMalloc( m_framesPerPeriod *
						sizeof( surroundSampleFrame ) );

		clearAudioBuffer( m_readBuf, m_framesPerPeriod );
		m_bufferPool.push_back( m_readBuf );
	}

	for( int i = 0; i < m_numWorkers+1; ++i )
	{
		MixerWorkerThread * wt = new MixerWorkerThread( this );
		if( i < m_numWorkers )
		{
			wt->start( QThread::TimeCriticalPriority );
		}
		m_workers.push_back( wt );
	}

	m_poolDepth = 2;
	m_readBuffer = 0;
	m_writeBuffer = 1;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
Mixer::Mixer() :
	m_framesPerPeriod( DEFAULT_BUFFER_SIZE ),
	m_workingBuf( NULL ),
	m_inputBufferRead( 0 ),
	m_inputBufferWrite( 1 ),
	m_readBuf( NULL ),
	m_writeBuf( NULL ),
	m_workers(),
	m_numWorkers( QThread::idealThreadCount()-1 ),
	m_queueReadyWaitCond(),
	m_qualitySettings( qualitySettings::Mode_Draft ),
	m_masterGain( 1.0f ),
	m_audioDev( NULL ),
	m_oldAudioDev( NULL ),
	m_globalMutex( QMutex::Recursive ),
	m_profiler()
{
	for( int i = 0; i < 2; ++i )
	{
		m_inputBufferFrames[i] = 0;
		m_inputBufferSize[i] = DEFAULT_BUFFER_SIZE * 100;
		m_inputBuffer[i] = new sampleFrame[ DEFAULT_BUFFER_SIZE * 100 ];
		clearAudioBuffer( m_inputBuffer[i], m_inputBufferSize[i] );
	}

	// just rendering?
	if( !Engine::hasGUI() )
	{
		m_framesPerPeriod = DEFAULT_BUFFER_SIZE;
		m_fifo = new fifo( 1 );
	}
	else if( ConfigManager::inst()->value( "mixer", "framesperaudiobuffer"
						).toInt() >= 32 )
	{
		m_framesPerPeriod =
			(fpp_t) ConfigManager::inst()->value( "mixer",
					"framesperaudiobuffer" ).toInt();

		if( m_framesPerPeriod > DEFAULT_BUFFER_SIZE )
		{
			m_fifo = new fifo( m_framesPerPeriod
							/ DEFAULT_BUFFER_SIZE );
			m_framesPerPeriod = DEFAULT_BUFFER_SIZE;
		}
		else
		{
			m_fifo = new fifo( 1 );
		}
	}
	else
	{
		ConfigManager::inst()->setValue( "mixer",
							"framesperaudiobuffer",
				QString::number( m_framesPerPeriod ) );
		m_fifo = new fifo( 1 );
	}

	// now that framesPerPeriod is fixed initialize global BufferManager
	BufferManager::init( m_framesPerPeriod );

	m_workingBuf = (sampleFrame*) MemoryHelper::alignedMalloc( m_framesPerPeriod *
							sizeof( sampleFrame ) );
	for( int i = 0; i < 3; i++ )
	{
		m_readBuf = (surroundSampleFrame*)
			MemoryHelper::alignedMalloc( m_framesPerPeriod *
						sizeof( surroundSampleFrame ) );

		clearAudioBuffer( m_readBuf, m_framesPerPeriod );
		m_bufferPool.push_back( m_readBuf );
	}

	for( int i = 0; i < m_numWorkers+1; ++i )
	{
		MixerWorkerThread * wt = new MixerWorkerThread( this );
		if( i < m_numWorkers )
		{
			wt->start( QThread::TimeCriticalPriority );
		}
		m_workers.push_back( wt );
	}

	m_poolDepth = 2;
	m_readBuffer = 0;
	m_writeBuffer = 1;
}
Esempio n. 5
0
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;
}