Move common effect processing code to wrapper method

- Introduce `processImpl` and `sleepImpl` methods, and adapt each effect
plugin to use them
- Use double for RMS out sum in Compressor and LOMM
- Run `checkGate` for GranularPitchShifterEffect
- Minor changes to LadspaEffect
- Remove dynamic allocations and VLAs from VstEffect's process method
- Some minor style/formatting fixes
This commit is contained in:
Dalton Messmer
2024-09-01 20:01:11 -04:00
parent 35f350eeff
commit a7e8af69b7
51 changed files with 263 additions and 354 deletions

View File

@@ -57,10 +57,8 @@ AmplifierEffect::AmplifierEffect(Model* parent, const Descriptor::SubPluginFeatu
}
bool AmplifierEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double AmplifierEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning()) { return false ; }
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -90,9 +88,7 @@ bool AmplifierEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
outSum += currentFrame.sumOfSquaredAmplitudes();
}
checkGate(outSum / frames);
return isRunning();
return outSum;
}

View File

@@ -37,7 +37,8 @@ class AmplifierEffect : public Effect
public:
AmplifierEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~AmplifierEffect() override = default;
bool processAudioBuffer(SampleFrame* buf, const fpp_t frames) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -69,12 +69,8 @@ BassBoosterEffect::BassBoosterEffect( Model* parent, const Descriptor::SubPlugin
bool BassBoosterEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double BassBoosterEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
// check out changed controls
if( m_frequencyChangeNeeded || m_bbControls.m_freqModel.isValueChanged() )
{
@@ -106,9 +102,7 @@ bool BassBoosterEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames
outSum += currentFrame.sumOfSquaredAmplitudes();
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}

View File

@@ -38,7 +38,8 @@ class BassBoosterEffect : public Effect
public:
BassBoosterEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~BassBoosterEffect() override = default;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -100,13 +100,8 @@ inline float BitcrushEffect::noise( float amt )
return fastRandf( amt * 2.0f ) - amt;
}
bool BitcrushEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double BitcrushEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
// update values
if( m_needsUpdate || m_controls.m_rateEnabled.isValueChanged() )
{
@@ -236,12 +231,10 @@ bool BitcrushEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
}
buf[f][0] = d * buf[f][0] + w * qBound( -m_outClip, lsum, m_outClip ) * m_outGain;
buf[f][1] = d * buf[f][1] + w * qBound( -m_outClip, rsum, m_outClip ) * m_outGain;
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}

View File

@@ -41,13 +41,14 @@ class BitcrushEffect : public Effect
public:
BitcrushEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~BitcrushEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{
return &m_controls;
}
private:
void sampleRateChanged();
float depthCrush( float in );

View File

@@ -233,31 +233,11 @@ void CompressorEffect::calcMix()
bool CompressorEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double CompressorEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning())
{
// Clear lookahead buffers and other values when needed
if (!m_cleanedBuffers)
{
m_yL[0] = m_yL[1] = COMP_NOISE_FLOOR;
m_gainResult[0] = m_gainResult[1] = 1;
m_displayPeak[0] = m_displayPeak[1] = COMP_NOISE_FLOOR;
m_displayGain[0] = m_displayGain[1] = COMP_NOISE_FLOOR;
std::fill(std::begin(m_scLookBuf[0]), std::end(m_scLookBuf[0]), COMP_NOISE_FLOOR);
std::fill(std::begin(m_scLookBuf[1]), std::end(m_scLookBuf[1]), COMP_NOISE_FLOOR);
std::fill(std::begin(m_inLookBuf[0]), std::end(m_inLookBuf[0]), 0);
std::fill(std::begin(m_inLookBuf[1]), std::end(m_inLookBuf[1]), 0);
m_cleanedBuffers = true;
}
return false;
}
else
{
m_cleanedBuffers = false;
}
m_cleanedBuffers = false;
float outSum = 0.0;
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -526,15 +506,30 @@ bool CompressorEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
rOutPeak = s[1] > rOutPeak ? s[1] : rOutPeak;
}
checkGate(outSum / frames);
m_compressorControls.m_outPeakL = lOutPeak;
m_compressorControls.m_outPeakR = rOutPeak;
m_compressorControls.m_inPeakL = lInPeak;
m_compressorControls.m_inPeakR = rInPeak;
return isRunning();
return outSum;
}
void CompressorEffect::sleepImpl()
{
// Clear lookahead buffers and other values when needed
if (!m_cleanedBuffers)
{
m_yL[0] = m_yL[1] = COMP_NOISE_FLOOR;
m_gainResult[0] = m_gainResult[1] = 1;
m_displayPeak[0] = m_displayPeak[1] = COMP_NOISE_FLOOR;
m_displayGain[0] = m_displayGain[1] = COMP_NOISE_FLOOR;
std::fill(std::begin(m_scLookBuf[0]), std::end(m_scLookBuf[0]), COMP_NOISE_FLOOR);
std::fill(std::begin(m_scLookBuf[1]), std::end(m_scLookBuf[1]), COMP_NOISE_FLOOR);
std::fill(std::begin(m_inLookBuf[0]), std::end(m_inLookBuf[0]), 0);
std::fill(std::begin(m_inLookBuf[1]), std::end(m_inLookBuf[1]), 0);
m_cleanedBuffers = true;
}
}
// Regular modulo doesn't handle negative numbers correctly. This does.
inline int CompressorEffect::realmod(int k, int n)

