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.

208 lines
6.5KB

  1. /* Audio Library for Teensy 3.X
  2. * Copyright (c) 2019, Paul Stoffregen, paul@pjrc.com
  3. *
  4. * Development of this audio library was funded by PJRC.COM, LLC by sales of
  5. * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
  6. * open source software by purchasing Teensy or other PJRC products.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice, development funding notice, and this permission
  16. * notice shall be included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. /*
  27. by Alexander Walch
  28. */
  29. #ifndef biquad_coeffs_h_
  30. #define biquad_coeffs_h_
  31. #include "Arduino.h"
  32. #include <arm_math.h>
  33. #include <type_traits>
  34. enum class BiquadType {
  35. LOW_PASS, HIGH_PASS, BAND_PASS, NOTCH, ALL_PASS, PEAKING, LOW_SHELF, HIGH_SHELF
  36. };
  37. template <typename T>
  38. void getCoefficients(T* coeffs, BiquadType type, double dbGain, double freq, double srate, double bandwidthOrQOrS, bool isBandwidthOrS=false){
  39. const double A =(type == BiquadType::PEAKING || type == BiquadType::LOW_SHELF || type == BiquadType::HIGH_SHELF) ? pow(10., dbGain / 40.) : pow(10, dbGain / 20);
  40. const double omega = 2 * M_PI * freq / srate;
  41. const double sn = sin(omega);
  42. const double cs = cos(omega);
  43. double alpha;
  44. if (!isBandwidthOrS) // Q
  45. alpha = sn / (2 * bandwidthOrQOrS);
  46. else if (type == BiquadType::LOW_SHELF || type == BiquadType::HIGH_SHELF) // S
  47. alpha = sn / 2 * sqrt((A + 1 / A) * (1 / bandwidthOrQOrS - 1) + 2);
  48. else // BW
  49. alpha = sn * sinh(_M_LN2 / 2 * bandwidthOrQOrS * omega / sn);
  50. const double beta = 2 * sqrt(A) * alpha;
  51. double b0, b1, b2, a0Inv, a1, a2;
  52. switch (type)
  53. {
  54. case BiquadType::LOW_PASS:
  55. b0 = (1 - cs) / 2;
  56. b1 = 1 - cs;
  57. b2 = (1 - cs) / 2;
  58. a0Inv = 1/(1 + alpha);
  59. a1 = -2 * cs;
  60. a2 = 1 - alpha;
  61. break;
  62. case BiquadType::HIGH_PASS:
  63. b0 = (1 + cs) / 2;
  64. b1 = -(1 + cs);
  65. b2 = (1 + cs) / 2;
  66. a0Inv = 1/(1 + alpha);
  67. a1 = -2 * cs;
  68. a2 = 1 - alpha;
  69. break;
  70. case BiquadType::BAND_PASS:
  71. b0 = alpha;
  72. b1 = 0;
  73. b2 = -alpha;
  74. a0Inv = 1/(1 + alpha);
  75. a1 = -2 * cs;
  76. a2 = 1 - alpha;
  77. break;
  78. case BiquadType::NOTCH:
  79. b0 = 1;
  80. b1 = -2 * cs;
  81. b2 = 1;
  82. a0Inv = 1/(1 + alpha);
  83. a1 = -2 * cs;
  84. a2 = 1 - alpha;
  85. break;
  86. case BiquadType::ALL_PASS:
  87. b0 = 1 - alpha;
  88. b1 = -2 * cs;
  89. b2 = 1 + alpha;
  90. a0Inv = 1/(1 + alpha);
  91. a1 = -2 * cs;
  92. a2 = 1 - alpha;
  93. break;
  94. case BiquadType::PEAKING:
  95. b0 = 1 + (alpha * A);
  96. b1 = -2 * cs;
  97. b2 = 1 - (alpha * A);
  98. a0Inv = 1/(1 + (alpha / A));
  99. a1 = -2 * cs;
  100. a2 = 1 - (alpha / A);
  101. break;
  102. case BiquadType::LOW_SHELF:
  103. b0 = A * ((A + 1) - (A - 1) * cs + beta);
  104. b1 = 2 * A * ((A - 1) - (A + 1) * cs);
  105. b2 = A * ((A + 1) - (A - 1) * cs - beta);
  106. a0Inv = (A + 1) + (A - 1) * cs + beta;
  107. a1 = -2 * ((A - 1) + (A + 1) * cs);
  108. a2 = (A + 1) + (A - 1) * cs - beta;
  109. break;
  110. case BiquadType::HIGH_SHELF:
  111. b0 = A * ((A + 1) + (A - 1) * cs + beta);
  112. b1 = -2 * A * ((A - 1) + (A + 1) * cs);
  113. b2 = A * ((A + 1) + (A - 1) * cs - beta);
  114. a0Inv = 1/((A + 1) - (A - 1) * cs + beta);
  115. a1 = 2 * ((A - 1) - (A + 1) * cs);
  116. a2 = (A + 1) - (A - 1) * cs - beta;
  117. break;
  118. }
  119. using writable_type = typename std::remove_const<T>::type;
  120. writable_type* coeffs_ptr = const_cast<writable_type*>(coeffs);
  121. *coeffs_ptr++ = (T)(b0 * a0Inv);
  122. *coeffs_ptr++ = (T)(b1 * a0Inv);
  123. *coeffs_ptr++ = (T)(b2 * a0Inv);
  124. *coeffs_ptr++ = (T)(-a1 * a0Inv);
  125. *coeffs_ptr = (T)(-a2 * a0Inv);
  126. }
  127. template <typename T, typename BIQUAD, typename BTYPE>
  128. void biquad_cascade_df2T(const BIQUAD* S, T* pSrc, T* pDst, uint32_t blockSize) {
  129. BTYPE* b0 =S->pCoeffs;
  130. BTYPE* b1=S->pCoeffs+1;
  131. BTYPE* b2=S->pCoeffs+2;
  132. BTYPE* a1Neg=S->pCoeffs+3;
  133. BTYPE* a2Neg=S->pCoeffs+4;
  134. BTYPE* state=S->pState;
  135. if(S->numStages==1){
  136. BTYPE yn;
  137. for (uint32_t j=0; j<blockSize; j++ ){
  138. yn = *b0 * *pSrc + *state;
  139. *state = *b1 * *pSrc + *a1Neg * yn + *(state+1);
  140. *(state+1) = *b2 * *pSrc++ + *a2Neg * yn;
  141. *pDst++=(T)yn;
  142. }
  143. }
  144. else {
  145. BTYPE pDstD[blockSize];
  146. BTYPE* pDstDP=pDstD;
  147. for (uint32_t j=0; j<blockSize; j++ ){
  148. *pDstDP = *b0 * *pSrc + *state;
  149. *state = *b1 * *pSrc + *a1Neg * *pDstDP + *(state+1);
  150. *(state+1) = *b2 * *pSrc++ + *a2Neg * *pDstDP++;
  151. }
  152. b0+=5;
  153. b1+=5;
  154. b2+=5;
  155. a1Neg+=5;
  156. a2Neg+=5;
  157. state+=2;
  158. for (uint8_t i =0; i< S->numStages - 2;i++){
  159. pDstDP=pDstD;
  160. BTYPE xn;
  161. for (uint32_t j=0; j<blockSize; j++ ){
  162. xn=*pDstDP;
  163. *pDstDP = *b0 * xn + *state;
  164. *state = *b1 * xn + *a1Neg * *pDstDP + *(state+1);
  165. *(state+1) = *b2 * xn + *a2Neg * *pDstDP++;
  166. }
  167. b0+=5;
  168. b1+=5;
  169. b2+=5;
  170. a1Neg+=5;
  171. a2Neg+=5;
  172. state+=2;
  173. }
  174. BTYPE yn;
  175. pDstDP=pDstD;
  176. for (uint32_t j=0; j<blockSize; j++ ){
  177. yn = *b0 * *pDstDP + *state;
  178. *state = *b1 * *pDstDP + *a1Neg * yn + *(state+1);
  179. *(state+1) = *b2 * *pDstDP++ + *a2Neg * yn;
  180. *pDst++=(T)yn;
  181. }
  182. }
  183. }
  184. template <typename B>
  185. void preload(const B* S, double val=0.){
  186. // double* b1=B->pCoeffs+1;
  187. // double* b2=B->pCoeffs+2;
  188. // double* a1Neg=B->pCoeffs+3;
  189. // double* a2Neg=B->pCoeffs+4;
  190. *(S->pState+1) = (*(S->pCoeffs+2) + *(S->pCoeffs+4)) * val;
  191. *(S->pState) = (*(S->pCoeffs+1) + *(S->pCoeffs+3)) * val + *(S->pState+1);
  192. }
  193. #endif