From 60758172b02e2a61eeb3b6dabe981c6235e5c31d Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Sun, 8 Mar 2009 15:07:09 +0100 Subject: [PATCH] Standard filters: added 24 dB versions of RC filters as well as a vocal format filter Thanks to Stefan Fendt! (cherry picked from commit f5057ce6d2ce5922fa921da835c61f489c3e11ed) --- include/basic_filters.h | 334 +++++++++++++++++++++++++--- src/core/InstrumentSoundShaping.cpp | 10 +- 2 files changed, 316 insertions(+), 28 deletions(-) diff --git a/include/basic_filters.h b/include/basic_filters.h index 64d10ca86..ee986b0e2 100644 --- a/include/basic_filters.h +++ b/include/basic_filters.h @@ -57,9 +57,13 @@ public: AllPass, Moog, DoubleLowPass, - Lowpass_RC, - Bandpass_RC, - Highpass_RC, + Lowpass_RC12, + Bandpass_RC12, + Highpass_RC12, + Lowpass_RC24, + Bandpass_RC24, + Highpass_RC24, + Formantfilter, NumFilters } ; @@ -124,13 +128,17 @@ public: m_ou1[_chnl] = m_ou2[_chnl] = m_in1[_chnl] = m_in2[_chnl] = 0.0f; - // reset in/out historey for moog-filter + // 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] = m_oldy2[_chnl] = m_oldy3[_chnl] = 0.0f; - // reset in/out historey for RC-filter - m_rclp[_chnl] = m_rcbp[_chnl] = m_rchp[_chnl] = m_rclast[_chnl] = 0.0f; + // reset in/out history for RC-filters + m_rclp0[_chnl] = m_rcbp0[_chnl] = m_rchp0[_chnl] = m_rclast0[_chnl] = 0.0f; + m_rclp1[_chnl] = m_rcbp1[_chnl] = m_rchp1[_chnl] = m_rclast1[_chnl] = 0.0f; + + for(int i=0; i<6; i++) + m_vflp[i][_chnl] = m_vfbp[i][_chnl] = m_vfhp[i][_chnl] = m_vflast[i][_chnl] = 0.0f; } } @@ -177,43 +185,42 @@ public: // can be driven up to self-oscillation (BTW: do not remove the limits!!!). // (C) 1998 ... 2009 S.Fendt. Released under the GPL v2.0 or any later version. - case Lowpass_RC: - case Bandpass_RC: - case Highpass_RC: + case Lowpass_RC12: + case Bandpass_RC12: + case Highpass_RC12: { sample_t lp, hp, bp; sample_t in; - // 4-times oversampled... (even the moog would benefit from this) + // 4-times oversampled... (even the moog-filter would benefit from this) for( int n = 4; n != 0; --n ) { - in = _in0 + m_rcbp[_chnl] * m_rcq; + in = _in0 + m_rcbp0[_chnl] * m_rcq; in = (in > +1.f) ? +1.f : in; in = (in < -1.f) ? -1.f : in; - lp = in * m_rcb + m_rclp[_chnl] * m_rca; + lp = in * m_rcb + m_rclp0[_chnl] * m_rca; lp = (lp > +1.f) ? +1.f : lp; lp = (lp < -1.f) ? -1.f : lp; - hp = m_rcc * ( m_rchp[_chnl] + in - m_rclast[_chnl] ); + hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); hp = (hp > +1.f) ? +1.f : hp; hp = (hp < -1.f) ? -1.f : hp; - bp = hp * m_rcb + m_rcbp[_chnl] * m_rca; + bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; bp = (bp > +1.f) ? +1.f : bp; bp = (bp < -1.f) ? -1.f : bp; - m_rclast[_chnl] = in; - m_rclp[_chnl] = lp; - m_rchp[_chnl] = hp; - m_rcbp[_chnl] = bp; - + m_rclast0[_chnl] = in; + m_rclp0[_chnl] = lp; + m_rchp0[_chnl] = hp; + m_rcbp0[_chnl] = bp; } - if( m_type == Lowpass_RC ) + if( m_type == Lowpass_RC12 ) out = lp; - else if( m_type == Bandpass_RC ) + else if( m_type == Bandpass_RC12 ) out = bp; else out = hp; @@ -222,7 +229,234 @@ public: break; } + case Lowpass_RC24: + case Bandpass_RC24: + case Highpass_RC24: + { + sample_t lp, hp, bp; + sample_t in; + + for( int n = 4; n != 0; --n ) + { + // first stage is as for the 12dB case... + in = _in0 + m_rcbp0[_chnl] * m_rcq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_rcb + m_rclp0[_chnl] * m_rca; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_rcc * ( m_rchp0[_chnl] + in - m_rclast0[_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_rcb + m_rcbp0[_chnl] * m_rca; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_rclast0[_chnl] = in; + m_rclp0[_chnl] = lp; + m_rchp0[_chnl] = hp; + m_rcbp0[_chnl] = bp; + + // second stage gets the output of the first stage as input... + if( m_type == Lowpass_RC24 ) + { + in = lp + m_rcbp1[_chnl] * m_rcq; + } + else if( m_type == Bandpass_RC24 ) + { + in = bp + m_rcbp1[_chnl] * m_rcq; + } + else + { + in = hp + m_rcbp1[_chnl] * m_rcq; + } + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_rcb + m_rclp1[_chnl] * m_rca; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_rcc * ( m_rchp1[_chnl] + in - m_rclast1[_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_rcb + m_rcbp1[_chnl] * m_rca; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_rclast1[_chnl] = in; + m_rclp1[_chnl] = lp; + m_rchp1[_chnl] = hp; + m_rcbp1[_chnl] = bp; + } + + // output is second stage-lowpass... + if( m_type == Lowpass_RC24 ) + { + out = lp; + } + else if( m_type == Bandpass_RC24 ) + { + out = bp; + } + else + { + out = hp; + } + + return out; + break; + } + + case Formantfilter: + { + sample_t lp, hp, bp, in; + + out = 0; + for(int o=0; o<4; o++) + { + // first formant + in = _in0 + m_vfbp[0][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[0] + m_vflp[0][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[0] * ( m_vfhp[0][_chnl] + in - m_vflast[0][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[0] + m_vfbp[0][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[0][_chnl] = in; + m_vflp[0][_chnl] = lp; + m_vfhp[0][_chnl] = hp; + m_vfbp[0][_chnl] = bp; + + in = bp + m_vfbp[2][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[0] + m_vflp[2][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[0] * ( m_vfhp[2][_chnl] + in - m_vflast[2][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[0] + m_vfbp[2][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[2][_chnl] = in; + m_vflp[2][_chnl] = lp; + m_vfhp[2][_chnl] = hp; + m_vfbp[2][_chnl] = bp; + + in = bp + m_vfbp[4][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[0] + m_vflp[4][_chnl] * m_vfa[0]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[0] * ( m_vfhp[4][_chnl] + in - m_vflast[4][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[0] + m_vfbp[4][_chnl] * m_vfa[0]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[4][_chnl] = in; + m_vflp[4][_chnl] = lp; + m_vfhp[4][_chnl] = hp; + m_vfbp[4][_chnl] = bp; + + out += bp; + + // second formant + in = _in0 + m_vfbp[0][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[1] + m_vflp[1][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[1] * ( m_vfhp[1][_chnl] + in - m_vflast[1][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[1] + m_vfbp[1][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[1][_chnl] = in; + m_vflp[1][_chnl] = lp; + m_vfhp[1][_chnl] = hp; + m_vfbp[1][_chnl] = bp; + + in = bp + m_vfbp[3][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[1] + m_vflp[3][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[1] * ( m_vfhp[3][_chnl] + in - m_vflast[3][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[1] + m_vfbp[3][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[3][_chnl] = in; + m_vflp[3][_chnl] = lp; + m_vfhp[3][_chnl] = hp; + m_vfbp[3][_chnl] = bp; + + in = bp + m_vfbp[5][_chnl] * m_vfq; + in = (in > +1.f) ? +1.f : in; + in = (in < -1.f) ? -1.f : in; + + lp = in * m_vfb[1] + m_vflp[5][_chnl] * m_vfa[1]; + lp = (lp > +1.f) ? +1.f : lp; + lp = (lp < -1.f) ? -1.f : lp; + + hp = m_vfc[1] * ( m_vfhp[5][_chnl] + in - m_vflast[5][_chnl] ); + hp = (hp > +1.f) ? +1.f : hp; + hp = (hp < -1.f) ? -1.f : hp; + + bp = hp * m_vfb[1] + m_vfbp[5][_chnl] * m_vfa[1]; + bp = (bp > +1.f) ? +1.f : bp; + bp = (bp < -1.f) ? -1.f : bp; + + m_vflast[5][_chnl] = in; + m_vflp[5][_chnl] = lp; + m_vfhp[5][_chnl] = hp; + m_vfbp[5][_chnl] = bp; + + out += bp; + } + + return( out/2.0f ); + break; + } + default: // filter out = m_b0a0*_in0 + @@ -258,9 +492,12 @@ public: // bad noise out of the filter... _q = qMax( _q, minQ() ); - if( m_type == Lowpass_RC || - m_type == Bandpass_RC || - m_type == Highpass_RC ) + if( m_type == Lowpass_RC12 || + m_type == Bandpass_RC12 || + m_type == Highpass_RC12 || + m_type == Lowpass_RC24 || + m_type == Bandpass_RC24 || + m_type == Highpass_RC24 ) { if( _freq < 50.f ) { @@ -274,6 +511,46 @@ public: // Stretch Q/resonance, as self-oscillation reliably starts at a q of ~2.5 - ~2.6 m_rcq = _q/4.f; } + + if( m_type == Formantfilter ) + { + // formats for a, e, i, o, u, a + const float _f[5][2] = { { 1000, 1400 }, { 500, 2300 }, + { 320, 3200 }, + { 500, 1000 }, + { 320, 800 } }; + + // Stretch Q/resonance + m_vfq = _q/4.f; + + // frequency in lmms ranges from 1Hz to 14000Hz + const int vowel = (int)( floor( _freq/14000.f * 4.f ) ); + const float fract = ( _freq/14000.f * 4.f ) - + (float)vowel; + + // interpolate between formant frequencies + const float f0 = _f[vowel+0][0] * ( 1.0f - fract ) + + _f[vowel+1][0] * ( fract ); + + const float f1 = _f[vowel+0][1] * ( 1.0f - fract ) + + _f[vowel+1][1] * ( fract ); + + m_vfa[0] = 1.0f - (1.0f/(m_sampleRate*4)) / + ( (1.0f/(f0*2.0f*M_PI)) + + (1.0f/(m_sampleRate*4)) ); + m_vfb[0] = 1.0f - m_vfa[0]; + m_vfc[0] = (1.0f/(f0*2.0f*M_PI)) / + ( (1.0f/(f0*2.0f*M_PI)) + + (1.0f/(m_sampleRate*4)) ); + + m_vfa[1] = 1.0f - (1.0f/(m_sampleRate*4)) / + ( (1.0f/(f1*2.0f*M_PI)) + + (1.0f/(m_sampleRate*4)) ); + m_vfb[1] = 1.0f - m_vfa[1]; + m_vfc[1] = (1.0f/(f1*2.0f*M_PI)) / + ( (1.0f/(f1*2.0f*M_PI)) + + (1.0f/(m_sampleRate*4)) ); + } if( m_type == Moog ) { @@ -367,6 +644,9 @@ private: // coeffs for RC-type-filters float m_rca, m_rcb, m_rcc, m_rcq; + // coeffs for formant-filters + float m_vfa[4], m_vfb[4], m_vfc[4], m_vfq; + typedef sample_t frame[CHANNELS]; // in/out history @@ -376,8 +656,12 @@ private: frame m_y1, m_y2, m_y3, m_y4, m_oldx, m_oldy1, m_oldy2, m_oldy3; // in/out history for RC-type-filters - frame m_rcbp, m_rclp, m_rchp, m_rclast; + frame m_rcbp0, m_rclp0, m_rchp0, m_rclast0; + frame m_rcbp1, m_rclp1, m_rchp1, m_rclast1; + // in/out history for Formant-filters + frame m_vfbp[6], m_vflp[6], m_vfhp[6], m_vflast[6]; + FilterTypes m_type; bool m_doubleFilter; diff --git a/src/core/InstrumentSoundShaping.cpp b/src/core/InstrumentSoundShaping.cpp index 3020bf702..edd456a18 100644 --- a/src/core/InstrumentSoundShaping.cpp +++ b/src/core/InstrumentSoundShaping.cpp @@ -87,9 +87,13 @@ InstrumentSoundShaping::InstrumentSoundShaping( m_filterModel.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) ); m_filterModel.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) ); m_filterModel.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) ); - m_filterModel.addItem( tr( "RC LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "RC BandPass" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "RC HighPass" ), new PixmapLoader( "filter_hp" ) ); + m_filterModel.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) ); + m_filterModel.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) ); + m_filterModel.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) ); }