Mixer sends work in the backend

The backend code of mixer uses mixer sends to compute effects.
This commit is contained in:
Andrew Kelley
2009-09-15 17:53:59 -07:00
parent 3c18e436cd
commit 45c4b7b824
3 changed files with 128 additions and 66 deletions

View File

@@ -40,8 +40,10 @@ struct FxChannel
~FxChannel();
EffectChain m_fxChain;
bool m_used;
// set to true if any effect in the channel is enabled and running
bool m_stillRunning;
float m_peakLeft;
float m_peakRight;
sampleFrame * m_buffer;
@@ -50,6 +52,11 @@ struct FxChannel
QString m_name;
QMutex m_lock;
// pointers to other channels that this one sends to
QVector<fx_ch_t> m_sends;
// pointers to other channels that send to this one
QVector<fx_ch_t> m_receives;
} ;
@@ -86,11 +93,20 @@ public:
return NULL;
}
// make the output of channel fromChannel go to the input of channel toChannel
void createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel);
// delete the connection made by createChannelSend
void deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel);
// does fromChannel send its output to the input of toChannel?
bool channelSendsTo(fx_ch_t fromChannel, fx_ch_t toChannel);
private:
FxChannel * m_fxChannels[NumFxChannels+1]; // +1 = master
friend class mixerWorkerThread;
friend class FxMixerView;

View File

@@ -33,7 +33,6 @@
FxChannel::FxChannel( Model * _parent ) :
m_fxChain( NULL ),
m_used( false ),
m_stillRunning( false ),
m_peakLeft( 0.0f ),
m_peakRight( 0.0f ),
@@ -64,10 +63,19 @@ FxMixer::FxMixer() :
JournallingObject(),
Model( NULL )
{
for( int i = 0; i < NumFxChannels+1; ++i )
// create master channel
m_fxChannels[0] = new FxChannel(this);
// create the rest of the channels
for( int i = 1; i < NumFxChannels+1; ++i )
{
// create new channel
m_fxChannels[i] = new FxChannel( this );
// send the channel into master
createChannelSend(i, 0);
}
// reset name etc.
clear();
}
@@ -85,6 +93,64 @@ FxMixer::~FxMixer()
void FxMixer::createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel)
{
// first make sure the send doesn't already exist
if( ! channelSendsTo(fromChannel, toChannel) )
{
// add to from's sends
m_fxChannels[fromChannel]->m_sends.push_back(toChannel);
// add to to's receives
m_fxChannels[toChannel]->m_receives.push_back(fromChannel);
}
}
// delete the connection made by createChannelSend
void FxMixer::deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel)
{
// delete the send
FxChannel * from = m_fxChannels[fromChannel];
FxChannel * to = m_fxChannels[toChannel];
// find and delete the send entry
for(int i=0; i<from->m_sends.size(); ++i) {
if( from->m_sends[i] == toChannel )
{
// delete this index
from->m_sends.remove(i);
break;
}
}
// find and delete the receive entry
for(int i=0; i<to->m_receives.size(); ++i)
{
if( to->m_receives[i] == fromChannel )
{
// delete this index
to->m_receives.remove(i);
break;
}
}
}
// does fromChannel send its output to the input of toChannel?
bool FxMixer::channelSendsTo(fx_ch_t fromChannel, fx_ch_t toChannel)
{
FxChannel * from = m_fxChannels[fromChannel];
for(int i=0; i<from->m_sends.size(); ++i){
if( from->m_sends[i] == toChannel )
return true;
}
return false;
}
void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
{
@@ -93,7 +159,6 @@ void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
m_fxChannels[_ch]->m_lock.lock();
CPU::bufMix( m_fxChannels[_ch]->m_buffer, _buf,
engine::getMixer()->framesPerPeriod() );
m_fxChannels[_ch]->m_used = true;
m_fxChannels[_ch]->m_lock.unlock();
}
}
@@ -103,32 +168,49 @@ void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch )
void FxMixer::processChannel( fx_ch_t _ch, sampleFrame * _buf )
{
if( m_fxChannels[_ch]->m_muteModel.value() == false &&
( m_fxChannels[_ch]->m_used ||
m_fxChannels[_ch]->m_stillRunning ||
_ch == 0 ) )
const fpp_t fpp = engine::getMixer()->framesPerPeriod();
FxChannel * thisCh = m_fxChannels[_ch];
if( ! thisCh->m_muteModel.value() )
{
// do mixer sends. loop through the channels that send to this one
for( int i = 0; i < thisCh->m_receives.size(); ++i)
{
fx_ch_t senderIndex = thisCh->m_receives[i];
FxChannel * sender = m_fxChannels[senderIndex];
// compute the sending channel
processChannel( senderIndex );
// mix it with this one
sampleFrame * ch_buf = sender->m_buffer;
const float v = sender->m_volumeModel.value();
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;
}
engine::getMixer()->clearAudioBuffer( ch_buf,
engine::getMixer()->framesPerPeriod() );
}
if( _buf == NULL )
{
_buf = m_fxChannels[_ch]->m_buffer;
_buf = thisCh->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(
_buf, f );
m_fxChannels[_ch]->m_peakLeft =
engine::getMixer()->peakValueLeft( _buf, f ) *
m_fxChannels[_ch]->m_volumeModel.value();
m_fxChannels[_ch]->m_peakRight =
engine::getMixer()->peakValueRight( _buf, f ) *
m_fxChannels[_ch]->m_volumeModel.value();
m_fxChannels[_ch]->m_used = true;
const float v = thisCh->m_volumeModel.value();
thisCh->m_fxChain.startRunning();
thisCh->m_stillRunning = thisCh->
m_fxChain.processAudioBuffer( _buf, fpp);
thisCh->m_peakLeft =
engine::getMixer()->peakValueLeft( _buf, fpp ) * v;
thisCh->m_peakRight =
engine::getMixer()->peakValueRight( _buf, fpp ) * v;
}
else
{
m_fxChannels[_ch]->m_peakLeft =
m_fxChannels[_ch]->m_peakRight = 0.0f;
thisCh->m_peakLeft = thisCh->m_peakRight = 0.0f;
}
}
@@ -149,31 +231,14 @@ void FxMixer::masterMix( sampleFrame * _buf )
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 < fpp; ++f )
{
_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;
}
}
processChannel( 0, _buf );
if( m_fxChannels[0]->m_muteModel.value() )
/*if( m_fxChannels[0]->m_muteModel.value() )
{
engine::getMixer()->clearAudioBuffer( _buf,
engine::getMixer()->framesPerPeriod() );
return;
}
}*/
const float v = m_fxChannels[0]->m_volumeModel.value();
for( f_cnt_t f = 0; f < engine::getMixer()->framesPerPeriod(); ++f )

