* use one static jobqueue for not getting problems with cached pointers
* check for job being NULL * improved performance of master mix git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1721 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -62,10 +62,10 @@ public:
|
||||
virtual ~fxMixer();
|
||||
|
||||
void mixToChannel( const sampleFrame * _buf, fx_ch_t _ch );
|
||||
void processChannel( fx_ch_t _ch );
|
||||
void processChannel( fx_ch_t _ch, sampleFrame * _buf = NULL );
|
||||
|
||||
void prepareMasterMix( void );
|
||||
const surroundSampleFrame * masterMix( void );
|
||||
void masterMix( sampleFrame * _buf );
|
||||
|
||||
|
||||
void clear( void );
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
|
||||
private:
|
||||
fxChannel * m_fxChannels[NumFxChannels+1]; // +1 = master
|
||||
surroundSampleFrame * m_out;
|
||||
|
||||
|
||||
friend class mixerWorkerThread;
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
|
||||
fxChannel::fxChannel( model * _parent ) :
|
||||
m_fxChain( NULL ),
|
||||
m_used( FALSE ),
|
||||
m_stillRunning( FALSE ),
|
||||
m_used( false ),
|
||||
m_stillRunning( false ),
|
||||
m_peakLeft( 0.0f ),
|
||||
m_peakRight( 0.0f ),
|
||||
m_buffer( new sampleFrame[engine::getMixer()->framesPerPeriod()] ),
|
||||
m_muteModel( FALSE, _parent ),
|
||||
m_muteModel( false, _parent ),
|
||||
m_volumeModel( 1.0, 0.0, 2.0, 0.01, _parent ),
|
||||
m_name(),
|
||||
m_lock()
|
||||
@@ -63,9 +63,7 @@ fxChannel::~fxChannel()
|
||||
|
||||
fxMixer::fxMixer() :
|
||||
journallingObject(),
|
||||
model( NULL ),
|
||||
m_out( new surroundSampleFrame[
|
||||
engine::getMixer()->framesPerPeriod()] )
|
||||
model( NULL )
|
||||
{
|
||||
for( int i = 0; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
@@ -80,7 +78,6 @@ fxMixer::fxMixer() :
|
||||
|
||||
fxMixer::~fxMixer()
|
||||
{
|
||||
delete[] m_out;
|
||||
for( int i = 0; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
delete m_fxChannels[i];
|
||||
@@ -92,7 +89,7 @@ fxMixer::~fxMixer()
|
||||
|
||||
void fxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
|
||||
{
|
||||
if( m_fxChannels[_ch]->m_muteModel.value() == FALSE )
|
||||
if( m_fxChannels[_ch]->m_muteModel.value() == false )
|
||||
{
|
||||
m_fxChannels[_ch]->m_lock.lock();
|
||||
sampleFrame * buf = m_fxChannels[_ch]->m_buffer;
|
||||
@@ -102,7 +99,7 @@ void fxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
|
||||
buf[f][0] += _buf[f][0];
|
||||
buf[f][1] += _buf[f][1];
|
||||
}
|
||||
m_fxChannels[_ch]->m_used = TRUE;
|
||||
m_fxChannels[_ch]->m_used = true;
|
||||
m_fxChannels[_ch]->m_lock.unlock();
|
||||
}
|
||||
}
|
||||
@@ -110,27 +107,29 @@ void fxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
|
||||
|
||||
|
||||
|
||||
void fxMixer::processChannel( fx_ch_t _ch )
|
||||
void fxMixer::processChannel( fx_ch_t _ch, sampleFrame * _buf )
|
||||
{
|
||||
if( m_fxChannels[_ch]->m_muteModel.value() == FALSE &&
|
||||
if( m_fxChannels[_ch]->m_muteModel.value() == false &&
|
||||
( m_fxChannels[_ch]->m_used ||
|
||||
m_fxChannels[_ch]->m_stillRunning ||
|
||||
_ch == 0 ) )
|
||||
{
|
||||
if( _buf == NULL )
|
||||
{
|
||||
_buf = m_fxChannels[_ch]->m_buffer;
|
||||
}
|
||||
const fpp_t f = engine::getMixer()->framesPerPeriod();
|
||||
m_fxChannels[_ch]->m_fxChain.startRunning();
|
||||
m_fxChannels[_ch]->m_stillRunning =
|
||||
m_fxChannels[_ch]->m_fxChain.processAudioBuffer(
|
||||
m_fxChannels[_ch]->m_buffer, f );
|
||||
_buf, f );
|
||||
m_fxChannels[_ch]->m_peakLeft =
|
||||
engine::getMixer()->peakValueLeft(
|
||||
m_fxChannels[_ch]->m_buffer, f ) *
|
||||
engine::getMixer()->peakValueLeft( _buf, f ) *
|
||||
m_fxChannels[_ch]->m_volumeModel.value();
|
||||
m_fxChannels[_ch]->m_peakRight =
|
||||
engine::getMixer()->peakValueRight(
|
||||
m_fxChannels[_ch]->m_buffer, f ) *
|
||||
engine::getMixer()->peakValueRight( _buf, f ) *
|
||||
m_fxChannels[_ch]->m_volumeModel.value();
|
||||
m_fxChannels[_ch]->m_used = TRUE;
|
||||
m_fxChannels[_ch]->m_used = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -151,49 +150,46 @@ void fxMixer::prepareMasterMix( void )
|
||||
|
||||
|
||||
|
||||
const surroundSampleFrame * fxMixer::masterMix( void )
|
||||
void fxMixer::masterMix( sampleFrame * _buf )
|
||||
{
|
||||
sampleFrame * buf = m_fxChannels[0]->m_buffer;
|
||||
const int fpp = engine::getMixer()->framesPerPeriod();
|
||||
memcpy( _buf, m_fxChannels[0]->m_buffer, sizeof( sampleFrame ) * fpp );
|
||||
|
||||
for( int i = 1; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
if( m_fxChannels[i]->m_used )
|
||||
{
|
||||
sampleFrame * ch_buf = m_fxChannels[i]->m_buffer;
|
||||
const float v = m_fxChannels[i]->m_volumeModel.value();
|
||||
for( f_cnt_t f = 0; f <
|
||||
engine::getMixer()->framesPerPeriod(); ++f )
|
||||
for( f_cnt_t f = 0; f < fpp; ++f )
|
||||
{
|
||||
buf[f][0] += ch_buf[f][0] * v;
|
||||
buf[f][1] += ch_buf[f][1] * v;
|
||||
_buf[f][0] += ch_buf[f][0] * v;
|
||||
_buf[f][1] += ch_buf[f][1] * v;
|
||||
}
|
||||
engine::getMixer()->clearAudioBuffer( ch_buf,
|
||||
engine::getMixer()->framesPerPeriod() );
|
||||
m_fxChannels[i]->m_used = FALSE;
|
||||
m_fxChannels[i]->m_used = false;
|
||||
}
|
||||
}
|
||||
|
||||
processChannel( 0 );
|
||||
processChannel( 0, _buf );
|
||||
|
||||
if( m_fxChannels[0]->m_muteModel.value() )
|
||||
{
|
||||
engine::getMixer()->clearAudioBuffer( m_out,
|
||||
engine::getMixer()->clearAudioBuffer( _buf,
|
||||
engine::getMixer()->framesPerPeriod() );
|
||||
return( m_out );
|
||||
return;
|
||||
}
|
||||
|
||||
const float v = m_fxChannels[0]->m_volumeModel.value();
|
||||
for( f_cnt_t f = 0; f < engine::getMixer()->framesPerPeriod(); ++f )
|
||||
{
|
||||
for( ch_cnt_t ch = 0; ch < SURROUND_CHANNELS; ++ch )
|
||||
{
|
||||
m_out[f][ch] = buf[f][ch%DEFAULT_CHANNELS] * v;
|
||||
}
|
||||
_buf[f][0] *= v;
|
||||
_buf[f][1] *= v;
|
||||
}
|
||||
|
||||
m_fxChannels[0]->m_peakLeft *= engine::getMixer()->masterGain();
|
||||
m_fxChannels[0]->m_peakRight *= engine::getMixer()->masterGain();
|
||||
|
||||
return( m_out );
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +201,7 @@ void fxMixer::clear()
|
||||
{
|
||||
m_fxChannels[i]->m_fxChain.clear();
|
||||
m_fxChannels[i]->m_volumeModel.setValue( 1.0f );
|
||||
m_fxChannels[i]->m_muteModel.setValue( FALSE );
|
||||
m_fxChannels[i]->m_muteModel.setValue( false );
|
||||
m_fxChannels[i]->m_name = ( i == 0 ) ?
|
||||
tr( "Master" ) : tr( "FX %1" ).arg( i );
|
||||
m_fxChannels[i]->m_volumeModel.setDisplayName(
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QWaitCondition>
|
||||
|
||||
#include <math.h>
|
||||
@@ -67,12 +66,13 @@
|
||||
#include "midi_dummy.h"
|
||||
|
||||
|
||||
static QVector<fx_ch_t> __fx_channel_jobs( NumFxChannels );
|
||||
|
||||
|
||||
|
||||
#define ALIGN_SIZE 64
|
||||
|
||||
void aligned_free( void * _buf )
|
||||
static void aligned_free( void * _buf )
|
||||
{
|
||||
if( _buf != NULL )
|
||||
{
|
||||
@@ -82,7 +82,7 @@ void aligned_free( void * _buf )
|
||||
}
|
||||
}
|
||||
|
||||
void * aligned_malloc( int _bytes )
|
||||
static void * aligned_malloc( int _bytes )
|
||||
{
|
||||
char *ptr,*ptr2,*aligned_ptr;
|
||||
int align_mask = ALIGN_SIZE- 1;
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
playHandle * playHandleJob;
|
||||
audioPort * audioPortJob;
|
||||
int effectChannelJob;
|
||||
void * job;
|
||||
volatile void * job;
|
||||
};
|
||||
|
||||
#if QT_VERSION >= 0x040400
|
||||
@@ -154,13 +154,14 @@ public:
|
||||
#endif
|
||||
} ;
|
||||
|
||||
static jobQueue s_jobQueue;
|
||||
|
||||
mixerWorkerThread( mixer * _mixer ) :
|
||||
QThread( _mixer ),
|
||||
m_quit( false ),
|
||||
m_mixer( _mixer ),
|
||||
m_queueReadySem( &m_mixer->m_queueReadySem ),
|
||||
m_workersDoneSem( &m_mixer->m_workersDoneSem ),
|
||||
m_jobQueue( NULL )
|
||||
m_workersDoneSem( &m_mixer->m_workersDoneSem )
|
||||
{
|
||||
start( QThread::TimeCriticalPriority );
|
||||
}
|
||||
@@ -169,11 +170,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void setJobQueue( jobQueue * _q )
|
||||
{
|
||||
m_jobQueue = _q;
|
||||
}
|
||||
|
||||
virtual void quit( void )
|
||||
{
|
||||
m_quit = true;
|
||||
@@ -189,15 +185,16 @@ private:
|
||||
{
|
||||
m_queueReadySem->acquire();
|
||||
for( jobQueueItems::iterator it =
|
||||
m_jobQueue->items.begin();
|
||||
it != m_jobQueue->items.end(); ++it )
|
||||
s_jobQueue.items.begin();
|
||||
it != s_jobQueue.items.end(); ++it )
|
||||
{
|
||||
#if QT_VERSION >= 0x040400
|
||||
if( it->done.fetchAndStoreRelaxed( 1 ) == 0 )
|
||||
if( it->done.fetchAndStoreRelaxed( 1 ) == 0 &&
|
||||
it->job != NULL )
|
||||
{
|
||||
#else
|
||||
m_jobQueue->lock.lock();
|
||||
if( !it->done )
|
||||
if( !it->done && it->job != NULL )
|
||||
{
|
||||
it->done = true;
|
||||
m_jobQueue->lock.unlock();
|
||||
@@ -242,29 +239,28 @@ private:
|
||||
mixer * m_mixer;
|
||||
QSemaphore * m_queueReadySem;
|
||||
QSemaphore * m_workersDoneSem;
|
||||
jobQueue * m_jobQueue;
|
||||
volatile jobQueue * m_jobQueue;
|
||||
|
||||
} ;
|
||||
|
||||
mixerWorkerThread::jobQueue mixerWorkerThread::s_jobQueue;
|
||||
|
||||
|
||||
#define FILL_JOB_QUEUE(_jq,_vec_type,_vec,_job_type,_condition) \
|
||||
#define FILL_JOB_QUEUE(_vec_type,_vec,_job_type,_condition) \
|
||||
mixerWorkerThread::s_jobQueue.items.clear(); \
|
||||
for( _vec_type::iterator it = _vec.begin(); \
|
||||
it != _vec.end(); ++it ) \
|
||||
{ \
|
||||
if( _condition ) \
|
||||
{ \
|
||||
_jq.items.push_back( \
|
||||
mixerWorkerThread::s_jobQueue.items. \
|
||||
push_back( \
|
||||
mixerWorkerThread::jobQueueItem( _job_type, \
|
||||
(void *)*it ) );\
|
||||
} \
|
||||
}
|
||||
|
||||
#define DISTRIBUTE_JOB_QUEUE(_jq) \
|
||||
for( int i = 0; i < m_numWorkers; ++i ) \
|
||||
{ \
|
||||
m_workers[i]->setJobQueue( &_jq ); \
|
||||
} \
|
||||
#define START_JOBS() \
|
||||
m_queueReadySem.release( m_numWorkers ); \
|
||||
|
||||
#define WAIT_FOR_JOBS() \
|
||||
@@ -300,6 +296,11 @@ mixer::mixer( void ) :
|
||||
clearAudioBuffer( m_inputBuffer[i], m_inputBufferSize[i] );
|
||||
}
|
||||
|
||||
for( int i = 1; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
__fx_channel_jobs[i-1] = (fx_ch_t) i;
|
||||
}
|
||||
|
||||
// just rendering?
|
||||
if( !engine::hasGUI() )
|
||||
{
|
||||
@@ -309,7 +310,8 @@ mixer::mixer( void ) :
|
||||
else if( configManager::inst()->value( "mixer", "framesperaudiobuffer"
|
||||
).toInt() >= 32 )
|
||||
{
|
||||
m_framesPerPeriod = configManager::inst()->value( "mixer",
|
||||
m_framesPerPeriod =
|
||||
(fpp_t) configManager::inst()->value( "mixer",
|
||||
"framesperaudiobuffer" ).toInt();
|
||||
|
||||
if( m_framesPerPeriod > DEFAULT_BUFFER_SIZE )
|
||||
@@ -368,12 +370,12 @@ mixer::~mixer()
|
||||
{
|
||||
// distribute an empty job-queue so that worker-threads
|
||||
// get out of their processing-loop
|
||||
mixerWorkerThread::jobQueue jq;
|
||||
mixerWorkerThread::s_jobQueue.items.clear();
|
||||
for( int w = 0; w < m_numWorkers; ++w )
|
||||
{
|
||||
m_workers[w]->quit();
|
||||
}
|
||||
DISTRIBUTE_JOB_QUEUE(jq);
|
||||
START_JOBS();
|
||||
for( int w = 0; w < m_numWorkers; ++w )
|
||||
{
|
||||
m_workers[w]->wait( 500 );
|
||||
@@ -506,7 +508,7 @@ void mixer::pushInputFrames( sampleFrame * _ab, const f_cnt_t _frames )
|
||||
|
||||
if( frames + _frames > size )
|
||||
{
|
||||
size = tMax( size * 2, frames + _frames );
|
||||
size = qMax( size * 2, frames + _frames );
|
||||
sampleFrame * ab = new sampleFrame[ size ];
|
||||
memcpy( ab, buf, frames * sizeof( sampleFrame ) );
|
||||
delete [] buf;
|
||||
@@ -604,11 +606,10 @@ const surroundSampleFrame * mixer::renderNextBuffer( void )
|
||||
lockPlayHandles();
|
||||
if( m_multiThreaded )
|
||||
{
|
||||
mixerWorkerThread::jobQueue jq;
|
||||
FILL_JOB_QUEUE(jq,playHandleVector,m_playHandles,
|
||||
FILL_JOB_QUEUE(playHandleVector,m_playHandles,
|
||||
mixerWorkerThread::PlayHandle,
|
||||
!( *it )->done());
|
||||
DISTRIBUTE_JOB_QUEUE(jq);
|
||||
START_JOBS();
|
||||
WAIT_FOR_JOBS();
|
||||
}
|
||||
else
|
||||
@@ -649,21 +650,14 @@ const surroundSampleFrame * mixer::renderNextBuffer( void )
|
||||
|
||||
if( m_multiThreaded )
|
||||
{
|
||||
mixerWorkerThread::jobQueue jq;
|
||||
FILL_JOB_QUEUE(jq,QVector<audioPort*>,m_audioPorts,
|
||||
FILL_JOB_QUEUE(QVector<audioPort*>,m_audioPorts,
|
||||
mixerWorkerThread::AudioPortEffects,1);
|
||||
DISTRIBUTE_JOB_QUEUE(jq);
|
||||
START_JOBS();
|
||||
WAIT_FOR_JOBS();
|
||||
|
||||
jq.items.clear();
|
||||
QVector<fx_ch_t> fx_channels( NumFxChannels );
|
||||
for( int i = 1; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
fx_channels[i-1] = i;
|
||||
}
|
||||
FILL_JOB_QUEUE(jq,QVector<fx_ch_t>,fx_channels,
|
||||
FILL_JOB_QUEUE(QVector<fx_ch_t>,__fx_channel_jobs,
|
||||
mixerWorkerThread::EffectChannel,1);
|
||||
DISTRIBUTE_JOB_QUEUE(jq);
|
||||
START_JOBS();
|
||||
WAIT_FOR_JOBS();
|
||||
}
|
||||
else
|
||||
@@ -686,13 +680,11 @@ const surroundSampleFrame * mixer::renderNextBuffer( void )
|
||||
}
|
||||
for( int i = 1; i < NumFxChannels+1; ++i )
|
||||
{
|
||||
engine::getFxMixer()->processChannel( i );
|
||||
engine::getFxMixer()->processChannel(
|
||||
(fx_ch_t) i );
|
||||
}
|
||||
}
|
||||
const surroundSampleFrame * buf =
|
||||
engine::getFxMixer()->masterMix();
|
||||
memcpy( m_writeBuf, buf, m_framesPerPeriod *
|
||||
sizeof( surroundSampleFrame ) );
|
||||
engine::getFxMixer()->masterMix( m_writeBuf );
|
||||
}
|
||||
|
||||
unlock();
|
||||
@@ -744,12 +736,12 @@ void mixer::bufferToPort( const sampleFrame * _buf,
|
||||
stereoVolumeVector _vv,
|
||||
audioPort * _port )
|
||||
{
|
||||
const fpp_t start_frame = _offset % m_framesPerPeriod;
|
||||
fpp_t end_frame = start_frame + _frames;
|
||||
const fpp_t loop1_frame = tMin( end_frame, m_framesPerPeriod );
|
||||
const int start_frame = _offset % m_framesPerPeriod;
|
||||
int end_frame = start_frame + _frames;
|
||||
const int loop1_frame = qMin<int>( end_frame, m_framesPerPeriod );
|
||||
|
||||
_port->lockFirstBuffer();
|
||||
for( fpp_t frame = start_frame; frame < loop1_frame; ++frame )
|
||||
for( int frame = start_frame; frame < loop1_frame; ++frame )
|
||||
{
|
||||
for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
|
||||
{
|
||||
@@ -763,9 +755,9 @@ void mixer::bufferToPort( const sampleFrame * _buf,
|
||||
_port->lockSecondBuffer();
|
||||
if( end_frame > m_framesPerPeriod )
|
||||
{
|
||||
fpp_t frames_done = m_framesPerPeriod - start_frame;
|
||||
end_frame = tMin( end_frame -= m_framesPerPeriod,
|
||||
m_framesPerPeriod );
|
||||
const int frames_done = m_framesPerPeriod - start_frame;
|
||||
end_frame -= m_framesPerPeriod;
|
||||
end_frame = qMin<int>( end_frame, m_framesPerPeriod );
|
||||
for( fpp_t frame = 0; frame < end_frame; ++frame )
|
||||
{
|
||||
for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS;
|
||||
@@ -798,7 +790,7 @@ void mixer::clearAudioBuffer( sampleFrame * _ab, const f_cnt_t _frames,
|
||||
|
||||
|
||||
|
||||
#ifndef DISABLE_SURROUND
|
||||
#ifndef LMMS_DISABLE_SURROUND
|
||||
void mixer::clearAudioBuffer( surroundSampleFrame * _ab, const f_cnt_t _frames,
|
||||
const f_cnt_t _offset )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user