diff options
-rw-r--r-- | Alc/filters/biquad.cpp | 44 | ||||
-rw-r--r-- | Alc/filters/biquad.h | 43 |
2 files changed, 51 insertions, 36 deletions
diff --git a/Alc/filters/biquad.cpp b/Alc/filters/biquad.cpp index 16a1b3fb..b010ebed 100644 --- a/Alc/filters/biquad.cpp +++ b/Alc/filters/biquad.cpp @@ -10,19 +10,20 @@ #include "biquad.h" -void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rcpQ) +template<typename Real> +void BiquadFilterR<Real>::setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ) { // Limit gain to -100dB assert(gain > 0.00001f); - const float w0{F_TAU * f0norm}; - const float sin_w0{std::sin(w0)}; - const float cos_w0{std::cos(w0)}; - const float alpha{sin_w0/2.0f * rcpQ}; + const Real w0{F_TAU * f0norm}; + const Real sin_w0{std::sin(w0)}; + const Real cos_w0{std::cos(w0)}; + const Real alpha{sin_w0/2.0f * rcpQ}; - float sqrtgain_alpha_2; - float a[3]{ 1.0f, 0.0f, 0.0f }; - float b[3]{ 1.0f, 0.0f, 0.0f }; + Real sqrtgain_alpha_2; + Real a[3]{ 1.0f, 0.0f, 0.0f }; + Real b[3]{ 1.0f, 0.0f, 0.0f }; /* Calculate filter coefficients depending on filter type */ switch(type) @@ -73,7 +74,7 @@ void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rc break; case BiquadType::BandPass: b[0] = alpha; - b[1] = 0; + b[1] = 0.0f; b[2] = -alpha; a[0] = 1.0f + alpha; a[1] = -2.0f * cos_w0; @@ -88,18 +89,18 @@ void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rc b2 = b[2] / a[0]; } - -void BiquadFilter::process(float *dst, const float *src, int numsamples) +template<typename Real> +void BiquadFilterR<Real>::process(Real *dst, const Real *src, int numsamples) { ASSUME(numsamples > 0); - const float b0{this->b0}; - const float b1{this->b1}; - const float b2{this->b2}; - const float a1{this->a1}; - const float a2{this->a2}; - float z1{this->z1}; - float z2{this->z2}; + const Real b0{this->b0}; + const Real b1{this->b1}; + const Real b2{this->b2}; + const Real a1{this->a1}; + const Real a2{this->a2}; + Real z1{this->z1}; + Real z2{this->z2}; /* Processing loop is Transposed Direct Form II. This requires less storage * compared to Direct Form I (only two delay components, instead of a four- @@ -109,9 +110,9 @@ void BiquadFilter::process(float *dst, const float *src, int numsamples) * * See: http://www.earlevel.com/main/2003/02/28/biquads/ */ - auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](float input) noexcept -> float + auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real { - float output = input*b0 + z1; + Real output = input*b0 + z1; z1 = input*b1 - output*a1 + z2; z2 = input*b2 - output*a2; return output; @@ -121,3 +122,6 @@ void BiquadFilter::process(float *dst, const float *src, int numsamples) this->z1 = z1; this->z2 = z2; } + +template class BiquadFilterR<float>; +template class BiquadFilterR<double>; diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h index eccaed35..a7d830a2 100644 --- a/Alc/filters/biquad.h +++ b/Alc/filters/biquad.h @@ -34,13 +34,14 @@ enum class BiquadType { BandPass, }; -class BiquadFilter { +template<typename Real> +class BiquadFilterR { /* Last two delayed components for direct form II. */ - float z1{0.0f}, z2{0.0f}; + Real z1{0.0f}, z2{0.0f}; /* Transfer function coefficients "b" (numerator) */ - float b0{1.0f}, b1{0.0f}, b2{0.0f}; + Real b0{1.0f}, b1{0.0f}, b2{0.0f}; /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ - float a1{0.0f}, a2{0.0f}; + Real a1{0.0f}, a2{0.0f}; public: void clear() noexcept { z1 = z2 = 0.0f; } @@ -59,9 +60,9 @@ public: * transition band. Can be generated from calc_rcpQ_from_slope * or calc_rcpQ_from_bandwidth as needed. */ - void setParams(BiquadType type, float gain, float f0norm, float rcpQ); + void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ); - void copyParamsFrom(const BiquadFilter &other) + void copyParamsFrom(const BiquadFilterR &other) { b0 = other.b0; b1 = other.b1; @@ -71,7 +72,7 @@ public: } - void process(float *dst, const float *src, int numsamples); + void process(Real *dst, const Real *src, int numsamples); void passthru(int numsamples) noexcept { @@ -88,19 +89,21 @@ public: } /* Rather hacky. It's just here to support "manual" processing. */ - std::pair<float,float> getComponents() const noexcept + std::pair<Real,Real> getComponents() const noexcept { return {z1, z2}; } - void setComponents(float z1_, float z2_) noexcept + void setComponents(Real z1_, Real z2_) noexcept { z1 = z1_; z2 = z2_; } - float processOne(const float in, float &z1_, float &z2_) const noexcept + Real processOne(const Real in, Real &z1_, Real &z2_) const noexcept { - float out{in*b0 + z1_}; + Real out{in*b0 + z1_}; z1_ = in*b1 - out*a1 + z2_; z2_ = in*b2 - out*a2; return out; } }; +using BiquadFilter = BiquadFilterR<float>; + /** * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the * reference gain and shelf slope parameter. @@ -108,19 +111,27 @@ public: * \param slope 0 < slope <= 1 */ inline float calc_rcpQ_from_slope(float gain, float slope) -{ - return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); -} +{ return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } + +inline double calc_rcpQ_from_slope(double gain, double slope) +{ return std::sqrt((gain + 1.0/gain)*(1.0/slope - 1.0) + 2.0); } + /** * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized * reference frequency and bandwidth. * \param f0norm 0 < f0norm < 0.5. * \param bandwidth 0 < bandwidth */ -inline ALfloat calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) +inline float calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) { - float w0 = F_TAU * f0norm; + const float w0{F_TAU * f0norm}; return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); } +inline double calc_rcpQ_from_bandwidth(double f0norm, double bandwidth) +{ + const double w0{F_TAU * f0norm}; + return 2.0*std::sinh(std::log(2.0)/2.0*bandwidth*w0/std::sin(w0)); +} + #endif /* FILTERS_BIQUAD_H */ |