diff --git a/plugins/Disintegrator/Disintegrator.cpp b/plugins/Disintegrator/Disintegrator.cpp index d4c883ada..2498591d0 100644 --- a/plugins/Disintegrator/Disintegrator.cpp +++ b/plugins/Disintegrator/Disintegrator.cpp @@ -35,7 +35,7 @@ Plugin::Descriptor PLUGIN_EXPORT disintegrator_plugin_descriptor = { STRINGIFY(PLUGIN_NAME), "Disintegrator", - QT_TRANSLATE_NOOP("pluginBrowser", "A delay modulation effect for creating very aggressive digital distortion."), + QT_TRANSLATE_NOOP("pluginBrowser", "A delay modulation effect for very aggressive digital distortion."), "Lost Robot ", 0x0100, Plugin::Effect, @@ -50,15 +50,18 @@ Plugin::Descriptor PLUGIN_EXPORT disintegrator_plugin_descriptor = DisintegratorEffect::DisintegratorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key) : Effect(&disintegrator_plugin_descriptor, parent, key), - m_disintegratorControls(this) + m_disintegratorControls(this), + m_lp( Engine::mixer()->processingSampleRate() ), + m_hp( Engine::mixer()->processingSampleRate() ), + m_needsUpdate( true ) { // Fill buffer with DISINTEGRATOR_BUFFER_SIZE number of samples - for (int i = 0; i < DISINTEGRATOR_BUFFER_SIZE; ++i) + for (int i = 0; i < 2; ++i) { m_inBuf[i].reserve(DISINTEGRATOR_BUFFER_SIZE); - for (int j = 0; j < 2; ++j) + for (int j = 0; j < DISINTEGRATOR_BUFFER_SIZE; ++j) { - m_inBuf[j].push_back(0); + m_inBuf[i].push_back(0); } } } @@ -72,6 +75,15 @@ DisintegratorEffect::~DisintegratorEffect() +void DisintegratorEffect::sampleRateChanged() +{ + sample_rate_t sampleRate = Engine::mixer()->processingSampleRate(); + m_lp.setSampleRate( sampleRate ); + m_hp.setSampleRate( sampleRate ); + m_needsUpdate = true; +} + + bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) { @@ -84,18 +96,26 @@ bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frame const float d = dryLevel(); const float w = wetLevel(); - const ValueBuffer * lowCutBuf = m_disintegratorControls.m_lowCutModel.valueBuffer(); - const ValueBuffer * highCutBuf = m_disintegratorControls.m_highCutModel.valueBuffer(); const ValueBuffer * amountBuf = m_disintegratorControls.m_amountModel.valueBuffer(); const ValueBuffer * typeBuf = m_disintegratorControls.m_typeModel.valueBuffer(); const ValueBuffer * freqBuf = m_disintegratorControls.m_lowCutModel.valueBuffer(); sample_rate_t sampleRate = Engine::mixer()->processingSampleRate(); + // Update filters + if( m_needsUpdate || m_disintegratorControls.m_highCutModel.isValueChanged() ) + { + m_lp.setLowpass( m_disintegratorControls.m_highCutModel.value() ); + + } + if( m_needsUpdate || m_disintegratorControls.m_lowCutModel.isValueChanged() ) + { + m_hp.setHighpass( m_disintegratorControls.m_lowCutModel.value() ); + } + m_needsUpdate = false; + for (fpp_t f = 0; f < frames; ++f) { - const float lowCut = lowCutBuf ? lowCutBuf->value(f) : m_disintegratorControls.m_lowCutModel.value(); - const float highCut = highCutBuf ? highCutBuf->value(f) : m_disintegratorControls.m_highCutModel.value(); const float amount = amountBuf ? amountBuf->value(f) : m_disintegratorControls.m_amountModel.value(); const int type = typeBuf ? typeBuf->value(f) : m_disintegratorControls.m_typeModel.value(); const float freq = freqBuf ? freqBuf->value(f) : m_disintegratorControls.m_freqModel.value(); @@ -126,8 +146,8 @@ bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frame { newInBufLoc[0] = fast_rand() / (float)FAST_RAND_MAX; - calcHighpassFilter(newInBufLoc[0], newInBufLoc[0], 0, lowCut, sampleRate); - calcLowpassFilter(newInBufLoc[0], newInBufLoc[0], 0, highCut, sampleRate); + newInBufLoc[0] = m_hp.update( newInBufLoc[0], 0 ); + newInBufLoc[0] = m_lp.update( newInBufLoc[0], 0 ); newInBufLoc[0] = realfmod(m_inBufLoc - newInBufLoc[0] * amount, DISINTEGRATOR_BUFFER_SIZE); newInBufLoc[1] = newInBufLoc[0]; @@ -143,10 +163,10 @@ bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frame newInBufLoc[0] = fast_rand() / (float)FAST_RAND_MAX; newInBufLoc[1] = fast_rand() / (float)FAST_RAND_MAX; - calcHighpassFilter(newInBufLoc[0], newInBufLoc[0], 0, lowCut, sampleRate); - calcHighpassFilter(newInBufLoc[1], newInBufLoc[1], 1, lowCut, sampleRate); - calcLowpassFilter(newInBufLoc[0], newInBufLoc[0], 0, highCut, sampleRate); - calcLowpassFilter(newInBufLoc[1], newInBufLoc[1], 1, highCut, sampleRate); + newInBufLoc[0] = m_hp.update( newInBufLoc[0], 0 ); + newInBufLoc[0] = m_lp.update( newInBufLoc[0], 0 ); + newInBufLoc[1] = m_hp.update( newInBufLoc[1], 1 ); + newInBufLoc[1] = m_lp.update( newInBufLoc[1], 1 ); newInBufLoc[0] = realfmod(m_inBufLoc - newInBufLoc[0] * amount, DISINTEGRATOR_BUFFER_SIZE); newInBufLoc[1] = realfmod(m_inBufLoc - newInBufLoc[1] * amount, DISINTEGRATOR_BUFFER_SIZE); @@ -204,66 +224,6 @@ bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frame -inline void DisintegratorEffect::calcLowpassFilter(sample_t &outSamp, sample_t inSamp, int channel, float lpCutoff, sample_rate_t sampleRate) -{ - // "if" statement is here so the filter coefficients only need to be calculated when they change - if (m_prevLPCutoff[channel] != lpCutoff) - { - m_prevLPCutoff[channel] = lpCutoff; - const float w0 = D_2PI * lpCutoff / sampleRate; - const float tempCosW0 = cos(w0); - const float alpha = sin(w0) / 0.3535f; - - m_LPa0 = 1 + alpha; - m_LPb0 = (1 - tempCosW0) * 0.5f; - m_LPb1 = 1 - tempCosW0; - m_LPa1 = -(2 * tempCosW0); - m_LPa2 = 1 - alpha; - } - - m_filtLPY[channel][0] = (m_LPb0 * (inSamp + m_filtLPX[channel][2]) + m_LPb1 * m_filtLPX[channel][1] - - m_LPa1 * m_filtLPY[channel][1] - m_LPa2 * m_filtLPY[channel][2]) / m_LPa0; - - m_filtLPX[channel][2] = m_filtLPX[channel][1]; - m_filtLPX[channel][1] = inSamp; - m_filtLPY[channel][2] = m_filtLPY[channel][1]; - m_filtLPY[channel][1] = m_filtLPY[channel][0]; - - outSamp = m_filtLPY[channel][0]; -} - - - -inline void DisintegratorEffect::calcHighpassFilter(sample_t &outSamp, sample_t inSamp, int channel, float hpCutoff, sample_rate_t sampleRate) -{ - // "if" statement is here so the filter coefficients only need to be calculated when they change - if (m_prevHPCutoff[channel] != hpCutoff) - { - m_prevHPCutoff[channel] = hpCutoff; - const float w0 = D_2PI * hpCutoff / sampleRate; - const float tempCosW0 = cos(w0); - const float alpha = sin(w0) / 0.3535f; - - m_HPa0 = 1 + alpha; - m_HPb0 = (1 + tempCosW0) * 0.5f; - m_HPb1 = -(1 + tempCosW0); - m_HPa1 = -2 * tempCosW0; - m_HPa2 = 1 - alpha; - } - - m_filtHPY[channel][0] = (m_HPb0 * (inSamp + m_filtHPX[channel][2]) + m_HPb1 * m_filtHPX[channel][1] - - m_HPa1 * m_filtHPY[channel][1] - m_HPa2 * m_filtHPY[channel][2]) / m_HPa0; - - m_filtHPX[channel][2] = m_filtHPX[channel][1]; - m_filtHPX[channel][1] = inSamp; - m_filtHPY[channel][2] = m_filtHPY[channel][1]; - m_filtHPY[channel][1] = m_filtHPY[channel][0]; - - outSamp = m_filtHPY[channel][0]; -} - - - // Handles negative values properly, unlike fmod. inline float DisintegratorEffect::realfmod(float k, float n) { @@ -273,6 +233,14 @@ inline float DisintegratorEffect::realfmod(float k, float n) +void DisintegratorEffect::clearFilterHistories() +{ + m_lp.clearHistory(); + m_hp.clearHistory(); +} + + + extern "C" { diff --git a/plugins/Disintegrator/Disintegrator.h b/plugins/Disintegrator/Disintegrator.h index 04c7bdb82..cd7642f71 100644 --- a/plugins/Disintegrator/Disintegrator.h +++ b/plugins/Disintegrator/Disintegrator.h @@ -28,6 +28,7 @@ #include "DisintegratorControls.h" +#include "BasicFilters.h" #include "Effect.h" #include "ValueBuffer.h" @@ -47,30 +48,11 @@ public: return &m_disintegratorControls; } + void sampleRateChanged(); + inline float realfmod(float k, float n); - inline void calcLowpassFilter(sample_t &outSamp, sample_t inSamp, int channel, float lpCutoff, sample_rate_t sampleRate); - inline void calcHighpassFilter(sample_t &outSamp, sample_t inSamp, int channel, float lpCutoff, sample_rate_t sampleRate); - - float m_filtLPX[2][3] = {{0}};// [filter number][samples back in time] - float m_filtLPY[2][3] = {{0}};// [filter number][samples back in time] - float m_prevLPCutoff[2] = {0}; - - float m_LPa0; - float m_LPb0; - float m_LPb1; - float m_LPa1; - float m_LPa2; - - float m_filtHPX[2][3] = {{0}};// [filter number][samples back in time] - float m_filtHPY[2][3] = {{0}};// [filter number][samples back in time] - float m_prevHPCutoff[2] = {0}; - - float m_HPa0; - float m_HPb0; - float m_HPb1; - float m_HPa1; - float m_HPa2; + void clearFilterHistories(); private: DisintegratorControls m_disintegratorControls; @@ -80,6 +62,10 @@ private: float m_sineLoc = 0; + StereoLinkwitzRiley m_lp; + StereoLinkwitzRiley m_hp; + bool m_needsUpdate; + friend class DisintegratorControls; } ; diff --git a/plugins/Disintegrator/DisintegratorControls.cpp b/plugins/Disintegrator/DisintegratorControls.cpp index a628cfbeb..7528066f1 100644 --- a/plugins/Disintegrator/DisintegratorControls.cpp +++ b/plugins/Disintegrator/DisintegratorControls.cpp @@ -50,6 +50,8 @@ DisintegratorControls::DisintegratorControls(DisintegratorEffect* effect) : m_typeModel.addItem(tr("Mono Noise")); m_typeModel.addItem(tr("Stereo Noise")); m_typeModel.addItem(tr("Sine Wave")); + + connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); } @@ -71,4 +73,14 @@ void DisintegratorControls::loadSettings(const QDomElement& _this) m_amountModel.loadSettings(_this, "amount"); m_typeModel.loadSettings(_this, "type"); m_freqModel.loadSettings(_this, "freq"); + + m_effect->m_needsUpdate = true; + m_effect->clearFilterHistories(); +} + + + +void DisintegratorControls::sampleRateChanged() +{ + m_effect->sampleRateChanged(); } diff --git a/plugins/Disintegrator/DisintegratorControls.h b/plugins/Disintegrator/DisintegratorControls.h index c8611cf92..11316cc08 100644 --- a/plugins/Disintegrator/DisintegratorControls.h +++ b/plugins/Disintegrator/DisintegratorControls.h @@ -62,6 +62,9 @@ public: return m_effectView; } +private slots: + void sampleRateChanged(); + private: DisintegratorEffect* m_effect; DisintegratorControlDialog * m_effectView;