Merge pull request #1230 from diizy/newfilter

New filters: SV Lowpass, SV Bandpass, SV Highpass, DoubleMoog
This commit is contained in:
Vesa V
2014-10-22 16:23:41 +03:00
3 changed files with 102 additions and 16 deletions

View File

@@ -3,6 +3,9 @@
*
* original file by ???
* modified and enhanced by Tobias Doerffel
*
* Lowpass_SV code originally from Nekobee, Copyright (C) 2004 Sean Bolton and others
* adapted & modified for use in LMMS
*
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -65,12 +68,16 @@ public:
Bandpass_RC24,
Highpass_RC24,
Formantfilter,
DoubleMoog,
Lowpass_SV,
Bandpass_SV,
Highpass_SV,
NumFilters
} ;
static inline float minFreq()
{
return( 3.0f );
return( 5.0f );
}
static inline float minQ()
@@ -80,7 +87,7 @@ public:
inline void setFilterType( const int _idx )
{
m_doubleFilter = _idx == DoubleLowPass;
m_doubleFilter = _idx == DoubleLowPass || _idx == DoubleMoog;
if( !m_doubleFilter )
{
m_type = static_cast<FilterTypes>( _idx );
@@ -89,7 +96,9 @@ public:
// Double lowpass mode, backwards-compat for the goofy
// Add-NumFilters to signify doubleFilter stuff
m_type = static_cast<FilterTypes>( LowPass );
m_type = _idx == DoubleLowPass
? LowPass
: Moog;
if( m_subFilter == NULL )
{
m_subFilter = new basicFilters<CHANNELS>(
@@ -108,10 +117,15 @@ public:
m_rca( 0.0f ),
m_rcb( 1.0f ),
m_rcc( 0.0f ),
m_svf1( 0.0f ),
m_svf2( 0.0f ),
m_svq( 0.0f ),
m_doubleFilter( false ),
m_sampleRate( (float) _sample_rate ),
m_sampleRatio( 1.0f / m_sampleRate ),
m_subFilter( NULL )
{
m_svsr = 1.0f - expf( -4646.39874051f / m_sampleRate );
clearHistory();
}
@@ -140,6 +154,13 @@ public:
for(int i=0; i<6; i++)
m_vfbp[i][_chnl] = m_vfhp[i][_chnl] = m_vflast[i][_chnl] = 0.0f;
// reset in/out history for SV-filters
m_delay1[_chnl] = 0.0f;
m_delay2[_chnl] = 0.0f;
m_delay3[_chnl] = 0.0f;
m_delay4[_chnl] = 0.0f;
m_sva[_chnl] = 0.0f;
}
}
@@ -179,6 +200,41 @@ public:
m_y4[_chnl] * ( 1.0f / 6.0f );
break;
}
// 4-pole state-variant lowpass filter, adapted from Nekobee source code
// /* Hal Chamberlin's state variable filter */
case Lowpass_SV:
case Bandpass_SV:
{
m_sva[_chnl] += ( qAbs( _in0 ) - m_sva[_chnl] ) * m_svsr;
m_delay2[_chnl] = m_delay2[_chnl] + m_svf1 * m_delay1[_chnl]; /* delay2/4 = lowpass output */
float highpass = _in0 - m_delay2[_chnl] - m_svq * m_delay1[_chnl];
m_delay1[_chnl] = m_svf1 * highpass + m_delay1[_chnl]; /* delay1/3 = bandpass output */
m_delay4[_chnl] = m_delay4[_chnl] + m_svf2 * m_delay3[_chnl];
highpass = m_delay2[_chnl] - m_delay4[_chnl] - m_svq * m_delay3[_chnl];
m_delay3[_chnl] = m_svf2 * highpass + m_delay3[_chnl];
/* mix filter output into output buffer */
out = m_type == Lowpass_SV
? atanf( 3.0f * m_delay4[_chnl] * m_sva[_chnl] )
: atanf( 3.0f * m_delay3[_chnl] * m_sva[_chnl] );
break;
}
case Highpass_SV:
{
m_sva[_chnl] += ( qAbs( _in0 ) - m_sva[_chnl] ) * m_svsr;
m_delay2[_chnl] = m_delay2[_chnl] + m_svf1 * m_delay1[_chnl];
float hp = _in0 - m_delay2[_chnl] - m_svq * m_delay1[_chnl];
m_delay1[_chnl] = m_svf1 * hp + m_delay1[_chnl];
out = atanf( 3.0f * hp * m_sva[_chnl] );
break;
}
// 4-times oversampled simulation of an active RC-Bandpass,-Lowpass,-Highpass-
@@ -351,8 +407,8 @@ public:
m_vflast[2][_chnl] = in;
m_vfhp[2][_chnl] = hp;
m_vfbp[2][_chnl] = bp;
m_vfbp[2][_chnl] = bp;
in = bp + m_vfbp[4][_chnl] * m_vfq;
in = qBound( -1.0f, in, 1.0f );
@@ -364,7 +420,7 @@ public:
m_vflast[4][_chnl] = in;
m_vfhp[4][_chnl] = hp;
m_vfbp[4][_chnl] = bp;
m_vfbp[4][_chnl] = bp;
out += bp;
@@ -393,7 +449,7 @@ public:
m_vflast[3][_chnl] = in;
m_vfhp[3][_chnl] = hp;
m_vfbp[3][_chnl] = bp;
m_vfbp[3][_chnl] = bp;
in = bp + m_vfbp[5][_chnl] * m_vfq;
in = qBound( -1.0f, in, 1.0f );
@@ -406,7 +462,7 @@ public:
m_vflast[5][_chnl] = in;
m_vfhp[5][_chnl] = hp;
m_vfbp[5][_chnl] = bp;
m_vfbp[5][_chnl] = bp;
out += bp;
}
@@ -441,8 +497,7 @@ public:
}
inline void calcFilterCoeffs( float _freq, float _q
/*, const bool _q_is_bandwidth = false*/ )
inline void calcFilterCoeffs( float _freq, float _q )
{
// temp coef vars
_q = qMax( _q, minQ() );
@@ -506,12 +561,13 @@ public:
return;
}
if( m_type == Moog )
if( m_type == Moog ||
m_type == DoubleMoog )
{
_freq = qBound( minFreq(), _freq, 20000.0f );
_freq = qBound( minFreq(), _freq, 20000.0f );
// [ 0 - 0.5 ]
const float f = _freq / m_sampleRate;
const float f = _freq * m_sampleRatio;
// (Empirical tunning)
m_p = ( 3.6f - 3.2f * f ) * f;
m_k = 2.0f * m_p - 1;
@@ -526,9 +582,20 @@ public:
return;
}
if( m_type == Lowpass_SV ||
m_type == Bandpass_SV ||
m_type == Highpass_SV )
{
const float f = qMax( minFreq(), _freq ) * m_sampleRatio;
m_svf1 = qMin( f * 2.0f, 0.825f );
m_svf2 = qMin( f * 4.0f, 0.825f );
m_svq = qMax( 0.0001f, 2.0f - ( _q * 0.1995f ) );
return;
}
// other filters
_freq = qBound( minFreq(), _freq, 20000.0f );
const float omega = F_2PI * _freq / m_sampleRate;
_freq = qBound( minFreq(), _freq, 20000.0f );
const float omega = F_2PI * _freq * m_sampleRatio;
const float tsin = sinf( omega );
const float tcos = cosf( omega );
//float alpha;
@@ -604,6 +671,9 @@ private:
// coeffs for formant-filters
float m_vfa[4], m_vfb[4], m_vfc[4], m_vfq;
// coeffs for Lowpass_SV (state-variant lowpass)
float m_svf1, m_svf2, m_svq, m_svsr;
typedef sample_t frame[CHANNELS];
// in/out history
@@ -618,11 +688,15 @@ private:
// in/out history for Formant-filters
frame m_vfbp[6], m_vfhp[6], m_vflast[6];
// in/out history for Lowpass_SV (state-variant lowpass)
frame m_delay1, m_delay2, m_delay3, m_delay4, m_sva;
FilterTypes m_type;
bool m_doubleFilter;
float m_sampleRate;
float m_sampleRatio;
basicFilters<CHANNELS> * m_subFilter;
} ;

View File

@@ -74,6 +74,10 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
m_filter1Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filter1Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) );
@@ -90,6 +94,10 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
m_filter2Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filter2Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFilters() ) );
}

View File

@@ -94,6 +94,10 @@ InstrumentSoundShaping::InstrumentSoundShaping(
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" ) );
m_filterModel.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filterModel.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
}