View File

@@ -43,7 +43,9 @@ class CompressorEffect : public Effect
public:
CompressorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~CompressorEffect() override = default;
bool processAudioBuffer(SampleFrame* buf, const fpp_t frames) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
void sleepImpl() override;
EffectControls* controls() override
{

View File

@@ -89,13 +89,8 @@ void CrossoverEQEffect::sampleRateChanged()
}
bool CrossoverEQEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double CrossoverEQEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
// filters update
if( m_needsUpdate || m_controls.m_xover12.isValueChanged() )
{
@@ -199,10 +194,8 @@ bool CrossoverEQEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames
buf[f][1] = d * buf[f][1] + w * m_work[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}
void CrossoverEQEffect::clearFilterHistories()

View File

@@ -40,7 +40,8 @@ class CrossoverEQEffect : public Effect
public:
CrossoverEQEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~CrossoverEQEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -81,12 +81,8 @@ DelayEffect::~DelayEffect()
bool DelayEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double DelayEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
double outSum = 0.0;
const float sr = Engine::audioEngine()->outputSampleRate();
const float d = dryLevel();
@@ -143,11 +139,11 @@ bool DelayEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
lfoTimePtr += lfoTimeInc;
feedbackPtr += feedbackInc;
}
checkGate( outSum / frames );
m_delayControls.m_outPeakL = peak.left();
m_delayControls.m_outPeakR = peak.right();
return isRunning();
return outSum;
}
void DelayEffect::changeSampleRate()

View File

@@ -39,7 +39,9 @@ class DelayEffect : public Effect
public:
DelayEffect(Model* parent , const Descriptor::SubPluginFeatures::Key* key );
~DelayEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{
return &m_delayControls;

View File

@@ -58,13 +58,8 @@ DispersionEffect::DispersionEffect(Model* parent, const Descriptor::SubPluginFea
}
bool DispersionEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double DispersionEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning())
{
return false;
}
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -125,8 +120,7 @@ bool DispersionEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate(outSum / frames);
return isRunning();
return outSum;
}

View File

@@ -41,7 +41,8 @@ class DispersionEffect : public Effect
public:
DispersionEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~DispersionEffect() override = default;
bool processAudioBuffer(SampleFrame* buf, const fpp_t frames) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -77,23 +77,18 @@ DualFilterEffect::~DualFilterEffect()
bool DualFilterEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double DualFilterEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
if( m_dfControls.m_filter1Model.isValueChanged() || m_filter1changed )
if( m_dfControls.m_filter1Model.isValueChanged() || m_filter1changed )
{
m_filter1->setFilterType( static_cast<BasicFilters<2>::FilterType>(m_dfControls.m_filter1Model.value()) );
m_filter1changed = true;
}
if( m_dfControls.m_filter2Model.isValueChanged() || m_filter2changed )
if( m_dfControls.m_filter2Model.isValueChanged() || m_filter2changed )
{
m_filter2->setFilterType( static_cast<BasicFilters<2>::FilterType>(m_dfControls.m_filter2Model.value()) );
m_filter2changed = true;
@@ -213,9 +208,7 @@ bool DualFilterEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames
mixPtr += mixInc;
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}
void DualFilterEffect::onEnabledChanged()

View File

