Merge pull request #1372 from diizy/multitap
Separate BiQuad, OnePole filters as their own classes in BasicFilters.h
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