implemented changes proposed in #121

This commit is contained in:
Navin K
2022-05-15 01:40:16 -04:00
parent 92d81d67c2
commit 79334d2c8d
2 changed files with 71 additions and 42 deletions

View File

@@ -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,52 +79,72 @@ public:
*/ */
void setNotch( StkFloat frequency, StkFloat radius ); void setNotch( StkFloat frequency, StkFloat radius );
//! Set the filter coefficients for a low-pass at \e frequency (in Hz) with factor \e Q. //! 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 This method determines the filter coefficients corresponding to a
a low-pass filter with cutoff placed at \e frequency and low-pass filter with cutoff placed at \e fc, where sloping behaviour
Q-factor set by \e Q. Both \e frequency and \e Q must be positive. 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 frequency, StkFloat Q ); void setLowPass( StkFloat fc, StkFloat Q=RECIP_SQRT_2 );
//! Set the filter coefficients for a high-pass at \e frequency (in Hz) with factor \e Q. //! 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 This method determines the filter coefficients corresponding to a high-pass
a high-pass filter with cutoff placed at \e frequency and filter with cutoff placed at \e fc, where sloping behaviour and resonance
Q-factor set by \e Q. Both \e frequency and \e Q must be positive. 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 frequency, StkFloat Q ); void setHighPass( StkFloat fc, StkFloat Q=RECIP_SQRT_2 );
//! Set the filter coefficients for a band-pass at \e frequency (in Hz) with factor \e Q. //! 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 This method determines the filter coefficients corresponding to a band-pass
a band-pass filter with center placed at \e frequency and filter with pass-band centered at \e fc, where band width and slope a
Q-factor set by \e Q. Both \e frequency and \e Q must be positive. 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 frequency, StkFloat Q ); void setBandPass( StkFloat fc, StkFloat Q );
//! Set the filter coefficients for a band-reject at \e frequency (in Hz) with factor \e 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 This method determines the filter coefficients corresponding to a
a band-reject filter with center placed at \e frequency and band-reject filter with stop-band centered at \e fc, where band width
Q-factor set by \e Q. Both \e frequency and \e Q must be positive. 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 frequency, StkFloat Q ); void setBandReject( StkFloat fc, StkFloat Q );
//! Set the filter coefficients for an all-pass at \e frequency (in Hz) with factor \e 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 This method determines the filter coefficients corresponding to
an all-pass filter with center placed at \e frequency and an all-pass filter whose phase response crosses -pi radians at \e fc.
Q-factor set by \e Q. Both \e frequency and \e Q must be positive. 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 frequency, StkFloat Q ); 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 );
@@ -156,8 +181,8 @@ public:
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 // Helper function to update the three intermediate values for the predefined filter types
// along with the feedback filter coefficients. Performs the debug check for frequency and Q-factor arguments. // along with the feedback filter coefficients. Performs the debug check for fc and Q-factor arguments.
void setCommonFilterValues( StkFloat frequency, StkFloat Q ); void setCommonFilterValues( StkFloat fc, StkFloat Q );
StkFloat K_; StkFloat K_;
StkFloat kSqr_; StkFloat kSqr_;

View File

@@ -98,49 +98,53 @@ 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 frequency, StkFloat Q ) void BiQuad :: setLowPass( StkFloat fc, StkFloat Q )
{ {
setCommonFilterValues(frequency, Q); setCommonFilterValues(fc, Q);
b_[0] = kSqr_ * Q * denom_; b_[0] = kSqr_ * Q * denom_;
b_[1] = 2 * b_[0]; b_[1] = 2 * b_[0];
b_[2] = b_[0]; b_[2] = b_[0];
} }
void BiQuad :: setHighPass( StkFloat frequency, StkFloat Q ) void BiQuad :: setHighPass( StkFloat fc, StkFloat Q )
{ {
setCommonFilterValues(frequency, Q); setCommonFilterValues(fc, Q);
b_[0] = Q * denom_; b_[0] = Q * denom_;
b_[1] = -2 * b_[0]; b_[1] = -2 * b_[0];
b_[2] = b_[0]; b_[2] = b_[0];
} }
void BiQuad :: setBandPass( StkFloat frequency, StkFloat Q ) void BiQuad :: setBandPass( StkFloat fc, StkFloat Q )
{ {
setCommonFilterValues(frequency, Q); setCommonFilterValues(fc, Q);
b_[0] = K_ * denom_; b_[0] = K_ * denom_;
b_[1] = 0.0; b_[1] = 0.0;
b_[2] = -b_[0]; b_[2] = -b_[0];
} }
void BiQuad :: setBandReject( StkFloat frequency, StkFloat Q ) void BiQuad :: setBandReject( StkFloat fc, StkFloat Q )
{ {
setCommonFilterValues(frequency, Q); setCommonFilterValues(fc, Q);
b_[0] = Q * (kSqr_ + 1) * denom_; b_[0] = Q * (kSqr_ + 1) * denom_;
b_[1] = 2 * Q * (kSqr_ - 1) * denom_; b_[1] = 2 * Q * (kSqr_ - 1) * denom_;
b_[2] = b_[0]; b_[2] = b_[0];
} }
void BiQuad :: setAllPass( StkFloat frequency, StkFloat Q ) void BiQuad :: setAllPass( StkFloat fc, StkFloat Q )
{ {
setCommonFilterValues(frequency, Q); setCommonFilterValues(fc, Q);
b_[0] = a_[2]; b_[0] = a_[2];
b_[1] = a_[1]; b_[1] = a_[1];
@@ -154,11 +158,11 @@ void BiQuad :: setEqualGainZeroes( void )
b_[2] = -1.0; b_[2] = -1.0;
} }
void BiQuad :: setCommonFilterValues( StkFloat frequency, StkFloat Q) void BiQuad :: setCommonFilterValues( StkFloat fc, StkFloat Q)
{ {
#if defined(_STK_DEBUG_) #if defined(_STK_DEBUG_)
if ( frequency < 0.0 ) { if ( fc < 0.0 ) {
oStream_ << "BiQuad::updateKValues: frequency argument (" << frequency << ") is negative!"; oStream_ << "BiQuad::updateKValues: fc argument (" << fc << ") is negative!";
handleError( StkError::WARNING ); return; handleError( StkError::WARNING ); return;
} }
if ( Q < 0.0 ) { if ( Q < 0.0 ) {
@@ -167,7 +171,7 @@ void BiQuad :: setCommonFilterValues( StkFloat frequency, StkFloat Q)
} }
#endif #endif
K_ = tan(PI * frequency / Stk::sampleRate()); K_ = tan(PI * fc / Stk::sampleRate());
kSqr_ = K_ * K_; kSqr_ = K_ * K_;
denom_ = 1 / (kSqr_ * Q + K_ + Q); denom_ = 1 / (kSqr_ * Q + K_ + Q);