@@ -40,7 +40,8 @@ class DualFilterEffect : public Effect
public:
DualFilterEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~DualFilterEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -91,15 +91,8 @@ inline void DynProcEffect::calcRelease()
}
bool DynProcEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double DynProcEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
//apparently we can't keep running after the decay value runs out so we'll just set the peaks to zero
m_currentPeak[0] = m_currentPeak[1] = DYN_NOISE_FLOOR;
return( false );
}
//qDebug( "%f %f", m_currentPeak[0], m_currentPeak[1] );
// variables for effect
@@ -140,9 +133,9 @@ bool DynProcEffect::processAudioBuffer( SampleFrame* _buf,
}
}
for( fpp_t f = 0; f < _frames; ++f )
for (fpp_t f = 0; f < frames; ++f)
{
auto s = std::array{_buf[f][0], _buf[f][1]};
auto s = std::array{buf[f][0], buf[f][1]};
// apply input gain
s[0] *= inputGain;
@@ -210,17 +203,19 @@ bool DynProcEffect::processAudioBuffer( SampleFrame* _buf,
s[1] *= outputGain;
// mix wet/dry signals
_buf[f][0] = d * _buf[f][0] + w * s[0];
_buf[f][1] = d * _buf[f][1] + w * s[1];
out_sum += _buf[f][0] * _buf[f][0] + _buf[f][1] * _buf[f][1];
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
out_sum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( out_sum / _frames );
return( isRunning() );
return out_sum;
}
void DynProcEffect::sleepImpl()
{
// Apparently we can't keep running after the decay value runs out so we'll just set the peaks to zero
m_currentPeak[0] = m_currentPeak[1] = DYN_NOISE_FLOOR;
}

View File

@@ -42,8 +42,9 @@ public:
DynProcEffect( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key );
~DynProcEffect() override;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
void sleepImpl() override;
EffectControls * controls() override
{

View File

@@ -64,7 +64,7 @@ EqEffect::EqEffect( Model *parent, const Plugin::Descriptor::SubPluginFeatures::
bool EqEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double EqEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
const int sampleRate = Engine::audioEngine()->outputSampleRate();
@@ -131,13 +131,6 @@ bool EqEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
m_lp481.setParameters( sampleRate, lpFreq, lpRes, 1 );
if( !isEnabled() || !isRunning () )
{
return( false );
}
if( m_eqControls.m_outGainModel.isValueChanged() )
{
m_outGain = dbfsToAmp(m_eqControls.m_outGainModel.value());
@@ -151,9 +144,9 @@ bool EqEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
m_eqControls.m_inProgress = true;
double outSum = 0.0;
for( fpp_t f = 0; f < frames; ++f )
for (fpp_t f = 0; f < frames; ++f)
{
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
const float outGain = m_outGain;
@@ -268,8 +261,6 @@ bool EqEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
m_eqControls.m_outPeakL = m_eqControls.m_outPeakL < outPeak[0] ? outPeak[0] : m_eqControls.m_outPeakL;
m_eqControls.m_outPeakR = m_eqControls.m_outPeakR < outPeak[1] ? outPeak[1] : m_eqControls.m_outPeakR;
checkGate( outSum / frames );
if(m_eqControls.m_analyseOutModel.value( true ) && outSum > 0 && m_eqControls.isViewVisible() )
{
m_eqControls.m_outFftBands.analyze( buf, frames );
@@ -281,7 +272,8 @@ bool EqEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
}
m_eqControls.m_inProgress = false;
return isRunning();
return outSum;
}

View File

@@ -40,7 +40,9 @@ class EqEffect : public Effect
public:
EqEffect( Model * parent , const Descriptor::SubPluginFeatures::Key * key );
~EqEffect() override = default;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls * controls() override
{
return &m_eqControls;

View File

@@ -85,12 +85,8 @@ FlangerEffect::~FlangerEffect()
bool FlangerEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double FlangerEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -127,10 +123,10 @@ bool FlangerEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
buf[f][0] = ( d * dryS[0] ) + ( w * buf[f][0] );
buf[f][1] = ( d * dryS[1] ) + ( w * buf[f][1] );
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}

View File

@@ -41,7 +41,9 @@ class FlangerEffect : public Effect
public:
FlangerEffect( Model* parent , const Descriptor::SubPluginFeatures::Key* key );
~FlangerEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{
return &m_flangerControls;

View File

@@ -60,10 +60,8 @@ GranularPitchShifterEffect::GranularPitchShifterEffect(Model* parent, const Desc
}
bool GranularPitchShifterEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double GranularPitchShifterEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning()) { return false; }
const float d = dryLevel();
const float w = wetLevel();
@@ -93,6 +91,7 @@ bool GranularPitchShifterEffect::processAudioBuffer(SampleFrame* buf, const fpp_
const float shapeK = cosWindowApproxK(shape);
const int sizeSamples = m_sampleRate / size;
const float waitMult = sizeSamples / (density * 2);
double outSum = 0.0;
for (fpp_t f = 0; f < frames; ++f)
{
@@ -237,6 +236,7 @@ bool GranularPitchShifterEffect::processAudioBuffer(SampleFrame* buf, const fpp_
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
outSum += buf[f].sumOfSquaredAmplitudes();
}
if (m_sampleRateNeedsUpdate)
@@ -245,7 +245,7 @@ bool GranularPitchShifterEffect::processAudioBuffer(SampleFrame* buf, const fpp_
changeSampleRate();
}
return isRunning();
return outSum;
}
void GranularPitchShifterEffect::changeSampleRate()

View File

@@ -48,7 +48,8 @@ class GranularPitchShifterEffect : public Effect
public:
GranularPitchShifterEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~GranularPitchShifterEffect() override = default;
bool processAudioBuffer(SampleFrame* buf, const fpp_t frames) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -101,13 +101,8 @@ void LOMMEffect::changeSampleRate()
}
bool LOMMEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double LOMMEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning())
{
return false;
}
if (m_needsUpdate || m_lommControls.m_split1Model.isValueChanged())
{
m_lp1.setLowpass(m_lommControls.m_split1Model.value());
@@ -121,7 +116,7 @@ bool LOMMEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
}
m_needsUpdate = false;
float outSum = 0.f;
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -423,11 +418,10 @@ bool LOMMEffect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
outSum += buf[f][0] + buf[f][1];
outSum += buf[f].sumOfSquaredAmplitudes();
}
checkGate(outSum / frames);
return isRunning();
return outSum;
}
extern "C"

View File

@@ -45,7 +45,8 @@ class LOMMEffect : public Effect
public:
LOMMEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~LOMMEffect() override = default;
bool processAudioBuffer(SampleFrame* buf, const fpp_t frames) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -129,26 +129,20 @@ void LadspaEffect::changeSampleRate()
bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double LadspaEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
m_pluginMutex.lock();
if( !isOkay() || dontRun() || !isRunning() || !isEnabled() )
{
m_pluginMutex.unlock();
return( false );
}
auto frames = _frames;
SampleFrame* o_buf = nullptr;
QVarLengthArray<SampleFrame> sBuf(_frames);
auto outFrames = frames;
SampleFrame* outBuf = nullptr;
QVarLengthArray<SampleFrame> sBuf(frames);
if( m_maxSampleRate < Engine::audioEngine()->outputSampleRate() )
{
o_buf = _buf;
_buf = sBuf.data();
sampleDown( o_buf, _buf, m_maxSampleRate );
frames = _frames * m_maxSampleRate /
outBuf = buf;
buf = sBuf.data();
sampleDown(outBuf, buf, m_maxSampleRate);
outFrames = frames * m_maxSampleRate /
Engine::audioEngine()->outputSampleRate();
}
@@ -163,11 +157,9 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
switch( pp->rate )
{
case BufferRate::ChannelIn:
for( fpp_t frame = 0;
frame < frames; ++frame )
for (fpp_t frame = 0; frame < outFrames; ++frame)
{
pp->buffer[frame] =
_buf[frame][channel];
pp->buffer[frame] = buf[frame][channel];
}
++channel;
break;
@@ -176,7 +168,7 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
ValueBuffer * vb = pp->control->valueBuffer();
if( vb )
{
memcpy( pp->buffer, vb->values(), frames * sizeof(float) );
memcpy(pp->buffer, vb->values(), outFrames * sizeof(float));
}
else
{
@@ -185,11 +177,9 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
// 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 )
for (fpp_t frame = 0; frame < outFrames; ++frame)
{
pp->buffer[frame] =
pp->value;
pp->buffer[frame] = pp->value;
}
}
break;
@@ -218,7 +208,7 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
// Process the buffers.
for( ch_cnt_t proc = 0; proc < processorCount(); ++proc )
{
(m_descriptor->run)( m_handles[proc], frames );
(m_descriptor->run)(m_handles[proc], outFrames);
}
// Copy the LADSPA output buffers to the LMMS buffer.
@@ -238,11 +228,9 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
case BufferRate::ControlRateInput:
break;
case BufferRate::ChannelOut:
for( fpp_t frame = 0;
frame < frames; ++frame )
for (fpp_t frame = 0; frame < outFrames; ++frame)
{
_buf[frame][channel] = d * _buf[frame][channel] + w * pp->buffer[frame];
out_sum += _buf[frame][channel] * _buf[frame][channel];
buf[frame][channel] = d * buf[frame][channel] + w * pp->buffer[frame];
}
++channel;
break;
@@ -255,17 +243,19 @@ bool LadspaEffect::processAudioBuffer( SampleFrame* _buf,
}
}
if( o_buf != nullptr )
if (outBuf != nullptr)
{
sampleBack( _buf, o_buf, m_maxSampleRate );
sampleBack(buf, outBuf, m_maxSampleRate);
}
checkGate( out_sum / frames );
for (fpp_t frame = 0; frame < frames; ++frame)
{
out_sum += buf[frame].sumOfSquaredAmplitudes();
}
bool is_running = isRunning();
m_pluginMutex.unlock();
return( is_running );
return out_sum;
}

