* LADSPA-effect-plugin: improved handling of effects which only work at limited samplerates

* audio-port: small optimizations
* mixer: removed obsolete idle-property of worker-threads
* FX-mixer: protect individual buffers of FX-channels from being processed by more than one thread



git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@979 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2008-05-17 15:50:27 +00:00
parent fc63352e55
commit fc1b985fe8
7 changed files with 257 additions and 202 deletions

View File

@@ -64,7 +64,8 @@ ladspaEffect::ladspaEffect( model * _parent,
const descriptor::subPluginFeatures::key * _key ) :
effect( &ladspaeffect_plugin_descriptor, _parent, _key ),
m_controls( NULL ),
m_effName( "none" ),
m_publicName( "none" ),
m_maxSampleRate( 0 ),
m_key( ladspaSubPluginFeatures::subPluginKeyToLadspaKey( _key ) )
{
ladspa2LMMS * manager = engine::getLADSPAManager();
@@ -76,7 +77,7 @@ ladspaEffect::ladspaEffect( model * _parent,
setOkay( FALSE );
return;
}
setPublicName( manager->getShortName( m_key ) );
pluginInstantiation();
@@ -114,30 +115,200 @@ void ladspaEffect::changeSampleRate( void )
bool ladspaEffect::processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames )
{
m_pluginMutex.lock();
if( !isOkay() || dontRun() || !isRunning() || !isEnabled() )
{
m_pluginMutex.unlock();
return( FALSE );
}
int frames = _frames;
sampleFrame * o_buf = NULL;
int sr = m_maxSampleRate;
if( sr < engine::getMixer()->processingSampleRate() )
{
o_buf = _buf;
_buf = new sampleFrame[_frames];
sampleDown( o_buf, _buf, sr );
frames = _frames * sr /
engine::getMixer()->processingSampleRate();
}
// Copy the LMMS audio buffer to the LADSPA input buffer and initialize
// the control ports. Need to change this to handle non-in-place-broken
// plugins--would speed things up to use the same buffer for both
// LMMS and LADSPA.
ch_cnt_t channel = 0;
for( ch_cnt_t proc = 0; proc < getProcessorCount(); ++proc )
{
for( int port = 0; port < m_portCount; ++port )
{
switch( m_ports[proc][port]->rate )
{
case CHANNEL_IN:
for( fpp_t frame = 0;
frame < frames; ++frame )
{
m_ports[proc][port]->buffer[frame] =
_buf[frame][channel];
}
++channel;
break;
case AUDIO_RATE_INPUT:
m_ports[proc][port]->value =
static_cast<LADSPA_Data>(
m_ports[proc][port]->control->getValue() /
m_ports[proc][port]->scale );
// This only supports control rate ports, so the audio rates are
// treated as though they were control rate by setting the
// port buffer to all the same value.
for( fpp_t frame = 0;
frame < frames; ++frame )
{
m_ports[proc][port]->buffer[frame] =
m_ports[proc][port]->value;
}
break;
case CONTROL_RATE_INPUT:
if( m_ports[proc][port]->control ==
NULL )
{
break;
}
m_ports[proc][port]->value =
static_cast<LADSPA_Data>(
m_ports[proc][port]->control->getValue() /
m_ports[proc][port]->scale );
m_ports[proc][port]->buffer[0] =
m_ports[proc][port]->value;
break;
case CHANNEL_OUT:
case AUDIO_RATE_OUTPUT:
case CONTROL_RATE_OUTPUT:
break;
default:
break;
}
}
}
// Process the buffers.
for( ch_cnt_t proc = 0; proc < getProcessorCount(); ++proc )
{
(m_descriptor->run)( m_handles[proc], frames );
}
// Copy the LADSPA output buffers to the LMMS buffer.
double out_sum = 0.0;
channel = 0;
const float d = getDryLevel();
const float w = getWetLevel();
for( ch_cnt_t proc = 0; proc < getProcessorCount(); ++proc )
{
for( int port = 0; port < m_portCount; ++port )
{
switch( m_ports[proc][port]->rate )
{
case CHANNEL_IN:
case AUDIO_RATE_INPUT:
case CONTROL_RATE_INPUT:
break;
case CHANNEL_OUT:
for( fpp_t frame = 0;
frame < frames; ++frame )
{
_buf[frame][channel] =
d *
_buf[frame][channel] +
w *
m_ports[proc][port]->buffer[frame];
out_sum +=
_buf[frame][channel] *
_buf[frame][channel];
}
++channel;
break;
case AUDIO_RATE_OUTPUT:
case CONTROL_RATE_OUTPUT:
break;
default:
break;
}
}
}
if( o_buf != NULL )
{
sampleBack( _buf, o_buf, sr );
delete[] _buf;
}
// Check whether we need to continue processing input. Restart the
// counter if the threshold has been exceeded.
if( out_sum / frames <= getGate()+0.000001 )
{
incrementBufferCount();
if( getBufferCount() > getTimeout() )
{
stopRunning();
resetBufferCount();
}
}
else
{
resetBufferCount();
}
bool is_running = isRunning();
m_pluginMutex.unlock();
return( is_running );
}
void ladspaEffect::setControl( int _control, LADSPA_Data _value )
{
if( !isOkay() )
{
return;
}
m_portControls[_control]->value = _value;
}
void ladspaEffect::pluginInstantiation( void )
{
m_maxSampleRate = maxSamplerate( publicName() );
ladspa2LMMS * manager = engine::getLADSPAManager();
// Calculate how many processing units are needed.
const ch_cnt_t lmms_chnls = engine::getMixer()->audioDev()->channels();
m_effectChannels = manager->getDescription( m_key )->inputChannels;
setProcessorCount( lmms_chnls / m_effectChannels );
int effect_channels = manager->getDescription( m_key )->inputChannels;
setProcessorCount( lmms_chnls / effect_channels );
// Categorize the ports, and create the buffers.
m_portCount = manager->getPortCount( m_key );
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++ )
{
multi_proc_t ports;
for( Uint16 port = 0; port < m_portCount; port++ )
for( int port = 0; port < m_portCount; port++ )
{
port_desc_t * p = new portDescription;
p->name = manager->getPortName( m_key, port );
p->proc = proc;
p->port_id = port;
p->control = NULL;
// Determine the port's category.
if( manager->isPortAudio( m_key, port ) )
{
@@ -227,7 +398,7 @@ void ladspaEffect::pluginInstantiation( void )
if( manager->areHintsSampleRateDependent(
m_key, port ) )
{
p->max *= engine::getMixer()->processingSampleRate();
p->max *= m_maxSampleRate;
}
p->min = manager->getLowerBound( m_key, port );
@@ -239,7 +410,7 @@ void ladspaEffect::pluginInstantiation( void )
if( manager->areHintsSampleRateDependent(
m_key, port ) )
{
p->min *= engine::getMixer()->processingSampleRate();
p->min *= m_maxSampleRate;
}
p->def = manager->getDefaultSetting( m_key, port );
@@ -296,7 +467,7 @@ void ladspaEffect::pluginInstantiation( void )
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++ )
{
LADSPA_Handle effect = manager->instantiate( m_key,
engine::getMixer()->processingSampleRate() );
m_maxSampleRate );
if( effect == NULL )
{
QMessageBox::warning( 0, "Effect",
@@ -311,7 +482,7 @@ void ladspaEffect::pluginInstantiation( void )
// Connect the ports.
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++ )
{
for( Uint16 port = 0; port < m_portCount; port++ )
for( int port = 0; port < m_portCount; port++ )
{
if( !manager->connectPort( m_key,
m_handles[proc],
@@ -355,7 +526,7 @@ void ladspaEffect::pluginDestruction( void )
ladspa2LMMS * manager = engine::getLADSPAManager();
manager->deactivate( m_key, m_handles[proc] );
manager->cleanup( m_key, m_handles[proc] );
for( Uint16 port = 0; port < m_portCount; port++ )
for( int port = 0; port < m_portCount; port++ )
{
free( m_ports[proc][port]->buffer );
free( m_ports[proc][port] );
@@ -370,171 +541,27 @@ void ladspaEffect::pluginDestruction( void )
bool ladspaEffect::processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames )
static QMap<QString, int> __buggy_plugins;
int ladspaEffect::maxSamplerate( const QString & _name )
{
m_pluginMutex.lock();
if( !isOkay() || dontRun() || !isRunning() || !isEnabled() )
if( __buggy_plugins.isEmpty() )
{
m_pluginMutex.unlock();
return( FALSE );
__buggy_plugins["C * AmpVTS"] = 88200;
__buggy_plugins["Chorus2"] = 44100;
}
sampleFrame * o_buf = NULL;
int frames = _frames;
if( publicName().contains( "C* AmpVTS" ) &&
engine::getMixer()->processingSampleRate() > 88200 )
if( __buggy_plugins.contains( _name ) )
{
o_buf = _buf;
_buf = new sampleFrame[_frames];
sampleDown( o_buf, _buf, 88200 );
frames = _frames * 88200 /
engine::getMixer()->processingSampleRate();
return( __buggy_plugins[_name] );
}
// Copy the LMMS audio buffer to the LADSPA input buffer and initialize
// the control ports. Need to change this to handle non-in-place-broken
// plugins--would speed things up to use the same buffer for both
// LMMS and LADSPA.
ch_cnt_t channel = 0;
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++)
{
for( Uint16 port = 0; port < m_portCount; port++ )
{
switch( m_ports[proc][port]->rate )
{
case CHANNEL_IN:
for( fpp_t frame = 0;
frame < frames; frame++ )
{
m_ports[proc][port]->buffer[frame] =
_buf[frame][channel];
}
channel++;
break;
case AUDIO_RATE_INPUT:
m_ports[proc][port]->value =
static_cast<LADSPA_Data>(
m_ports[proc][port]->control->getValue() /
m_ports[proc][port]->scale );
// This only supports control rate ports, so the audio rates are
// treated as though they were control rate by setting the
// port buffer to all the same value.
for( fpp_t frame = 0;
frame < frames; frame++ )
{
m_ports[proc][port]->buffer[frame] =
m_ports[proc][port]->value;
}
break;
case CONTROL_RATE_INPUT:
if( m_ports[proc][port]->control ==
NULL )
{
break;
}
m_ports[proc][port]->value =
static_cast<LADSPA_Data>(
m_ports[proc][port]->control->getValue() /
m_ports[proc][port]->scale );
m_ports[proc][port]->buffer[0] =
m_ports[proc][port]->value;
break;
case CHANNEL_OUT:
case AUDIO_RATE_OUTPUT:
case CONTROL_RATE_OUTPUT:
break;
default:
break;
}
}
}
// Process the buffers.
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++ )
{
(m_descriptor->run)(m_handles[proc], frames);
}
// Copy the LADSPA output buffers to the LMMS buffer.
double out_sum = 0.0;
channel = 0;
const float d = getDryLevel();
const float w = getWetLevel();
for( ch_cnt_t proc = 0; proc < getProcessorCount(); proc++)
{
for( Uint16 port = 0; port < m_portCount; port++ )
{
switch( m_ports[proc][port]->rate )
{
case CHANNEL_IN:
case AUDIO_RATE_INPUT:
case CONTROL_RATE_INPUT:
break;
case CHANNEL_OUT:
for( fpp_t frame = 0;
frame < frames; frame++ )
{
_buf[frame][channel] =
d *
_buf[frame][channel] +
w *
m_ports[proc][port]->buffer[frame];
out_sum +=
_buf[frame][channel] *
_buf[frame][channel];
}
++channel;
break;
case AUDIO_RATE_OUTPUT:
case CONTROL_RATE_OUTPUT:
break;
default:
break;
}
}
}
if( o_buf != NULL )
{
sampleBack( _buf, o_buf, 88200 );
delete[] _buf;
}
// Check whether we need to continue processing input. Restart the
// counter if the threshold has been exceeded.
if( out_sum / frames <= getGate()+0.000001 )
{
incrementBufferCount();
if( getBufferCount() > getTimeout() )
{
stopRunning();
resetBufferCount();
}
}
else
{
resetBufferCount();
}
bool is_running = isRunning();
m_pluginMutex.unlock();
return( is_running );
return( engine::getMixer()->processingSampleRate() );
}
void ladspaEffect::setControl( Uint16 _control, LADSPA_Data _value )
{
if( !isOkay() )
{
return;
}
m_portControls[_control]->value = _value;
}
extern "C"
{

View File

@@ -48,7 +48,7 @@ public:
virtual bool processAudioBuffer( sampleFrame * _buf,
const fpp_t _frames );
void setControl( Uint16 _control, LADSPA_Data _data );
void setControl( int _control, LADSPA_Data _data );
virtual effectControls * getControls( void )
{
@@ -62,12 +62,12 @@ public:
virtual inline QString publicName( void ) const
{
return( m_effName );
return( m_publicName );
}
inline void setPublicName( const QString & _name )
{
m_effName = _name;
m_publicName = _name;
}
@@ -79,15 +79,16 @@ private:
void pluginInstantiation( void );
void pluginDestruction( void );
static int maxSamplerate( const QString & _name );
QMutex m_pluginMutex;
ladspaControls * m_controls;
QString m_effName;
QString m_publicName;
int m_maxSampleRate;
ladspa_key_t m_key;
Uint16 m_effectChannels;
Uint16 m_portCount;
fpp_t m_bufferSize;
int m_portCount;
const LADSPA_Descriptor * m_descriptor;
QVector<LADSPA_Handle> m_handles;