mirror of
https://github.com/thestk/stk
synced 2026-04-19 22:16:54 +00:00
Merge pull request #121 from navin-neu/biquad-filter-types
add support for different filter types in biquad
This commit is contained in:
@@ -13,10 +13,15 @@ namespace stk {
|
|||||||
Methods are provided for creating a resonance or notch in the
|
Methods are provided for creating a resonance or notch in the
|
||||||
frequency response while maintaining a constant filter gain.
|
frequency response while maintaining a constant filter gain.
|
||||||
|
|
||||||
|
Formulae used calculate coefficients for lowpass, highpass,
|
||||||
|
bandpass, bandreject and allpass are found on pg. 55 of
|
||||||
|
Udo Zölzer's "DAFX - Digital Audio Effects" (2011 2nd ed).
|
||||||
|
|
||||||
by Perry R. Cook and Gary P. Scavone, 1995--2021.
|
by Perry R. Cook and Gary P. Scavone, 1995--2021.
|
||||||
*/
|
*/
|
||||||
/***************************************************/
|
/***************************************************/
|
||||||
|
|
||||||
|
const StkFloat RECIP_SQRT_2 = static_cast<StkFloat>( M_SQRT1_2 );
|
||||||
class BiQuad : public Filter
|
class BiQuad : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -74,12 +79,72 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setNotch( StkFloat frequency, StkFloat radius );
|
void setNotch( StkFloat frequency, StkFloat radius );
|
||||||
|
|
||||||
|
//! Set the filter coefficients for a low-pass with cutoff frequency \e fc (in Hz) and Q-factor \e Q.
|
||||||
|
/*!
|
||||||
|
This method determines the filter coefficients corresponding to a
|
||||||
|
low-pass filter with cutoff placed at \e fc, where sloping behaviour
|
||||||
|
and resonance are determined by \e Q. The default value for \e Q is
|
||||||
|
1/sqrt(2), resulting in a gradual attenuation of frequencies higher than
|
||||||
|
\e fc without added resonance. Values greater than this will more
|
||||||
|
aggressively attenuate frequencies above \e fc while also adding a
|
||||||
|
resonance at \e fc. Values less than this will result in a more gradual
|
||||||
|
attenuation of frequencies above \e fc, but will also attenuate
|
||||||
|
frequencies below \e fc as well. Both \e fc and \e Q must be positive.
|
||||||
|
*/
|
||||||
|
void setLowPass( StkFloat fc, StkFloat Q=RECIP_SQRT_2 );
|
||||||
|
|
||||||
|
//! Set the filter coefficients for a high-pass with cutoff frequency \e fc (in Hz) and Q-factor \e Q.
|
||||||
|
/*!
|
||||||
|
This method determines the filter coefficients corresponding to a high-pass
|
||||||
|
filter with cutoff placed at \e fc, where sloping behaviour and resonance
|
||||||
|
are determined by \e Q. The default value for \e Q is 1/sqrt(2), resulting
|
||||||
|
in a gradual attenuation of frequencies lower than \e fc without added
|
||||||
|
resonance. Values greater than this will more aggressively attenuate
|
||||||
|
frequencies below \e fc while also adding a resonance at \e fc. Values less
|
||||||
|
than this will result in a more gradual attenuation of frequencies below
|
||||||
|
\e fc, but will also attenuate frequencies above \e fc as well.
|
||||||
|
Both \e fc and \e Q must be positive.
|
||||||
|
*/
|
||||||
|
void setHighPass( StkFloat fc, StkFloat Q=RECIP_SQRT_2 );
|
||||||
|
|
||||||
|
//! Set the filter coefficients for a band-pass centered at \e fc (in Hz) with Q-factor \e Q.
|
||||||
|
/*!
|
||||||
|
This method determines the filter coefficients corresponding to a band-pass
|
||||||
|
filter with pass-band centered at \e fc, where band width and slope a
|
||||||
|
determined by \e Q. Values for \e Q that are less than 1.0 will attenuate
|
||||||
|
frequencies above and below \e fc more gradually, resulting in a convex
|
||||||
|
slope and a wider band. Values for \e Q greater than 1.0 will attenuate
|
||||||
|
frequencies above and below \e fc more aggressively, resulting in a
|
||||||
|
concave slope and a narrower band. Both \e fc and \e Q must be positive.
|
||||||
|
*/
|
||||||
|
void setBandPass( StkFloat fc, StkFloat Q );
|
||||||
|
|
||||||
|
//! Set the filter coefficients for a band-reject centered at \e fc (in Hz) with Q-factor \e Q.
|
||||||
|
/*!
|
||||||
|
This method determines the filter coefficients corresponding to a
|
||||||
|
band-reject filter with stop-band centered at \e fc, where band width
|
||||||
|
and slope are determined by \e Q. Values for \e Q that are less than 1.0
|
||||||
|
will yield a wider band with greater attenuation of \e fc. Values for \e Q
|
||||||
|
greater than 1.0 will yield a narrower band with less attenuation of \e fc.
|
||||||
|
Both \e fc and \e Q must be positive.
|
||||||
|
*/
|
||||||
|
void setBandReject( StkFloat fc, StkFloat Q );
|
||||||
|
|
||||||
|
//! Set the filter coefficients for an all-pass centered at \e fc (in Hz) with Q-factor \e Q.
|
||||||
|
/*!
|
||||||
|
This method determines the filter coefficients corresponding to
|
||||||
|
an all-pass filter whose phase response crosses -pi radians at \e fc.
|
||||||
|
High values for \e Q will result in a more instantaenous shift in phase
|
||||||
|
response at \e fc. Lower values will result in a more gradual shift in
|
||||||
|
phase response around \e fc. Both \e fc and \e Q must be positive.
|
||||||
|
*/
|
||||||
|
void setAllPass( StkFloat fc, StkFloat Q );
|
||||||
|
|
||||||
//! Sets the filter zeroes for equal resonance gain.
|
//! Sets the filter zeroes for equal resonance gain.
|
||||||
/*!
|
/*!
|
||||||
When using the filter as a resonator, zeroes places at z = 1, z
|
When using the filter as a resonator, zeroes places at z = 1, z
|
||||||
= -1 will result in a constant gain at resonance of 1 / (1 - R),
|
= -1 will result in a constant gain at resonance of 1 / (1 - R),
|
||||||
where R is the pole radius setting.
|
where R is the pole radius setting.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void setEqualGainZeroes( void );
|
void setEqualGainZeroes( void );
|
||||||
|
|
||||||
@@ -114,6 +179,14 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
|
virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
|
||||||
|
|
||||||
|
// Helper function to update the three intermediate values for the predefined filter types
|
||||||
|
// along with the feedback filter coefficients. Performs the debug check for fc and Q-factor arguments.
|
||||||
|
void setCommonFilterValues( StkFloat fc, StkFloat Q );
|
||||||
|
|
||||||
|
StkFloat K_;
|
||||||
|
StkFloat kSqr_;
|
||||||
|
StkFloat denom_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline StkFloat BiQuad :: tick( StkFloat input )
|
inline StkFloat BiQuad :: tick( StkFloat input )
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ BiQuad :: BiQuad() : Filter()
|
|||||||
inputs_.resize( 3, 1, 0.0 );
|
inputs_.resize( 3, 1, 0.0 );
|
||||||
outputs_.resize( 3, 1, 0.0 );
|
outputs_.resize( 3, 1, 0.0 );
|
||||||
|
|
||||||
|
K_ = 0.0;
|
||||||
|
kSqr_ = 0.0;
|
||||||
|
denom_ = 1.0;
|
||||||
|
|
||||||
Stk::addSampleRateAlert( this );
|
Stk::addSampleRateAlert( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +77,11 @@ void BiQuad :: setResonance( StkFloat frequency, StkFloat radius, bool normalize
|
|||||||
b_[1] = 0.0;
|
b_[1] = 0.0;
|
||||||
b_[2] = -b_[0];
|
b_[2] = -b_[0];
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
b_[0] = 1.0;
|
||||||
|
b_[1] = 0.0;
|
||||||
|
b_[2] = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiQuad :: setNotch( StkFloat frequency, StkFloat radius )
|
void BiQuad :: setNotch( StkFloat frequency, StkFloat radius )
|
||||||
@@ -89,8 +98,57 @@ void BiQuad :: setNotch( StkFloat frequency, StkFloat radius )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This method does not attempt to normalize the filter gain.
|
// This method does not attempt to normalize the filter gain.
|
||||||
b_[2] = radius * radius;
|
b_[0] = 1.0;
|
||||||
b_[1] = (StkFloat) -2.0 * radius * cos( TWO_PI * (double) frequency / Stk::sampleRate() );
|
b_[1] = (StkFloat) -2.0 * radius * cos( TWO_PI * (double) frequency / Stk::sampleRate() );
|
||||||
|
b_[2] = radius * radius;
|
||||||
|
|
||||||
|
a_[1] = 0.0;
|
||||||
|
a_[2] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setLowPass( StkFloat fc, StkFloat Q )
|
||||||
|
{
|
||||||
|
setCommonFilterValues(fc, Q);
|
||||||
|
|
||||||
|
b_[0] = kSqr_ * Q * denom_;
|
||||||
|
b_[1] = 2 * b_[0];
|
||||||
|
b_[2] = b_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setHighPass( StkFloat fc, StkFloat Q )
|
||||||
|
{
|
||||||
|
setCommonFilterValues(fc, Q);
|
||||||
|
|
||||||
|
b_[0] = Q * denom_;
|
||||||
|
b_[1] = -2 * b_[0];
|
||||||
|
b_[2] = b_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setBandPass( StkFloat fc, StkFloat Q )
|
||||||
|
{
|
||||||
|
setCommonFilterValues(fc, Q);
|
||||||
|
|
||||||
|
b_[0] = K_ * denom_;
|
||||||
|
b_[1] = 0.0;
|
||||||
|
b_[2] = -b_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setBandReject( StkFloat fc, StkFloat Q )
|
||||||
|
{
|
||||||
|
setCommonFilterValues(fc, Q);
|
||||||
|
|
||||||
|
b_[0] = Q * (kSqr_ + 1) * denom_;
|
||||||
|
b_[1] = 2 * Q * (kSqr_ - 1) * denom_;
|
||||||
|
b_[2] = b_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setAllPass( StkFloat fc, StkFloat Q )
|
||||||
|
{
|
||||||
|
setCommonFilterValues(fc, Q);
|
||||||
|
|
||||||
|
b_[0] = a_[2];
|
||||||
|
b_[1] = a_[1];
|
||||||
|
b_[2] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiQuad :: setEqualGainZeroes( void )
|
void BiQuad :: setEqualGainZeroes( void )
|
||||||
@@ -100,4 +158,25 @@ void BiQuad :: setEqualGainZeroes( void )
|
|||||||
b_[2] = -1.0;
|
b_[2] = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BiQuad :: setCommonFilterValues( StkFloat fc, StkFloat Q)
|
||||||
|
{
|
||||||
|
#if defined(_STK_DEBUG_)
|
||||||
|
if ( fc < 0.0 ) {
|
||||||
|
oStream_ << "BiQuad::updateKValues: fc argument (" << fc << ") is negative!";
|
||||||
|
handleError( StkError::WARNING ); return;
|
||||||
|
}
|
||||||
|
if ( Q < 0.0 ) {
|
||||||
|
oStream_ << "BiQuad::updateKValues: Q argument (" << Q << ") is negative!";
|
||||||
|
handleError( StkError::WARNING ); return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
K_ = tan(PI * fc / Stk::sampleRate());
|
||||||
|
kSqr_ = K_ * K_;
|
||||||
|
denom_ = 1 / (kSqr_ * Q + K_ + Q);
|
||||||
|
|
||||||
|
a_[1] = 2 * Q * (kSqr_ - 1) * denom_;
|
||||||
|
a_[2] = (kSqr_ * Q - K_ + Q) * denom_;
|
||||||
|
}
|
||||||
|
|
||||||
} // stk namespace
|
} // stk namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user