View File

@@ -47,9 +47,8 @@ public:
const Descriptor::SubPluginFeatures::Key * _key );
~LadspaEffect() override;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
void setControl( int _control, LADSPA_Data _data );
EffectControls * controls() override

View File

@@ -68,9 +68,8 @@ Lv2Effect::Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key *ke
bool Lv2Effect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
double Lv2Effect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning()) { return false; }
Q_ASSERT(frames <= static_cast<fpp_t>(m_tmpOutputSmps.size()));
m_controls.copyBuffersFromLmms(buf, frames);
@@ -95,9 +94,8 @@ bool Lv2Effect::processAudioBuffer(SampleFrame* buf, const fpp_t frames)
auto r = static_cast<double>(buf[f][1]);
outSum += l*l + r*r;
}
checkGate(outSum / frames);
return isRunning();
return outSum;
}

View File

@@ -42,7 +42,8 @@ public:
*/
Lv2Effect(Model* parent, const Descriptor::SubPluginFeatures::Key* _key);
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override { return &m_controls; }
Lv2FxControls* lv2Controls() { return &m_controls; }

View File

@@ -94,13 +94,8 @@ void MultitapEchoEffect::runFilter( SampleFrame* dst, SampleFrame* src, StereoOn
}
bool MultitapEchoEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double MultitapEchoEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -158,10 +153,8 @@ bool MultitapEchoEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frame
buf[f][1] = d * buf[f][1] + w * m_work[f][1];
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}

