From a3cce23d6d1e26a6f5aaed7e99ef09a52f7920d0 Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 13 Nov 2014 19:11:34 +0200 Subject: [PATCH] Even more filters --- include/basic_filters.h | 80 ++++++++++++++++++++++++----- src/core/InstrumentSoundShaping.cpp | 1 + 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index 52465e17d..5a70ed264 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -43,6 +43,7 @@ #include "templates.h" #include "lmms_constants.h" #include "interpolation.h" +#include "MemoryManager.h" //#include //#include @@ -50,6 +51,7 @@ template class basicFilters { + MM_OPERATORS public: enum FilterTypes { @@ -74,8 +76,9 @@ public: Highpass_SV, Notch_SV, FastFormant, + Tripole, NumFilters - } ; + }; static inline float minFreq() { @@ -149,6 +152,9 @@ public: m_y1[_chnl] = m_y2[_chnl] = m_y3[_chnl] = m_y4[_chnl] = m_oldx[_chnl] = m_oldy1[_chnl] = m_oldy2[_chnl] = m_oldy3[_chnl] = 0.0f; + + // tripole + m_last[_chnl] = 0.0f; // reset in/out history for RC-filters m_rclp0[_chnl] = m_rcbp0[_chnl] = m_rchp0[_chnl] = m_rclast0[_chnl] = 0.0f; @@ -177,22 +183,22 @@ public: // four cascaded onepole filters // (bilinear transform) - m_y1[_chnl] = tLimit( + m_y1[_chnl] = qBound( -10.0f, ( x + m_oldx[_chnl] ) * m_p - m_k * m_y1[_chnl], - -10.0f, 10.0f ); - m_y2[_chnl] = tLimit( + 10.0f ); + m_y2[_chnl] = qBound( -10.0f, ( m_y1[_chnl] + m_oldy1[_chnl] ) * m_p - m_k * m_y2[_chnl], - -10.0f, 10.0f ); - m_y3[_chnl] = tLimit( + 10.0f ); + m_y3[_chnl] = qBound( -10.0f, ( m_y2[_chnl] + m_oldy2[_chnl] ) * m_p - m_k * m_y3[_chnl], - -10.0f, 10.0f ); - m_y4[_chnl] = tLimit( + 10.0f ); + m_y4[_chnl] = qBound( -10.0f, ( m_y3[_chnl] + m_oldy3[_chnl] ) * m_p - m_k * m_y4[_chnl], - -10.0f, 10.0f ); + 10.0f ); m_oldx[_chnl] = x; m_oldy1[_chnl] = m_y1[_chnl]; @@ -203,6 +209,40 @@ public: break; } + // 3x onepole filters with 4x oversampling and interpolation of oversampled signal: + // input signal is linear-interpolated after oversampling, output signal is averaged from oversampled outputs + case Tripole: + { + out = 0.0f; + float ip = 0.0f; + for( int i = 0; i < 4; ++i ) + { + ip += 0.25f; + sample_t x = linearInterpolate( m_last[_chnl], _in0, ip ) - m_r * m_y3[_chnl]; + + m_y1[_chnl] = qBound( -10.0f, + ( x + m_oldx[_chnl] ) * m_p + - m_k * m_y1[_chnl], + 10.0f ); + m_y2[_chnl] = qBound( -10.0f, + ( m_y1[_chnl] + m_oldy1[_chnl] ) * m_p + - m_k * m_y2[_chnl], + 10.0f ); + m_y3[_chnl] = qBound( -10.0f, + ( m_y2[_chnl] + m_oldy2[_chnl] ) * m_p + - m_k * m_y3[_chnl], + 10.0f ); + m_oldx[_chnl] = x; + m_oldy1[_chnl] = m_y1[_chnl]; + m_oldy2[_chnl] = m_y2[_chnl]; + + out += ( m_y3[_chnl] - m_y3[_chnl] * m_y3[_chnl] * m_y3[_chnl] * ( 1.0f / 6.0f ) ); + } + out *= 0.25f; + m_last[_chnl] = _in0; + break; + } + // 4-pole state-variant lowpass filter, adapted from Nekobee source code // and extended to other SV filter types // /* Hal Chamberlin's state variable filter */ @@ -264,7 +304,7 @@ public: } /* mix filter output into output buffer */ - out = atanf( 1.5f * ( m_delay4[_chnl] + hp2 ) * m_sva[_chnl] ); + out = atanf( 1.5f * ( m_delay4[_chnl] + hp1 ) * m_sva[_chnl] ); break; } @@ -560,10 +600,11 @@ public: _freq = qBound( minFreq(), _freq, 20000.0f ); // limit freq and q for not getting bad noise out of the filter... // formats for a, e, i, o, u, a - static const float _f[5][2] = { { 1000, 1400 }, { 500, 2300 }, + static const float _f[6][2] = { { 1000, 1400 }, { 500, 2300 }, { 320, 3200 }, { 500, 1000 }, - { 320, 800 } }; + { 320, 800 }, + { 1000, 1400 } }; static const float freqRatio = 4.0f / 14000.0f; // Stretch Q/resonance @@ -604,7 +645,7 @@ public: // (Empirical tunning) m_p = ( 3.6f - 3.2f * f ) * f; m_k = 2.0f * m_p - 1; - m_r = _q * powf( M_E, ( 1 - m_p ) * 1.386249f ); + m_r = _q * powf( F_E, ( 1 - m_p ) * 1.386249f ); if( m_doubleFilter ) { @@ -614,6 +655,17 @@ public: } return; } + + if( m_type == Tripole ) + { + const float f = qBound( 20.0f, _freq, 20000.0f ) * m_sampleRatio * 0.25f; + + m_p = ( 3.6f - 3.2f * f ) * f; + m_k = 2.0f * m_p - 1.0f; + m_r = _q * 0.1f * powf( F_E, ( 1 - m_p ) * 1.386249f ); + + return; + } if( m_type == Lowpass_SV || m_type == Bandpass_SV || @@ -710,6 +762,8 @@ private: // 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 + frame m_last; // in/out history for RC-type-filters frame m_rcbp0, m_rclp0, m_rchp0, m_rclast0; diff --git a/src/core/InstrumentSoundShaping.cpp b/src/core/InstrumentSoundShaping.cpp index 4e32c9740..f815be85b 100644 --- a/src/core/InstrumentSoundShaping.cpp +++ b/src/core/InstrumentSoundShaping.cpp @@ -100,6 +100,7 @@ InstrumentSoundShaping::InstrumentSoundShaping( m_filterModel.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) ); m_filterModel.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) ); m_filterModel.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) ); + m_filterModel.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) ); }