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
This commit is contained in:
@@ -47,8 +47,85 @@
|
||||
|
||||
//#include <iostream>
|
||||
//#include <cstdlib>
|
||||
template<ch_cnt_t CHANNELS> class BasicFilters;
|
||||
template<ch_cnt_t CHANNELS>
|
||||
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<CHANNELS>;
|
||||
};
|
||||
typedef BiQuad<2> StereoBiQuad;
|
||||
|
||||
template<ch_cnt_t CHANNELS/* = DEFAULT_CHANNELS*/>
|
||||
template<ch_cnt_t CHANNELS>
|
||||
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<ch_cnt_t CHANNELS>
|
||||
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<CHANNELS> 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
|
||||
|
||||
@@ -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] );
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user