arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
Filter.h
1#pragma once
2#include "AudioToolsConfig.h"
3#include <math.h>
4#ifdef USE_TYPETRAITS
5#include <type_traits>
6#endif
7
20namespace audio_tools {
21
27template <typename T>
28class Filter {
29 public:
30 // construct without coefs
31 Filter() = default;
32 virtual ~Filter() = default;
33 Filter(Filter const &) = delete;
34 Filter &operator=(Filter const &) = delete;
35
36 virtual T process(T in) = 0;
37};
38
45template <typename T>
46class NoFilter : Filter<T> {
47 public:
48 // construct without coefs
49 NoFilter() = default;
50 virtual T process(T in) { return in; }
51};
52
62template <typename T>
63class FIR : public Filter<T> {
64 public:
65 template <size_t B>
66 FIR(const T (&b)[B], const T factor = 1.0) : lenB(B), factor(factor) {
67 setValues(b);
68 }
69
70 template <size_t B>
71 void setValues(const T (&b)[B]) {
72 x.resize(lenB);
73 coeff_b.resize(2 * lenB - 1);
74 for (uint16_t i = 0; i < 2 * lenB - 1; i++) {
75 coeff_b[i] = b[(2 * lenB - 1 - i) % lenB];
76 }
77 }
78
79 T process(T value) {
80 x[i_b] = value;
81 T b_terms = 0;
82 T *b_shift = &coeff_b[lenB - i_b - 1];
83 for (uint8_t i = 0; i < lenB; i++) {
84 b_terms += b_shift[i] * x[i];
85 }
86 i_b++;
87 if (i_b == lenB) i_b = 0;
88
89#ifdef USE_TYPETRAITS
90 if (!(std::is_same<T, float>::value || std::is_same<T, float>::value)) {
91 b_terms = b_terms / factor;
92 }
93#else
94 if (factor != 1.0) {
95 b_terms = b_terms / factor;
96 }
97#endif
98 return b_terms;
99 }
100
101 private:
102 const uint8_t lenB;
103 uint8_t i_b = 0;
104 Vector<T> x;
105 Vector<T> coeff_b;
106 T factor;
107};
108
117template <typename T>
118class IIR : public Filter<T> {
119 public:
120 template <size_t B, size_t A>
121 IIR(const T (&b)[B], const T (&_a)[A], T factor = 1.0)
122 : factor(factor), lenB(B), lenA(A - 1) {
123 x.resize(lenB);
124 y.resize(lenA);
125 coeff_b.resize(2 * lenB - 1);
126 coeff_a.resize(2 * lenA - 1);
127 T a0 = _a[0];
128 const T *a = &_a[1];
129 for (uint16_t i = 0; i < 2 * lenB - 1; i++) {
130 coeff_b[i] = b[(2 * lenB - 1 - i) % lenB] / a0;
131 }
132 for (uint16_t i = 0; i < 2 * lenA - 1; i++) {
133 coeff_a[i] = a[(2 * lenA - 2 - i) % lenA] / a0;
134 }
135 }
136
137
138 T process(T value) {
139 x[i_b] = value;
140 T b_terms = 0;
141 T *b_shift = &coeff_b[lenB - i_b - 1];
142
143 T a_terms = 0;
144 T *a_shift = &coeff_a[lenA - i_a - 1];
145
146 for (uint8_t i = 0; i < lenB; i++) {
147 b_terms += x[i] * b_shift[i];
148 }
149 for (uint8_t i = 0; i < lenA; i++) {
150 a_terms += y[i] * a_shift[i];
151 }
152
153 T filtered = b_terms - a_terms;
154 y[i_a] = filtered;
155 i_b++;
156 if (i_b == lenB) i_b = 0;
157 i_a++;
158 if (i_a == lenA) i_a = 0;
159
160#ifdef USE_TYPETRAITS
161 if (!(std::is_same<T, float>::value || std::is_same<T, float>::value)) {
162 filtered = filtered / factor;
163 }
164#else
165 if (factor != 1.0) {
166 filtered = filtered / factor;
167 }
168#endif
169 return filtered;
170 }
171
172 private:
173 T factor;
174 const uint8_t lenB, lenA;
175 uint8_t i_b = 0, i_a = 0;
176 Vector<T> x;
177 Vector<T> y;
178 Vector<T> coeff_b;
179 Vector<T> coeff_a;
180};
181
191template <typename T>
192class BiQuadDF1 : public Filter<T> {
193 public:
194 BiQuadDF1(const T (&b)[3], const T (&a)[3])
195 : b_0(b[0] / a[0]),
196 b_1(b[1] / a[0]),
197 b_2(b[2] / a[0]),
198 a_1(a[1] / a[0]),
199 a_2(a[2] / a[0]) {}
200 BiQuadDF1(const T (&b)[3], const T (&a)[2])
201 : b_0(b[0]), b_1(b[1]), b_2(b[2]), a_1(a[0]), a_2(a[1]) {}
202 BiQuadDF1(const T (&b)[3], const T (&a)[2], T gain)
203 : b_0(gain * b[0]),
204 b_1(gain * b[1]),
205 b_2(gain * b[2]),
206 a_1(a[0]),
207 a_2(a[1]) {}
208 BiQuadDF1(const T (&b)[3], const T (&a)[3], T gain)
209 : b_0(gain * b[0] / a[0]),
210 b_1(gain * b[1] / a[0]),
211 b_2(gain * b[2] / a[0]),
212 a_1(a[1] / a[0]),
213 a_2(a[2] / a[0]) {}
214
215 T process(T value) {
216 T x_2 = x_1;
217 x_1 = x_0;
218 x_0 = value;
219 T b_terms = x_0 * b_0 + x_1 * b_1 + x_2 * b_2;
220 T a_terms = y_1 * a_1 + y_2 * a_2;
221 y_2 = y_1;
222 y_1 = b_terms - a_terms;
223 return y_1;
224 }
225
226 private:
227 T b_0;
228 T b_1;
229 T b_2;
230 T a_1;
231 T a_2;
232
233 T x_0 = 0;
234 T x_1 = 0;
235 T y_1 = 0;
236 T y_2 = 0;
237};
238
249template <typename T>
250class BiQuadDF2 : public Filter<T> {
251 public:
252 BiQuadDF2(const T (&b)[3], const T (&a)[3])
253 : b_0(b[0] / a[0]),
254 b_1(b[1] / a[0]),
255 b_2(b[2] / a[0]),
256 a_1(a[1] / a[0]),
257 a_2(a[2] / a[0]) {}
258 BiQuadDF2(const T (&b)[3], const T (&a)[2])
259 : b_0(b[0]), b_1(b[1]), b_2(b[2]), a_1(a[0]), a_2(a[1]) {}
260 BiQuadDF2(const T (&b)[3], const T (&a)[2], T gain)
261 : b_0(gain * b[0]),
262 b_1(gain * b[1]),
263 b_2(gain * b[2]),
264 a_1(a[0]),
265 a_2(a[1]) {}
266 BiQuadDF2(const T (&b)[3], const T (&a)[3], T gain)
267 : b_0(gain * b[0] / a[0]),
268 b_1(gain * b[1] / a[0]),
269 b_2(gain * b[2] / a[0]),
270 a_1(a[1] / a[0]),
271 a_2(a[2] / a[0]) {}
272
273 T process(T value) {
274 T w_2 = w_1;
275 w_1 = w_0;
276 w_0 = value - a_1 * w_1 - a_2 * w_2;
277 T y = b_0 * w_0 + b_1 * w_1 + b_2 * w_2;
278 return y;
279 }
280
281 protected:
282 T b_0 = 0;
283 T b_1 = 0;
284 T b_2 = 0;
285 T a_1 = 0;
286 T a_2 = 0;
287
288 // allow constructor w/o parameter in subclasses
289 BiQuadDF2() = default;
290
291 T w_0 = 0;
292 T w_1 = 0;
293};
294
307template <typename T>
308class LowPassFilter : public BiQuadDF2<T> {
309 public:
310 LowPassFilter(float frequency, float sampleRate, float q = 0.7071f)
311 : BiQuadDF2<T>() {
312 begin(frequency, sampleRate, q);
313 }
314 void begin(float frequency, float sampleRate, float q = 0.7071f) {
315 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
316 T sinW0 = sin(w0);
317 T alpha = sinW0 / ((float)q * 2.0);
318 T cosW0 = cos(w0);
319 T scale = 1.0 / (1.0 + alpha);
320 BiQuadDF2<T>::b_0 = ((1.0 - cosW0) / 2.0) * scale;
321 BiQuadDF2<T>::b_1 = (1.0 - cosW0) * scale;
323 BiQuadDF2<T>::a_1 = (-2.0 * cosW0) * scale;
324 BiQuadDF2<T>::a_2 = (1.0 - alpha) * scale;
325 }
326};
327
340template <typename T>
341class HighPassFilter : public BiQuadDF2<T> {
342 public:
343 HighPassFilter(float frequency, float sampleRate, float q = 0.7071)
344 : BiQuadDF2<T>() {
345 begin(frequency, sampleRate, q);
346 }
347 void begin(float frequency, float sampleRate, float q = 0.7071) {
348 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
349 T sinW0 = sin(w0);
350 T alpha = sinW0 / ((float)q * 2.0);
351 T cosW0 = cos(w0);
352 T scale = 1.0 / (1.0 + alpha);
353 BiQuadDF2<T>::b_0 = ((1.0 + cosW0) / 2.0) * scale;
354 BiQuadDF2<T>::b_1 = -(1.0 + cosW0) * scale;
356 BiQuadDF2<T>::a_1 = (-2.0 * cosW0) * scale;
357 BiQuadDF2<T>::a_2 = (1.0 - alpha) * scale;
358 }
359};
360
373template <typename T>
374class BandPassFilter : public BiQuadDF2<T> {
375 public:
376 BandPassFilter(float frequency, float sampleRate, float q = 1.0)
377 : BiQuadDF2<T>() {
378 begin(frequency, sampleRate, q);
379 }
380 void begin(float frequency, float sampleRate, float q = 1.0) {
381 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
382 T sinW0 = sin(w0);
383 T alpha = sinW0 / ((T)q * 2.0);
384 T cosW0 = cos(w0);
385 T scale = 1.0 / (1.0 + alpha);
386 BiQuadDF2<T>::b_0 = alpha * scale;
388 BiQuadDF2<T>::b_2 = (-alpha) * scale;
389 BiQuadDF2<T>::a_1 = (-2.0 * cosW0) * scale;
390 BiQuadDF2<T>::a_2 = (1.0 - alpha) * scale;
391 }
392};
393
406template <typename T>
407class NotchFilter : public BiQuadDF2<T> {
408 public:
409 NotchFilter(float frequency, float sampleRate, float q = 1.0)
410 : BiQuadDF2<T>() {
411 begin(frequency, sampleRate, q);
412 }
413
414 void begin(float frequency, float sampleRate, float q = 1.0) {
415 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
416 T sinW0 = sin(w0);
417 T alpha = sinW0 / ((float)q * 2.0);
418 T cosW0 = cos(w0);
419 T scale = 1.0 / (1.0 + alpha);
420 BiQuadDF2<T>::b_0 = scale;
421 BiQuadDF2<T>::b_1 = (-2.0 * cosW0) * scale;
423 BiQuadDF2<T>::a_1 = (-2.0 * cosW0) * scale;
424 BiQuadDF2<T>::a_2 = (1.0 - alpha) * scale;
425 }
426};
427
440template <typename T>
441class LowShelfFilter : public BiQuadDF2<T> {
442 public:
443 LowShelfFilter(float frequency, float sampleRate, float gain,
444 float slope = 1.0f)
445 : BiQuadDF2<T>() {
446 begin(frequency, sampleRate, gain, slope);
447 }
448
449 void begin(float frequency, float sampleRate, float gain,
450 float slope = 1.0f) {
451 T a = pow(10.0, gain / 40.0f);
452 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
453 T sinW0 = sin(w0);
454 // float alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
455 T cosW0 = cos(w0);
456 // generate three helper-values (intermediate results):
457 T sinsq = sinW0 *
458 sqrt((pow(a, 2.0) + 1.0) * (1.0 / (float)slope - 1.0) + 2.0 * a);
459 T aMinus = (a - 1.0) * cosW0;
460 T aPlus = (a + 1.0) * cosW0;
461 T scale = 1.0 / ((a + 1.0) + aMinus + sinsq);
462 BiQuadDF2<T>::b_0 = a * ((a + 1.0) - aMinus + sinsq) * scale;
463 BiQuadDF2<T>::b_1 = 2.0 * a * ((a - 1.0) - aPlus) * scale;
464 BiQuadDF2<T>::b_2 = a * ((a + 1.0) - aMinus - sinsq) * scale;
465 BiQuadDF2<T>::a_1 = -2.0 * ((a - 1.0) + aPlus) * scale;
466 BiQuadDF2<T>::a_2 = ((a + 1.0) + aMinus - sinsq) * scale;
467 }
468};
469
482template <typename T>
483class HighShelfFilter : public BiQuadDF2<T> {
484 public:
485 HighShelfFilter(float frequency, float sampleRate, float gain,
486 float slope = 1.0f)
487 : BiQuadDF2<T>() {
488 begin(frequency, sampleRate, gain, slope);
489 }
490 void begin(float frequency, float sampleRate, float gain,
491 float slope = 1.0f) {
492 T a = pow(10.0, gain / 40.0f);
493 T w0 = frequency * (2.0f * 3.141592654f / sampleRate);
494 T sinW0 = sin(w0);
495 // float alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
496 T cosW0 = cos(w0);
497 // generate three helper-values (intermediate results):
498 T sinsq = sinW0 *
499 sqrt((pow(a, 2.0) + 1.0) * (1.0 / (float)slope - 1.0) + 2.0 * a);
500 T aMinus = (a - 1.0) * cosW0;
501 T aPlus = (a + 1.0) * cosW0;
502 T scale = 1.0 / ((a + 1.0) - aMinus + sinsq);
503 BiQuadDF2<T>::b_0 = a * ((a + 1.0) + aMinus + sinsq) * scale;
504 BiQuadDF2<T>::b_1 = -2.0 * a * ((a - 1.0) + aPlus) * scale;
505 BiQuadDF2<T>::b_2 = a * ((a + 1.0) + aMinus - sinsq) * scale;
506 BiQuadDF2<T>::a_1 = 2.0 * ((a - 1.0) - aPlus) * scale;
507 BiQuadDF2<T>::a_2 = ((a + 1.0) - aMinus - sinsq) * scale;
508 }
509};
510
521template <typename T, size_t N>
522class SOSFilter : public Filter<T> {
523 public:
524 SOSFilter(const T (&b)[N][3], const T (&a)[N][3], const T (&gain)[N]) {
525 for (size_t i = 0; i < N; i++)
526 filters[i] = new BiQuadDF2<T>(b[i], a[i], gain[i]);
527 }
528 SOSFilter(const T (&sos)[N][6], const T (&gain)[N]) {
529 for (size_t i = 0; i < N; i++) {
530 T b[3];
531 T a[3];
532 copy(b, &sos[i][0]);
533 copy(a, &sos[i][3]);
534 filters[i] = new BiQuadDF2<T>(b, a, gain[i]);
535 }
536 }
537 SOSFilter(const T (&b)[N][3], const T (&a)[N][2], const T (&gain)[N]) {
538 for (size_t i = 0; i < N; i++)
539 filters[i] = new BiQuadDF2<T>(b[i], a[i], gain[i]);
540 }
541 SOSFilter(const T (&b)[N][3], const T (&a)[N][2]) {
542 for (size_t i = 0; i < N; i++) filters[i] = new BiQuadDF2<T>(b[i], a[i]);
543 }
544 SOSFilter(const T (&b)[N][3], const T (&a)[N][3]) {
545 for (size_t i = 0; i < N; i++) filters[i] = new BiQuadDF2<T>(b[i], a[i]);
546 }
547 ~SOSFilter() {
548 for (size_t i = 0; i < N; i++) delete filters[i];
549 }
550 T process(T value) {
551 for (Filter<T> *&filter : filters) value = filter->process(value);
552 return value;
553 }
554
555 private:
556 Filter<T> *filters[N];
557 template <size_t M>
558 void copy(T (&dest)[M], const T *src) {
559 for (size_t i = 0; i < M; i++) dest[i] = src[i];
560 }
561};
562
569template <typename T, size_t N>
570class FilterChain : public Filter<T> {
571 public:
572 FilterChain(Filter<T> *(&&filters)[N]) {
573 for (size_t i = 0; i < N; i++) {
574 this->filters[i] = filters[i];
575 }
576 }
577
578 T process(T value) {
579 for (Filter<T> *&filter : filters) {
580 if (filter != nullptr) {
581 value = filter->process(value);
582 }
583 }
584 return value;
585 }
586
587 private:
588 Filter<T> *filters[N] = {0};
589};
590
591} // namespace audio_tools
Biquad DF2 Band Pass Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:374
Biquad DF1 Filter. converted from https://github.com/tttapa/Filters/blob/master/src/BiQuad....
Definition Filter.h:192
Biquad DF2 Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:250
FIR Filter Converted from https://github.com/sebnil/FIR-filter-Arduino-Library/tree/master/src You ca...
Definition Filter.h:63
FilterChain - A Cascade of multiple filters.
Definition Filter.h:570
Abstract filter interface definition;.
Definition Filter.h:28
Biquad DF2 High Pass Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:341
Biquad DF2 High Shelf Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:483
IIRFilter Converted from https://github.com/tttapa/Filters/blob/master/src/IIRFilter....
Definition Filter.h:118
Biquad DF2 Low Pass Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:308
Biquad DF2 Low Shelf Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:441
No change to the input.
Definition Filter.h:46
Biquad DF2 Notch Filter. When dealing with high-order IIR filters, they can get unstable....
Definition Filter.h:407
Second Order Filter: Instead of manually cascading BiQuad filters, you can use a Second Order Section...
Definition Filter.h:522
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10