View File

@@ -143,16 +143,6 @@ public:
private:
virtual void run()
{
#if 0
#ifdef LMMS_BUILD_LINUX
#ifdef LMMS_HAVE_PTHREAD_H
cpu_set_t mask;
CPU_ZERO( &mask );
CPU_SET( m_workerNum, &mask );
pthread_setaffinity_np( pthread_self(), sizeof( mask ), &mask );
#endif
#endif
#endif
QMutex m;
while( m_quit == false )
{
@@ -618,15 +608,17 @@ sampleFrameA * mixer::renderNextBuffer()
// STAGE 3: process effects in FX mixer
FILL_JOB_QUEUE_PARAM(QVector<fx_ch_t>,__fx_channel_jobs,
/*FILL_JOB_QUEUE_PARAM(QVector<fx_ch_t>,__fx_channel_jobs,
MixerWorkerThread::EffectChannel,1);
START_JOBS();
WAIT_FOR_JOBS();
WAIT_FOR_JOBS();*/
// STAGE 4: do master mix in FX mixer
engine::fxMixer()->masterMix( m_writeBuf );
WAIT_FOR_JOBS();
unlock();
@@ -1137,17 +1129,6 @@ void mixer::fifoWriter::finish()
void mixer::fifoWriter::run()
{
#if 0
#ifdef LMMS_BUILD_LINUX
#ifdef LMMS_HAVE_PTHREAD_H
cpu_set_t mask;
CPU_ZERO( &mask );
CPU_SET( 0, &mask );
pthread_setaffinity_np( pthread_self(), sizeof( mask ), &mask );
#endif
#endif
#endif
const fpp_t frames = m_mixer->framesPerPeriod();
while( m_writing )
{