From be04040ae810c46379a6d799c3962984aadd6844 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 30 Nov 2014 14:33:04 +0200 Subject: [PATCH] Separate BiQuad, OnePole filters as their own classes in BasicFilters.h Might do the same for other filter types, but these two are kind of "basic building blocks" for many effects so it makes most sense for them --- include/BasicFilters.h | 149 +++++++++++++++++++------- plugins/MultitapEcho/MultitapEcho.cpp | 15 ++- plugins/MultitapEcho/MultitapEcho.h | 35 ++---- 3 files changed, 125 insertions(+), 74 deletions(-) diff --git a/include/BasicFilters.h b/include/BasicFilters.h index 8842b0dc9..ba04b609c 100644 --- a/include/BasicFilters.h +++ b/include/BasicFilters.h @@ -47,8 +47,85 @@ //#include //#include +template class BasicFilters; +template +class BiQuad +{ + MM_OPERATORS +public: + BiQuad() + { + clearHistory(); + } + virtual ~BiQuad() {} + + inline void setCoeffs( float a1, float a2, float b0, float b1, float b2 ) + { + m_a1 = a1; + m_a2 = a2; + m_b0 = b0; + m_b1 = b1; + m_b2 = b2; + } + inline void clearHistory() + { + for( int i = 0; i < CHANNELS; ++i ) + { + m_z1[i] = 0.0f; + m_z2[i] = 0.0f; + } + } + inline float update( float in, ch_cnt_t ch ) + { + // biquad filter in transposed form + const float out = m_z1[ch] + m_b0 * in; + m_z1[ch] = m_b1 * in + m_z2[ch] - m_a1 * out; + m_z2[ch] = m_b2 * in - m_a2 * out; + return out; + } +private: + float m_a1, m_a2, m_b0, m_b1, m_b2; + float m_z1 [CHANNELS], m_z2 [CHANNELS]; + + friend class BasicFilters; +}; +typedef BiQuad<2> StereoBiQuad; -template +template +class OnePole +{ + MM_OPERATORS +public: + OnePole() + { + m_a0 = 1.0; + m_b1 = 0.0; + for( int i = 0; i < CHANNELS; ++i ) + { + m_z1[i] = 0.0; + } + } + virtual ~OnePole() {} + + inline void setCoeffs( float a0, float b1 ) + { + m_a0 = a0; + m_b1 = b1; + } + + inline float update( float s, ch_cnt_t ch ) + { + if( s < 1.0e-10f && m_z1[ch] < 1.0e-10f ) return 0.0f; + return m_z1[ch] = s * m_a0 + m_z1[ch] * m_b1; + } + +private: + float m_a0, m_b1; + float m_z1 [CHANNELS]; +}; +typedef OnePole<2> StereoOnePole; + +template class BasicFilters { MM_OPERATORS @@ -130,12 +207,12 @@ public: inline void clearHistory() { + // reset in/out history for biquads + m_biQuad.clearHistory(); + // reset in/out history for( ch_cnt_t _chnl = 0; _chnl < CHANNELS; ++_chnl ) { - // reset in/out history for simple filters - m_z1[_chnl] = m_z2[_chnl] = 0.0f; - // reset in/out history for moog-filter m_y1[_chnl] = m_y2[_chnl] = m_y3[_chnl] = m_y4[_chnl] = m_oldx[_chnl] = m_oldy1[_chnl] = @@ -534,10 +611,7 @@ public: } default: - // biquad filter in transposed form - out = m_z1[_chnl] + m_b0a0 * _in0; - m_z1[_chnl] = m_b1a0 * _in0 + m_z2[_chnl] - m_a1a0 * out; - m_z2[_chnl] = m_b2a0 * _in0 - m_a2a0 * out; + out = m_biQuad.update( _in0, _chnl ); break; } @@ -665,59 +739,61 @@ public: const float a0 = 1.0f / ( 1.0f + alpha ); - m_a1a0 = -2.0f * tcos * a0; - m_a2a0 = ( 1.0f - alpha ) * a0; + const float a1 = -2.0f * tcos * a0; + const float a2 = ( 1.0f - alpha ) * a0; switch( m_type ) { case LowPass: - m_b1a0 = ( 1.0f - tcos ) * a0; - m_b0a0 = m_b1a0 * 0.5f; - m_b2a0 = m_b0a0;//((1.0f-tcos)/2.0f)*a0; + { + const float b1 = ( 1.0f - tcos ) * a0; + const float b0 = b1 * 0.5f; + m_biQuad.setCoeffs( a1, a2, b0, b1, b0 ); break; + } case HiPass: - m_b1a0 = ( -1.0f - tcos ) * a0; - m_b0a0 = m_b1a0 * -0.5f; - m_b2a0 = m_b0a0;//((1.0f+tcos)/2.0f)*a0; + { + const float b1 = ( -1.0f - tcos ) * a0; + const float b0 = b1 * -0.5f; + m_biQuad.setCoeffs( a1, a2, b0, b1, b0 ); break; + } case BandPass_CSG: - m_b1a0 = 0.0f; - m_b0a0 = tsin * a0; - m_b2a0 = -m_b0a0; + { + const float b0 = tsin * a0; + m_biQuad.setCoeffs( a1, a2, b0, 0.0f, -b0 ); break; + } case BandPass_CZPG: - m_b1a0 = 0.0f; - m_b0a0 = alpha * a0; - m_b2a0 = -m_b0a0; + { + const float b0 = alpha * a0; + m_biQuad.setCoeffs( a1, a2, b0, 0.0f, -b0 ); break; + } case Notch: - m_b1a0 = m_a1a0; - m_b0a0 = a0; - m_b2a0 = a0; + { + m_biQuad.setCoeffs( a1, a2, a0, a1, a0 ); break; + } case AllPass: - m_b1a0 = m_a1a0; - m_b0a0 = m_a2a0; - m_b2a0 = 1.0f;//(1.0f+alpha)*a0; + { + m_biQuad.setCoeffs( a1, a2, a2, a1, 1.0f ); break; + } default: break; } if( m_doubleFilter ) { - m_subFilter->m_b0a0 = m_b0a0; - m_subFilter->m_b1a0 = m_b1a0; - m_subFilter->m_b2a0 = m_b2a0; - m_subFilter->m_a1a0 = m_a1a0; - m_subFilter->m_a2a0 = m_a2a0; + m_subFilter->m_biQuad.setCoeffs( m_biQuad.m_a1, m_biQuad.m_a2, m_biQuad.m_b0, m_biQuad.m_b1, m_biQuad.m_b2 ); } } private: - // filter coeffs - float m_b0a0, m_b1a0, m_b2a0, m_a1a0, m_a2a0; + // biquad filter + BiQuad m_biQuad; // coeffs for moog-filter float m_r, m_p, m_k; @@ -733,9 +809,6 @@ private: typedef sample_t frame[CHANNELS]; - // in/out history - frame m_z1, m_z2; - // in/out history for moog-filter frame m_y1, m_y2, m_y3, m_y4, m_oldx, m_oldy1, m_oldy2, m_oldy3; // additional one for Tripole filter diff --git a/plugins/MultitapEcho/MultitapEcho.cpp b/plugins/MultitapEcho/MultitapEcho.cpp index 8c060b2ea..e3da02075 100644 --- a/plugins/MultitapEcho/MultitapEcho.cpp +++ b/plugins/MultitapEcho/MultitapEcho.cpp @@ -53,7 +53,7 @@ MultitapEchoEffect::MultitapEchoEffect( Model* parent, const Descriptor::SubPlug m_sampleRate( Engine::mixer()->processingSampleRate() ), m_sampleRatio( 1.0f / m_sampleRate ) { - m_work = new sampleFrame[ Engine::mixer()->framesPerPeriod() ]; + m_work = MM_ALLOC( sampleFrame, Engine::mixer()->framesPerPeriod() ); m_buffer.reset(); updateFilters( 0, 19 ); } @@ -61,16 +61,15 @@ MultitapEchoEffect::MultitapEchoEffect( Model* parent, const Descriptor::SubPlug MultitapEchoEffect::~MultitapEchoEffect() { - delete m_work; + MM_FREE( m_work ); } void MultitapEchoEffect::updateFilters( int begin, int end ) { for( int i = begin; i <= end; ++i ) - { - m_filter[i][0].setFc( m_lpFreq[i] * m_sampleRatio ); - m_filter[i][1].setFc( m_lpFreq[i] * m_sampleRatio ); + { + setFilterFreq( m_lpFreq[i] * m_sampleRatio, m_filter[i] ); } } @@ -79,8 +78,8 @@ void MultitapEchoEffect::runFilter( sampleFrame * dst, sampleFrame * src, Stereo { for( int f = 0; f < frames; ++f ) { - dst[f][0] = filter[0].update( src[f][0] ); - dst[f][1] = filter[1].update( src[f][1] ); + dst[f][0] = filter.update( src[f][0], 0 ); + dst[f][1] = filter.update( src[f][1], 1 ); } } @@ -119,7 +118,7 @@ bool MultitapEchoEffect::processAudioBuffer( sampleFrame * buf, const fpp_t fram else { float offset = stepLength; - for( int i = 0; i < steps; ++i ) // add all steps swapped + for( int i = 0; i < steps; ++i ) // add all steps { runFilter( m_work, buf, m_filter[i], frames ); m_buffer.writeAddingMultiplied( m_work, offset, frames, m_amp[i] ); diff --git a/plugins/MultitapEcho/MultitapEcho.h b/plugins/MultitapEcho/MultitapEcho.h index 50ac5a55f..d1c4cdfaa 100644 --- a/plugins/MultitapEcho/MultitapEcho.h +++ b/plugins/MultitapEcho/MultitapEcho.h @@ -31,34 +31,7 @@ #include "ValueBuffer.h" #include "RingBuffer.h" #include "lmms_math.h" - -class OnePole -{ -public: - OnePole() - { - m_a0 = 1.0; - m_b1 = 0.0; - m_z1 = 0.0; - } - virtual ~OnePole() {} - - inline void setFc( float fc ) - { - m_b1 = expf( -2.0f * F_PI * fc ); - m_a0 = 1.0f - m_b1; - } - - inline float update( float s ) - { - return m_z1 = s * m_a0 + m_z1 * m_b1; - } - -private: - float m_a0, m_b1, m_z1; -}; - -typedef OnePole StereoOnePole [2]; +#include "BasicFilters.h" class MultitapEchoEffect : public Effect { @@ -76,6 +49,12 @@ private: void updateFilters( int begin, int end ); void runFilter( sampleFrame * dst, sampleFrame * src, StereoOnePole & filter, const fpp_t frames ); + inline void setFilterFreq( float fc, StereoOnePole & f ) + { + const float b1 = expf( -2.0f * F_PI * fc ); + f.setCoeffs( 1.0f - b1, b1 ); + } + MultitapEchoControls m_controls; float m_amp [20];