View File

@@ -40,7 +40,8 @@ class MultitapEchoEffect : public Effect
public:
MultitapEchoEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~MultitapEchoEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -93,37 +93,29 @@ PeakControllerEffect::~PeakControllerEffect()
}
bool PeakControllerEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double PeakControllerEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
PeakControllerEffectControls & c = m_peakControls;
// This appears to be used for determining whether or not to continue processing
// audio with this effect
if( !isEnabled() || !isRunning() )
{
return false;
}
// RMS:
double sum = 0;
if( c.m_absModel.value() )
{
for (auto i = std::size_t{0}; i < _frames; ++i)
for (auto i = std::size_t{0}; i < frames; ++i)
{
// absolute value is achieved because the squares are > 0
sum += _buf[i][0]*_buf[i][0] + _buf[i][1]*_buf[i][1];
sum += buf[i][0] * buf[i][0] + buf[i][1] * buf[i][1];
}
}
else
{
for (auto i = std::size_t{0}; i < _frames; ++i)
for (auto i = std::size_t{0}; i < frames; ++i)
{
// the value is absolute because of squaring,
// so we need to correct it
sum += _buf[i][0] * _buf[i][0] * sign( _buf[i][0] )
+ _buf[i][1] * _buf[i][1] * sign( _buf[i][1] );
sum += buf[i][0] * buf[i][0] * sign(buf[i][0])
+ buf[i][1] * buf[i][1] * sign(buf[i][1]);
}
}
@@ -131,19 +123,19 @@ bool PeakControllerEffect::processAudioBuffer( SampleFrame* _buf,
// this will mute the output after the values were measured
if( c.m_muteModel.value() )
{
for (auto i = std::size_t{0}; i < _frames; ++i)
for (auto i = std::size_t{0}; i < frames; ++i)
{
_buf[i][0] = _buf[i][1] = 0.0f;
buf[i][0] = buf[i][1] = 0.0f;
}
}
float curRMS = sqrt_neg( sum / _frames );
float curRMS = sqrt_neg( sum / frames );
const float tres = c.m_tresholdModel.value();
const float amount = c.m_amountModel.value() * c.m_amountMultModel.value();
curRMS = qAbs( curRMS ) < tres ? 0.0f : curRMS;
m_lastSample = qBound( 0.0f, c.m_baseModel.value() + amount * curRMS, 1.0f );
return isRunning();
return -1.0;
}

