🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.4 KiB

  1. #ifndef FILTERS_BIQUAD_H
  2. #define FILTERS_BIQUAD_H
  3. #include <cmath>
  4. #include <utility>
  5. #include "AL/al.h"
  6. #include "math_defs.h"
  7. /* Filters implementation is based on the "Cookbook formulae for audio
  8. * EQ biquad filter coefficients" by Robert Bristow-Johnson
  9. * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
  10. */
  11. /* Implementation note: For the shelf filters, the specified gain is for the
  12. * reference frequency, which is the centerpoint of the transition band. This
  13. * better matches EFX filter design. To set the gain for the shelf itself, use
  14. * the square root of the desired linear gain (or halve the dB gain).
  15. */
  16. enum class BiquadType {
  17. /** EFX-style low-pass filter, specifying a gain and reference frequency. */
  18. HighShelf,
  19. /** EFX-style high-pass filter, specifying a gain and reference frequency. */
  20. LowShelf,
  21. /** Peaking filter, specifying a gain and reference frequency. */
  22. Peaking,
  23. /** Low-pass cut-off filter, specifying a cut-off frequency. */
  24. LowPass,
  25. /** High-pass cut-off filter, specifying a cut-off frequency. */
  26. HighPass,
  27. /** Band-pass filter, specifying a center frequency. */
  28. BandPass,
  29. };
  30. template<typename Real>
  31. class BiquadFilterR {
  32. /* Last two delayed components for direct form II. */
  33. Real z1{0.0f}, z2{0.0f};
  34. /* Transfer function coefficients "b" (numerator) */
  35. Real b0{1.0f}, b1{0.0f}, b2{0.0f};
  36. /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */
  37. Real a1{0.0f}, a2{0.0f};
  38. public:
  39. void clear() noexcept { z1 = z2 = 0.0f; }
  40. /**
  41. * Sets the filter state for the specified filter type and its parameters.
  42. *
  43. * \param type The type of filter to apply.
  44. * \param gain The gain for the reference frequency response. Only used by
  45. * the Shelf and Peaking filter types.
  46. * \param f0norm The reference frequency normal (ref_freq / sample_rate).
  47. * This is the center point for the Shelf, Peaking, and
  48. * BandPass filter types, or the cutoff frequency for the
  49. * LowPass and HighPass filter types.
  50. * \param rcpQ The reciprocal of the Q coefficient for the filter's
  51. * transition band. Can be generated from calc_rcpQ_from_slope
  52. * or calc_rcpQ_from_bandwidth as needed.
  53. */
  54. void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ);
  55. void copyParamsFrom(const BiquadFilterR &other)
  56. {
  57. b0 = other.b0;
  58. b1 = other.b1;
  59. b2 = other.b2;
  60. a1 = other.a1;
  61. a2 = other.a2;
  62. }
  63. void process(Real *dst, const Real *src, int numsamples);
  64. void passthru(int numsamples) noexcept
  65. {
  66. if(LIKELY(numsamples >= 2))
  67. {
  68. z1 = 0.0f;
  69. z2 = 0.0f;
  70. }
  71. else if(numsamples == 1)
  72. {
  73. z1 = z2;
  74. z2 = 0.0f;
  75. }
  76. }
  77. /* Rather hacky. It's just here to support "manual" processing. */
  78. std::pair<Real,Real> getComponents() const noexcept
  79. { return {z1, z2}; }
  80. void setComponents(Real z1_, Real z2_) noexcept
  81. { z1 = z1_; z2 = z2_; }
  82. Real processOne(const Real in, Real &z1_, Real &z2_) const noexcept
  83. {
  84. Real out{in*b0 + z1_};
  85. z1_ = in*b1 - out*a1 + z2_;
  86. z2_ = in*b2 - out*a2;
  87. return out;
  88. }
  89. };
  90. using BiquadFilter = BiquadFilterR<float>;
  91. /**
  92. * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
  93. * reference gain and shelf slope parameter.
  94. * \param gain 0 < gain
  95. * \param slope 0 < slope <= 1
  96. */
  97. inline float calc_rcpQ_from_slope(float gain, float slope)
  98. { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); }
  99. inline double calc_rcpQ_from_slope(double gain, double slope)
  100. { return std::sqrt((gain + 1.0/gain)*(1.0/slope - 1.0) + 2.0); }
  101. /**
  102. * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized
  103. * reference frequency and bandwidth.
  104. * \param f0norm 0 < f0norm < 0.5.
  105. * \param bandwidth 0 < bandwidth
  106. */
  107. inline float calc_rcpQ_from_bandwidth(float f0norm, float bandwidth)
  108. {
  109. const float w0{al::MathDefs<float>::Tau() * f0norm};
  110. return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0));
  111. }
  112. inline double calc_rcpQ_from_bandwidth(double f0norm, double bandwidth)
  113. {
  114. const double w0{al::MathDefs<double>::Tau() * f0norm};
  115. return 2.0*std::sinh(std::log(2.0)/2.0*bandwidth*w0/std::sin(w0));
  116. }
  117. #endif /* FILTERS_BIQUAD_H */