Biquad.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. #include "Biquad.h"
  2. using namespace bell;
  3. Biquad::Biquad()
  4. {
  5. this->filterType = "biquad";
  6. }
  7. void Biquad::sampleRateChanged(uint32_t sampleRate)
  8. {
  9. this->sampleRate = sampleRate;
  10. //this->configure(this->type, this->currentConfig);
  11. }
  12. void Biquad::configure(Type type, std::map<std::string, float> &newConf)
  13. {
  14. this->type = type;
  15. this->currentConfig = newConf;
  16. switch (type)
  17. {
  18. case Type::Free:
  19. coeffs[0] = newConf["a1"];
  20. coeffs[1] = newConf["a2"];
  21. coeffs[2] = newConf["b0"];
  22. coeffs[3] = newConf["b1"];
  23. coeffs[4] = newConf["b2"];
  24. break;
  25. case Type::Highpass:
  26. highPassCoEffs(newConf["freq"], newConf["q"]);
  27. break;
  28. case Type::HighpassFO:
  29. highPassFOCoEffs(newConf["freq"]);
  30. break;
  31. case Type::Lowpass:
  32. lowPassCoEffs(newConf["freq"], newConf["q"]);
  33. break;
  34. case Type::LowpassFO:
  35. lowPassFOCoEffs(newConf["freq"]);
  36. break;
  37. case Type::Highshelf:
  38. // check if config has slope key
  39. if (newConf.find("slope") != newConf.end())
  40. {
  41. highShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]);
  42. }
  43. else
  44. {
  45. highShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
  46. }
  47. break;
  48. case Type::HighshelfFO:
  49. highShelfFOCoEffs(newConf["freq"], newConf["gain"]);
  50. break;
  51. case Type::Lowshelf:
  52. // check if config has slope key
  53. if (newConf.find("slope") != newConf.end())
  54. {
  55. lowShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]);
  56. }
  57. else
  58. {
  59. lowShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
  60. }
  61. break;
  62. case Type::LowshelfFO:
  63. lowShelfFOCoEffs(newConf["freq"], newConf["gain"]);
  64. break;
  65. case Type::Peaking:
  66. // check if config has bandwidth key
  67. if (newConf.find("bandwidth") != newConf.end())
  68. {
  69. peakCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]);
  70. }
  71. else
  72. {
  73. peakCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
  74. }
  75. break;
  76. case Type::Notch:
  77. if (newConf.find("bandwidth") != newConf.end())
  78. {
  79. notchCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]);
  80. }
  81. else
  82. {
  83. notchCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
  84. }
  85. break;
  86. case Type::Bandpass:
  87. if (newConf.find("bandwidth") != newConf.end())
  88. {
  89. bandPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
  90. }
  91. else
  92. {
  93. bandPassCoEffs(newConf["freq"], newConf["q"]);
  94. }
  95. break;
  96. case Type::Allpass:
  97. if (newConf.find("bandwidth") != newConf.end())
  98. {
  99. allPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
  100. }
  101. else
  102. {
  103. allPassCoEffs(newConf["freq"], newConf["q"]);
  104. }
  105. break;
  106. case Type::AllpassFO:
  107. allPassFOCoEffs(newConf["freq"]);
  108. break;
  109. }
  110. }
  111. // coefficients for a high pass biquad filter
  112. void Biquad::highPassCoEffs(float f, float q)
  113. {
  114. float w0 = 2 * M_PI * f / this->sampleRate;
  115. float c = cosf(w0);
  116. float s = sinf(w0);
  117. float alpha = s / (2 * q);
  118. float b0 = (1 + c) / 2;
  119. float b1 = -(1 + c);
  120. float b2 = b0;
  121. float a0 = 1 + alpha;
  122. float a1 = -2 * c;
  123. float a2 = 1 - alpha;
  124. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  125. }
  126. // coefficients for a high pass first order biquad filter
  127. void Biquad::highPassFOCoEffs(float f)
  128. {
  129. float w0 = 2 * M_PI * f / this->sampleRate;
  130. float k = tanf(w0 / 2.0);
  131. float alpha = 1.0 + k;
  132. float b0 = 1.0 / alpha;
  133. float b1 = -1.0 / alpha;
  134. float b2 = 0.0;
  135. float a0 = 1.0;
  136. float a1 = -(1.0 - k) / alpha;
  137. float a2 = 0.0;
  138. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  139. }
  140. // coefficients for a low pass biquad filter
  141. void Biquad::lowPassCoEffs(float f, float q)
  142. {
  143. float w0 = 2 * M_PI * f / this->sampleRate;
  144. float c = cosf(w0);
  145. float s = sinf(w0);
  146. float alpha = s / (2 * q);
  147. float b0 = (1 - c) / 2;
  148. float b1 = 1 - c;
  149. float b2 = b0;
  150. float a0 = 1 + alpha;
  151. float a1 = -2 * c;
  152. float a2 = 1 - alpha;
  153. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  154. }
  155. // coefficients for a low pass first order biquad filter
  156. void Biquad::lowPassFOCoEffs(float f)
  157. {
  158. float w0 = 2 * M_PI * f / this->sampleRate;
  159. float k = tanf(w0 / 2.0);
  160. float alpha = 1.0 + k;
  161. float b0 = k / alpha;
  162. float b1 = k / alpha;
  163. float b2 = 0.0;
  164. float a0 = 1.0;
  165. float a1 = -(1.0 - k) / alpha;
  166. float a2 = 0.0;
  167. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  168. }
  169. // coefficients for a peak biquad filter
  170. void Biquad::peakCoEffs(float f, float gain, float q)
  171. {
  172. float w0 = 2 * M_PI * f / this->sampleRate;
  173. float c = cosf(w0);
  174. float s = sinf(w0);
  175. float alpha = s / (2 * q);
  176. float ampl = std::pow(10.0f, gain / 40.0f);
  177. float b0 = 1.0 + (alpha * ampl);
  178. float b1 = -2.0 * c;
  179. float b2 = 1.0 - (alpha * ampl);
  180. float a0 = 1 + (alpha / ampl);
  181. float a1 = -2 * c;
  182. float a2 = 1 - (alpha / ampl);
  183. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  184. }
  185. void Biquad::peakCoEffsBandwidth(float f, float gain, float bandwidth)
  186. {
  187. float w0 = 2 * M_PI * f / this->sampleRate;
  188. float c = cosf(w0);
  189. float s = sinf(w0);
  190. float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
  191. float ampl = std::pow(10.0f, gain / 40.0f);
  192. float b0 = 1.0 + (alpha * ampl);
  193. float b1 = -2.0 * c;
  194. float b2 = 1.0 - (alpha * ampl);
  195. float a0 = 1 + (alpha / ampl);
  196. float a1 = -2 * c;
  197. float a2 = 1 - (alpha / ampl);
  198. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  199. }
  200. void Biquad::highShelfCoEffs(float f, float gain, float q)
  201. {
  202. float A = std::pow(10.0f, gain / 40.0f);
  203. float w0 = 2 * M_PI * f / this->sampleRate;
  204. float c = cosf(w0);
  205. float s = sinf(w0);
  206. float alpha = s / (2 * q);
  207. float beta = s * sqrtf(A) / q;
  208. float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
  209. float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
  210. float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
  211. float a0 = (A + 1.0) - (A - 1.0) * c + beta;
  212. float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
  213. float a2 = (A + 1.0) - (A - 1.0) * c - beta;
  214. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  215. }
  216. void Biquad::highShelfCoEffsSlope(float f, float gain, float slope)
  217. {
  218. float A = std::pow(10.0f, gain / 40.0f);
  219. float w0 = 2 * M_PI * f / this->sampleRate;
  220. float c = cosf(w0);
  221. float s = sinf(w0);
  222. float alpha =
  223. s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
  224. float beta = 2.0 * sqrtf(A) * alpha;
  225. float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
  226. float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
  227. float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
  228. float a0 = (A + 1.0) - (A - 1.0) * c + beta;
  229. float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
  230. float a2 = (A + 1.0) - (A - 1.0) * c - beta;
  231. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  232. }
  233. void Biquad::highShelfFOCoEffs(float f, float gain)
  234. {
  235. float A = std::pow(10.0f, gain / 40.0f);
  236. float w0 = 2 * M_PI * f / this->sampleRate;
  237. float tn = tanf(w0 / 2.0);
  238. float b0 = A * tn + std::pow(A, 2);
  239. float b1 = A * tn - std::pow(A, 2);
  240. float b2 = 0.0;
  241. float a0 = A * tn + 1.0;
  242. float a1 = A * tn - 1.0;
  243. float a2 = 0.0;
  244. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  245. }
  246. void Biquad::lowShelfCoEffs(float f, float gain, float q) {
  247. float A = std::pow(10.0f, gain / 40.0f);
  248. float w0 = 2 * M_PI * f / this->sampleRate;
  249. float c = cosf(w0);
  250. float s = sinf(w0);
  251. float beta = s * sqrtf(A) / q;
  252. float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
  253. float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
  254. float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
  255. float a0 = (A + 1.0) + (A - 1.0) * c + beta;
  256. float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
  257. float a2 = (A + 1.0) + (A - 1.0) * c - beta;
  258. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  259. }
  260. void Biquad::lowShelfCoEffsSlope(float f, float gain, float slope) {
  261. float A = std::pow(10.0f, gain / 40.0f);
  262. float w0 = 2 * M_PI * f / this->sampleRate;
  263. float c = cosf(w0);
  264. float s = sinf(w0);
  265. float alpha =
  266. s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
  267. float beta = 2.0 * sqrtf(A) * alpha;
  268. float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
  269. float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
  270. float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
  271. float a0 = (A + 1.0) + (A - 1.0) * c + beta;
  272. float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
  273. float a2 = (A + 1.0) + (A - 1.0) * c - beta;
  274. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  275. }
  276. void Biquad::lowShelfFOCoEffs(float f, float gain) {
  277. float A = std::pow(10.0f, gain / 40.0f);
  278. float w0 = 2 * M_PI * f / this->sampleRate;
  279. float tn = tanf(w0 / 2.0);
  280. float b0 = std::pow(A, 2) * tn + A;
  281. float b1 = std::pow(A, 2) * tn - A;
  282. float b2 = 0.0;
  283. float a0 = tn + A;
  284. float a1 = tn - A;
  285. float a2 = 0.0;
  286. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  287. }
  288. void Biquad::notchCoEffs(float f, float gain, float q) {
  289. float A = std::pow(10.0f, gain / 40.0f);
  290. float w0 = 2 * M_PI * f / this->sampleRate;
  291. float c = cosf(w0);
  292. float s = sinf(w0);
  293. float alpha = s / (2.0 * q);
  294. float b0 = 1.0;
  295. float b1 = -2.0 * c;
  296. float b2 = 1.0;
  297. float a0 = 1.0 + alpha;
  298. float a1 = -2.0 * c;
  299. float a2 = 1.0 - alpha;
  300. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  301. }
  302. void Biquad::notchCoEffsBandwidth(float f, float gain, float bandwidth) {
  303. float A = std::pow(10.0f, gain / 40.0f);
  304. float w0 = 2 * M_PI * f / this->sampleRate;
  305. float c = cosf(w0);
  306. float s = sinf(w0);
  307. float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
  308. float b0 = 1.0;
  309. float b1 = -2.0 * c;
  310. float b2 = 1.0;
  311. float a0 = 1.0 + alpha;
  312. float a1 = -2.0 * c;
  313. float a2 = 1.0 - alpha;
  314. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  315. }
  316. void Biquad::bandPassCoEffs(float f, float q) {
  317. float w0 = 2 * M_PI * f / this->sampleRate;
  318. float c = cosf(w0);
  319. float s = sinf(w0);
  320. float alpha = s / (2.0 * q);
  321. float b0 = alpha;
  322. float b1 = 0.0;
  323. float b2 = -alpha;
  324. float a0 = 1.0 + alpha;
  325. float a1 = -2.0 * c;
  326. float a2 = 1.0 - alpha;
  327. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  328. }
  329. void Biquad::bandPassCoEffsBandwidth(float f, float bandwidth) {
  330. float w0 = 2 * M_PI * f / this->sampleRate;
  331. float c = cosf(w0);
  332. float s = sinf(w0);
  333. float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
  334. float b0 = alpha;
  335. float b1 = 0.0;
  336. float b2 = -alpha;
  337. float a0 = 1.0 + alpha;
  338. float a1 = -2.0 * c;
  339. float a2 = 1.0 - alpha;
  340. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  341. }
  342. void Biquad::allPassCoEffs(float f, float q) {
  343. float w0 = 2 * M_PI * f / this->sampleRate;
  344. float c = cosf(w0);
  345. float s = sinf(w0);
  346. float alpha = s / (2.0 * q);
  347. float b0 = 1.0 - alpha;
  348. float b1 = -2.0 * c;
  349. float b2 = 1.0 + alpha;
  350. float a0 = 1.0 + alpha;
  351. float a1 = -2.0 * c;
  352. float a2 = 1.0 - alpha;
  353. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  354. }
  355. void Biquad::allPassCoEffsBandwidth(float f, float bandwidth) {
  356. float w0 = 2 * M_PI * f / this->sampleRate;
  357. float c = cosf(w0);
  358. float s = sinf(w0);
  359. float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
  360. float b0 = 1.0 - alpha;
  361. float b1 = -2.0 * c;
  362. float b2 = 1.0 + alpha;
  363. float a0 = 1.0 + alpha;
  364. float a1 = -2.0 * c;
  365. float a2 = 1.0 - alpha;
  366. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  367. }
  368. void Biquad::allPassFOCoEffs(float f) {
  369. float w0 = 2 * M_PI * f / this->sampleRate;
  370. float tn = tanf(w0 / 2.0);
  371. float alpha = (tn + 1.0) / (tn - 1.0);
  372. float b0 = 1.0;
  373. float b1 = alpha;
  374. float b2 = 0.0;
  375. float a0 = alpha;
  376. float a1 = 1.0;
  377. float a2 = 0.0;
  378. this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
  379. }
  380. void Biquad::normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, float b2)
  381. {
  382. coeffs[0] = b0 / a0;
  383. coeffs[1] = b1 / a0;
  384. coeffs[2] = b2 / a0;
  385. coeffs[3] = a1 / a0;
  386. coeffs[4] = a2 / a0;
  387. }
  388. std::unique_ptr<StreamInfo> Biquad::process(std::unique_ptr<StreamInfo> stream)
  389. {
  390. std::scoped_lock lock(accessMutex);
  391. auto input = stream->data[this->channel];
  392. auto numSamples = stream->numSamples;
  393. #ifdef ESP_PLATFORM
  394. dsps_biquad_f32_ae32(input, input, numSamples, coeffs, w);
  395. #else
  396. // Apply the set coefficients
  397. for (int i = 0; i < numSamples; i++)
  398. {
  399. float d0 = input[i] - coeffs[3] * w[0] - coeffs[4] * w[1];
  400. input[i] = coeffs[0] * d0 + coeffs[1] * w[0] + coeffs[2] * w[1];
  401. w[1] = w[0];
  402. w[0] = d0;
  403. }
  404. #endif
  405. return stream;
  406. };