View File

@@ -41,8 +41,8 @@ public:
PeakControllerEffect( Model * parent,
const Descriptor::SubPluginFeatures::Key * _key );
~PeakControllerEffect() override;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls * controls() override
{

View File

@@ -75,13 +75,8 @@ ReverbSCEffect::~ReverbSCEffect()
sp_destroy(&sp);
}
bool ReverbSCEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
double ReverbSCEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
double outSum = 0.0;
const float d = dryLevel();
const float w = wetLevel();
@@ -120,13 +115,10 @@ bool ReverbSCEffect::processAudioBuffer( SampleFrame* buf, const fpp_t frames )
buf[f][0] = d * buf[f][0] + w * dcblkL * outGain;
buf[f][1] = d * buf[f][1] + w * dcblkR * outGain;
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( outSum / frames );
return isRunning();
return outSum;
}
void ReverbSCEffect::changeSampleRate()

View File

@@ -45,7 +45,8 @@ class ReverbSCEffect : public Effect
public:
ReverbSCEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key );
~ReverbSCEffect() override;
bool processAudioBuffer( SampleFrame* buf, const fpp_t frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -77,7 +77,7 @@ Analyzer::~Analyzer()
}
// Take audio data and pass them to the spectrum processor.
bool Analyzer::processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count)
double Analyzer::processImpl(SampleFrame* buf, const fpp_t frames)
{
// Measure time spent in audio thread; both average and peak should be well under 1 ms.
#ifdef SA_DEBUG
@@ -91,14 +91,12 @@ bool Analyzer::processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count)
}
#endif
if (!isEnabled() || !isRunning ()) {return false;}
// Skip processing if the controls dialog isn't visible, it would only waste CPU cycles.
if (m_controls.isViewVisible())
{
// To avoid processing spikes on audio thread, data are stored in
// a lockless ringbuffer and processed in a separate thread.
m_inputBuffer.write(buffer, frame_count, true);
m_inputBuffer.write(buf, frames, true);
}
#ifdef SA_DEBUG
audio_time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - audio_time;
@@ -107,7 +105,7 @@ bool Analyzer::processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count)
if (audio_time / 1000000.0 > m_max_execution) {m_max_execution = audio_time / 1000000.0;}
#endif
return isRunning();
return -1.0;
}

View File

@@ -45,7 +45,8 @@ public:
Analyzer(Model *parent, const Descriptor::SubPluginFeatures::Key *key);
~Analyzer() override;
bool processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls *controls() override {return &m_controls;}
SaProcessor *getProcessor() {return &m_processor;}

View File

