🛠️🐜 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.

127 lines
4.2 KiB

  1. #include "config.h"
  2. #include <cmath>
  3. #include "AL/alc.h"
  4. #include "AL/al.h"
  5. #include "alMain.h"
  6. #include "biquad.h"
  7. template<typename Real>
  8. void BiquadFilterR<Real>::setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ)
  9. {
  10. // Limit gain to -100dB
  11. assert(gain > 0.00001f);
  12. const Real w0{al::MathDefs<Real>::Tau() * f0norm};
  13. const Real sin_w0{std::sin(w0)};
  14. const Real cos_w0{std::cos(w0)};
  15. const Real alpha{sin_w0/2.0f * rcpQ};
  16. Real sqrtgain_alpha_2;
  17. Real a[3]{ 1.0f, 0.0f, 0.0f };
  18. Real b[3]{ 1.0f, 0.0f, 0.0f };
  19. /* Calculate filter coefficients depending on filter type */
  20. switch(type)
  21. {
  22. case BiquadType::HighShelf:
  23. sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
  24. b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
  25. b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
  26. b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
  27. a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
  28. a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
  29. a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
  30. break;
  31. case BiquadType::LowShelf:
  32. sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
  33. b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
  34. b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
  35. b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
  36. a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
  37. a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
  38. a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
  39. break;
  40. case BiquadType::Peaking:
  41. gain = std::sqrt(gain);
  42. b[0] = 1.0f + alpha * gain;
  43. b[1] = -2.0f * cos_w0;
  44. b[2] = 1.0f - alpha * gain;
  45. a[0] = 1.0f + alpha / gain;
  46. a[1] = -2.0f * cos_w0;
  47. a[2] = 1.0f - alpha / gain;
  48. break;
  49. case BiquadType::LowPass:
  50. b[0] = (1.0f - cos_w0) / 2.0f;
  51. b[1] = 1.0f - cos_w0;
  52. b[2] = (1.0f - cos_w0) / 2.0f;
  53. a[0] = 1.0f + alpha;
  54. a[1] = -2.0f * cos_w0;
  55. a[2] = 1.0f - alpha;
  56. break;
  57. case BiquadType::HighPass:
  58. b[0] = (1.0f + cos_w0) / 2.0f;
  59. b[1] = -(1.0f + cos_w0);
  60. b[2] = (1.0f + cos_w0) / 2.0f;
  61. a[0] = 1.0f + alpha;
  62. a[1] = -2.0f * cos_w0;
  63. a[2] = 1.0f - alpha;
  64. break;
  65. case BiquadType::BandPass:
  66. b[0] = alpha;
  67. b[1] = 0.0f;
  68. b[2] = -alpha;
  69. a[0] = 1.0f + alpha;
  70. a[1] = -2.0f * cos_w0;
  71. a[2] = 1.0f - alpha;
  72. break;
  73. }
  74. a1 = a[1] / a[0];
  75. a2 = a[2] / a[0];
  76. b0 = b[0] / a[0];
  77. b1 = b[1] / a[0];
  78. b2 = b[2] / a[0];
  79. }
  80. template<typename Real>
  81. void BiquadFilterR<Real>::process(Real *dst, const Real *src, int numsamples)
  82. {
  83. ASSUME(numsamples > 0);
  84. const Real b0{this->b0};
  85. const Real b1{this->b1};
  86. const Real b2{this->b2};
  87. const Real a1{this->a1};
  88. const Real a2{this->a2};
  89. Real z1{this->z1};
  90. Real z2{this->z2};
  91. /* Processing loop is Transposed Direct Form II. This requires less storage
  92. * compared to Direct Form I (only two delay components, instead of a four-
  93. * sample history; the last two inputs and outputs), and works better for
  94. * floating-point which favors summing similarly-sized values while being
  95. * less bothered by overflow.
  96. *
  97. * See: http://www.earlevel.com/main/2003/02/28/biquads/
  98. */
  99. auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real
  100. {
  101. Real output = input*b0 + z1;
  102. z1 = input*b1 - output*a1 + z2;
  103. z2 = input*b2 - output*a2;
  104. return output;
  105. };
  106. std::transform(src, src+numsamples, dst, proc_sample);
  107. this->z1 = z1;
  108. this->z2 = z2;
  109. }
  110. template class BiquadFilterR<float>;
  111. template class BiquadFilterR<double>;