@@ -82,28 +82,21 @@ StereoEnhancerEffect::~StereoEnhancerEffect()
bool StereoEnhancerEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double StereoEnhancerEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
// This appears to be used for determining whether or not to continue processing
// audio with this effect
double out_sum = 0.0;
if( !isEnabled() || !isRunning() )
{
return( false );
}
const float d = dryLevel();
const float w = wetLevel();
for( fpp_t f = 0; f < _frames; ++f )
for( fpp_t f = 0; f < frames; ++f )
{
// copy samples into the delay buffer
m_delayBuffer[m_currFrame][0] = _buf[f][0];
m_delayBuffer[m_currFrame][1] = _buf[f][1];
m_delayBuffer[m_currFrame][0] = buf[f][0];
m_delayBuffer[m_currFrame][1] = buf[f][1];
// Get the width knob value from the Stereo Enhancer effect
float width = m_seFX.wideCoeff();
@@ -118,26 +111,25 @@ bool StereoEnhancerEffect::processAudioBuffer( SampleFrame* _buf,
}
//sample_t s[2] = { _buf[f][0], _buf[f][1] }; //Vanilla
auto s = std::array{_buf[f][0], m_delayBuffer[frameIndex][1]}; //Chocolate
auto s = std::array{buf[f][0], m_delayBuffer[frameIndex][1]}; //Chocolate
m_seFX.nextSample( s[0], s[1] );
_buf[f][0] = d * _buf[f][0] + w * s[0];
_buf[f][1] = d * _buf[f][1] + w * s[1];
out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1];
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
out_sum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
// Update currFrame
m_currFrame += 1;
m_currFrame %= DEFAULT_BUFFER_SIZE;
}
checkGate( out_sum / _frames );
if( !isRunning() )
{
clearMyBuffer();
}
return( isRunning() );
return out_sum;
}

View File

@@ -40,8 +40,8 @@ public:
StereoEnhancerEffect( Model * parent,
const Descriptor::SubPluginFeatures::Key * _key );
~StereoEnhancerEffect() override;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls * controls() override
{

View File

@@ -64,44 +64,33 @@ StereoMatrixEffect::StereoMatrixEffect(
bool StereoMatrixEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double StereoMatrixEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
// This appears to be used for determining whether or not to continue processing
// audio with this effect
if( !isEnabled() || !isRunning() )
{
return( false );
}
double out_sum = 0.0;
for( fpp_t f = 0; f < _frames; ++f )
for( fpp_t f = 0; f < frames; ++f )
{
const float d = dryLevel();
const float w = wetLevel();
sample_t l = _buf[f][0];
sample_t r = _buf[f][1];
sample_t l = buf[f][0];
sample_t r = buf[f][1];
// Init with dry-mix
_buf[f][0] = l * d;
_buf[f][1] = r * d;
buf[f][0] = l * d;
buf[f][1] = r * d;
// Add it wet
_buf[f][0] += ( m_smControls.m_llModel.value( f ) * l +
buf[f][0] += ( m_smControls.m_llModel.value( f ) * l +
m_smControls.m_rlModel.value( f ) * r ) * w;
_buf[f][1] += ( m_smControls.m_lrModel.value( f ) * l +
buf[f][1] += ( m_smControls.m_lrModel.value( f ) * l +
m_smControls.m_rrModel.value( f ) * r ) * w;
out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1];
out_sum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
checkGate( out_sum / _frames );
return( isRunning() );
return out_sum;
}

View File

@@ -39,8 +39,8 @@ public:
StereoMatrixEffect( Model * parent,
const Descriptor::SubPluginFeatures::Key * _key );
~StereoMatrixEffect() override = default;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{

View File

@@ -58,18 +58,17 @@ Vectorscope::Vectorscope(Model *parent, const Plugin::Descriptor::SubPluginFeatu
// Take audio data and store them for processing and display in the GUI thread.
bool Vectorscope::processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count)
double Vectorscope::processImpl(SampleFrame* buf, const fpp_t frames)
{
if (!isEnabled() || !isRunning ()) {return false;}
// Skip processing if the controls dialog isn't visible, it would only waste CPU cycles.
if (m_controls.isViewVisible())
{
// To avoid processing spikes on audio thread, data are stored in
// a lockless ringbuffer and processed in a separate thread.
m_inputBuffer.write(buffer, frame_count);
m_inputBuffer.write(buf, frames);
}
return isRunning();
return -1.0;
}

View File

@@ -39,7 +39,8 @@ public:
Vectorscope(Model *parent, const Descriptor::SubPluginFeatures::Key *key);
~Vectorscope() override = default;
bool processAudioBuffer(SampleFrame* buffer, const fpp_t frame_count) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls *controls() override {return &m_controls;}
LocklessRingBuffer<SampleFrame> *getBuffer() {return &m_inputBuffer;}

View File

@@ -71,51 +71,37 @@ VstEffect::VstEffect( Model * _parent,
}
setDisplayName( m_key.attributes["file"].section( ".dll", 0, 0 ).isEmpty()
? m_key.name : m_key.attributes["file"].section( ".dll", 0, 0 ) );
setDontRun(true);
}
bool VstEffect::processAudioBuffer( SampleFrame* _buf, const fpp_t _frames )
double VstEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
assert(m_plugin != nullptr);
assert(frames <= DEFAULT_BUFFER_SIZE);
static thread_local auto tempBuf = std::array<SampleFrame, DEFAULT_BUFFER_SIZE>();
std::memcpy(tempBuf.data(), buf, sizeof(SampleFrame) * frames);
if (m_pluginMutex.tryLock(Engine::getSong()->isExporting() ? -1 : 0))
{
return false;
m_plugin->process(tempBuf.data(), tempBuf.data());
m_pluginMutex.unlock();
}
if( m_plugin )
double outSum = 0.0;
const float w = wetLevel();
const float d = dryLevel();
for (fpp_t f = 0; f < frames; ++f)
{
const float d = dryLevel();
#ifdef __GNUC__
SampleFrame buf[_frames];
#else
SampleFrame* buf = new SampleFrame[_frames];
#endif
memcpy( buf, _buf, sizeof( SampleFrame ) * _frames );
if (m_pluginMutex.tryLock(Engine::getSong()->isExporting() ? -1 : 0))
{
m_plugin->process( buf, buf );
m_pluginMutex.unlock();
}
double out_sum = 0.0;
const float w = wetLevel();
for( fpp_t f = 0; f < _frames; ++f )
{
_buf[f][0] = w*buf[f][0] + d*_buf[f][0];
_buf[f][1] = w*buf[f][1] + d*_buf[f][1];
}
for( fpp_t f = 0; f < _frames; ++f )
{
out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1];
}
#ifndef __GNUC__
delete[] buf;
#endif
checkGate( out_sum / _frames );
buf[f][0] = w * tempBuf[f][0] + d * buf[f][0];
buf[f][1] = w * tempBuf[f][1] + d * buf[f][1];
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
}
return isRunning();
return outSum;
}
@@ -137,11 +123,13 @@ void VstEffect::openPlugin( const QString & _plugin )
if( m_plugin->failed() )
{
m_plugin.clear();
setDontRun(true);
delete tf;
collectErrorForUI( VstPlugin::tr( "The VST plugin %1 could not be loaded." ).arg( _plugin ) );
return;
}
setDontRun(false);
delete tf;
m_key.attributes["file"] = _plugin;

View File

@@ -45,8 +45,7 @@ public:
const Descriptor::SubPluginFeatures::Key * _key );
~VstEffect() override = default;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls * controls() override
{

View File

@@ -66,14 +66,8 @@ WaveShaperEffect::WaveShaperEffect( Model * _parent,
bool WaveShaperEffect::processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames )
double WaveShaperEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
if( !isEnabled() || !isRunning () )
{
return( false );
}
// variables for effect
int i = 0;
@@ -94,9 +88,9 @@ bool WaveShaperEffect::processAudioBuffer( SampleFrame* _buf,
const float *inputPtr = inputBuffer ? &( inputBuffer->values()[ 0 ] ) : &input;
const float *outputPtr = outputBufer ? &( outputBufer->values()[ 0 ] ) : &output;
for( fpp_t f = 0; f < _frames; ++f )
for (fpp_t f = 0; f < frames; ++f)
{
auto s = std::array{_buf[f][0], _buf[f][1]};
auto s = std::array{buf[f][0], buf[f][1]};
// apply input gain
s[0] *= *inputPtr;
@@ -138,17 +132,15 @@ bool WaveShaperEffect::processAudioBuffer( SampleFrame* _buf,
s[1] *= *outputPtr;
// mix wet/dry signals
_buf[f][0] = d * _buf[f][0] + w * s[0];
_buf[f][1] = d * _buf[f][1] + w * s[1];
out_sum += _buf[f][0] * _buf[f][0] + _buf[f][1] * _buf[f][1];
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
out_sum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
outputPtr += outputInc;
inputPtr += inputInc;
}
checkGate( out_sum / _frames );
return( isRunning() );
return out_sum;
}

View File

@@ -40,8 +40,8 @@ public:
WaveShaperEffect( Model * _parent,
const Descriptor::SubPluginFeatures::Key * _key );
~WaveShaperEffect() override = default;
bool processAudioBuffer( SampleFrame* _buf,
const fpp_t _frames ) override;
double processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls * controls() override
{