arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AudioEffectsSuite.h
1#pragma once
2
20#include <cmath>
21#include <cstdint>
22#include <iostream>
23#include "AudioTools/CoreAudio/AudioEffects/AudioEffect.h"
24#include "AudioTools/CoreAudio/AudioStreams.h"
25
26#ifndef PI
27# define PI 3.141592653589793f
28#endif
29
30namespace audio_tools {
31
32typedef float effectsuite_t;
33
38static effectsuite_t **interpolationTable = nullptr;
39
51 virtual effectsuite_t processDouble(effectsuite_t inputSample) = 0;
52
58 virtual effect_t process(effect_t inputSample) override {
59 return active_flag ? 32767.0f * processDouble(static_cast<effectsuite_t>(inputSample)/32767.0f) : inputSample;
60 }
61
62};
63
64
75public:
77 ModulationBaseClass() { srand(static_cast<unsigned>(time(0))); }
78
80
81 ModulationBaseClass(effectsuite_t extSampRate) {
82 this->sampleRate = extSampRate;
83 timeStep = 1. / extSampRate;
85 // setInterpTable();
86 srand(static_cast<unsigned>(time(0)));
87 }
90
96 void setupModulationBaseClass(effectsuite_t extSampRate) {
97 if (waveTable != nullptr) {
98 delete[] waveTable;
99 }
100 sampleRate = extSampRate;
101 timeStep = 1. / extSampRate;
103 }
104
108 void setTriangle() {
109 std::fill(waveTable, waveTable + sampleRate, 0);
110 const effectsuite_t radPerSec = 2 * 3.1415926536f * timeStep;
111 for (int i = 0; i < sampleRate; i++) {
112 for (int j = 0; j < 35; j += 1)
113 waveTable[i] += pow(-1., j) *
114 (sin((2. * effectsuite_t(j) + 1) * i * radPerSec)) /
115 (2. * effectsuite_t(j) + 1);
116 }
117 }
121 void setSquare() {
122 std::fill(waveTable, waveTable + sampleRate, 0);
123 const effectsuite_t radPerSec = 2 * 3.1415926536f * timeStep;
124 for (int i = 0; i < sampleRate; i++) {
125 for (int j = 0; j < 35; j += 1)
126 waveTable[i] += (sin((2 * j + 1) * i * radPerSec)) / (2 * j + 1);
127 }
128 }
132 void setSawtooth() {
133 std::fill(waveTable, waveTable + sampleRate, 0);
134 const effectsuite_t radPerSec = 2 * 3.1415926536f * timeStep;
135 for (int i = 0; i < sampleRate; i++) {
136 for (int j = 1; j < 11; j += 1)
137 waveTable[i] += pow(-1, j) * sin(j * radPerSec * i) / effectsuite_t(j);
138 }
139 }
143 void setSine() {
144 const effectsuite_t radPerSec = 2 * 3.1415926536f * timeStep;
145 for (int i = 0; i < sampleRate; i++)
146 waveTable[i] = sin(i * radPerSec);
147 }
151 void setOffSine() {
152 const effectsuite_t radPerSec = 2 * 3.1415926536f * timeStep;
153 for (int i = 0; i < sampleRate; i++)
154 waveTable[i] = (sin(i * radPerSec) + 1) * .5f;
155 }
156
157 void setNoise() {
158 is_noise = true;
159 }
160
161 bool isNoise() {
162 return is_noise;
163 }
164
168 void setDC() {
169 for (int i = 0; i < sampleRate; i++)
170 waveTable[i] = 1.0;
171 }
173 void setRamp() {
174 for (int i = 0; i < sampleRate; i++)
175 waveTable[i] = i / effectsuite_t(sampleRate);
176 }
181 effectsuite_t readNoise() {
182 const effectsuite_t lo = -1.;
183 const effectsuite_t hi = 1.;
184 return lo + static_cast<effectsuite_t>(rand()) /
185 (static_cast<effectsuite_t>(RAND_MAX / (hi - lo)));
186 }
193 void clipWave(effectsuite_t amp) {
194 if (amp < .01) {
195 amp = .01;
196 }
197
198 for (int i = 0; i < sampleRate; i++)
199 waveTable[i] = tanh(amp * waveTable[i]) / tanh(amp);
200 }
201
208 effectsuite_t readTable(effectsuite_t freq) {
209 if (freq > 0) {
210 // const effectsuite_t out = getInterpOut(tableIndex);
211 const effectsuite_t out = getSplineOut(tableIndex, int(freq));
212 tableIndex += freq;
213 if (tableIndex - sampleRate > 0)
215
216 return out;
217 } else {
218 return 0.;
219 }
220 }
221 void printInterpTable() {
222 for (int j = 0; j < res; j++) {
223 for (int i = 0; i < order; i++) {
224 std::cout << interpTable[i][j] << '\t';
225 }
226 std::cout << '\n';
227 }
228 }
234 effectsuite_t *polynomial_normaliser = new effectsuite_t[order];
235 if (!polynomial_normaliser) {
236 return false;
237 }
238 std::fill(polynomial_normaliser, polynomial_normaliser + order, 1);
239 effectsuite_t *alphas = new effectsuite_t[res];
240 if (!alphas) {
241 return false;
242 }
243
244 for (int i = 0; i < res; i++) {
245 alphas[i] = (i / float(res)) - 0.5;
246 }
247
248 effectsuite_t *anchors = new effectsuite_t[order];
249
250 if ((order % 2) == 0) {
251 for (int i = 0; i < order; i++) {
252 anchors[i] = -(effectsuite_t(order) - 1) * 0.5 + effectsuite_t(i);
253 std::fill(interpTable[i], interpTable[i] + res, 1);
254 }
255 } else {
256 for (int i = 0; i < order; i++) {
257 anchors[i] = (-(effectsuite_t(order)) * 0.5) + effectsuite_t(i);
258 }
259 }
260
261 // loop for every value of alpha
262 for (int q = 0; q < res; q++) {
263 // loop for sub polynomial
264 for (int j = 0; j < order; j++) {
265 // loop for each point in subpoly
266 for (int m = 0; m < order; m++) {
267 if (m != j) {
268 if (q == 0) {
269 polynomial_normaliser[j] =
270 polynomial_normaliser[j] * (anchors[j] - anchors[m]);
271 }
272 interpTable[j][q] *= (alphas[q] - anchors[m]);
273 }
274 }
275 interpTable[j][q] /= polynomial_normaliser[j];
276 }
277 }
278
279 delete[] polynomial_normaliser;
280 delete[] alphas;
281 delete[] anchors;
282 return true;
283 }
284
285protected:
291 waveTable = new effectsuite_t[sampleRate];
292 assert(waveTable!=nullptr);
293 if (!waveTable) {
294 return false;
295 }
296 std::fill(waveTable, waveTable + sampleRate, 0);
297 return true;
298 }
305 effectsuite_t getInterpOut(effectsuite_t bufferIndex) {
306 const int order = 4;
307 const int orderHalf = order * .5;
308 const int res = 100;
309 effectsuite_t interpOut = 0;
310 int intBufferIndex = floor(bufferIndex);
311 int alphaIndex = int(floor((bufferIndex - intBufferIndex) * res));
312
313 for (int i = 0; i < order; i++) {
314 int interpIndex =
315 (((i + 1 - orderHalf) + intBufferIndex) + sampleRate) % sampleRate;
316 interpOut += (interpTable[i][alphaIndex]) * (waveTable[interpIndex]);
317 }
318 return interpOut;
319 }
320
332 effectsuite_t getSplineOut(effectsuite_t bufferIndex, int freq) {
333 if (freq < 1) {
334 freq = 1;
335 }
336 const int n0 = floor(bufferIndex);
337 const int n1 = (n0 + freq) % sampleRate;
338 const int n2 = (n0 + (2 * freq)) % sampleRate;
339 const effectsuite_t alpha = bufferIndex - n0;
340 const effectsuite_t a = waveTable[n1];
341 const effectsuite_t c = ((3 * (waveTable[n2] - waveTable[n1])) -
342 (3 * (waveTable[n1] - waveTable[n0]))) *
343 .25;
344 const effectsuite_t b = (waveTable[n2] - waveTable[n1]) - ((2 * c)) / 3;
345 const effectsuite_t d = (-c) / 3;
346 return a + (b * alpha) + (c * alpha * alpha) + (d * alpha * alpha * alpha);
347 }
348
349public:
351 effectsuite_t tableIndex = 0;
355 effectsuite_t timeStep;
357 effectsuite_t *waveTable;
358
359protected:
360 static const int order = 4;
361 static const int res = 100;
362 effectsuite_t interpTable[order][res];// = {1};
363 bool is_noise = false;
364};
365
372 template <class T>
374 public:
376 p_mod = &mod;
377 this->freq = freq;
378 }
379 bool begin(AudioInfo info) override{
380 max_value = pow(2, info.bits_per_sample)/2-1;
381 return SoundGenerator<T>::begin(info);
382 }
383 virtual T readSample() override {
384 return p_mod->isNoise() ? max_value * p_mod->readNoise() : max_value * p_mod->readTable(freq);
385 }
386
387 protected:
388 ModulationBaseClass *p_mod=nullptr;
389 int freq;
390 float max_value=32767;
391};
392
393
404public:
406 DelayEffectBase() = default;
407
408 DelayEffectBase(DelayEffectBase &copy) = default;
409
410 DelayEffectBase(int bufferSizeSamples) {
411 error = setDelayBuffer(bufferSizeSamples);
412 delayTimeSamples = bufferSizeSamples;
413 if (interpolationTable == nullptr) {
415 }
416 }
417
420 if (delayBuffer != nullptr)
421 delete[] delayBuffer;
422 }
423
428 void setupDelayEffectBase(const int bufferSizeSamples) {
429 error = setDelayBuffer(bufferSizeSamples);
430 delayTimeSamples = bufferSizeSamples;
431 }
432
433protected:
441 static effectsuite_t **setInterpolationTable() {
442 const int order = interpOrder;
443 const int res = interpResolution;
444 effectsuite_t **interpTable = new effectsuite_t *[order];
445 if (!interpTable) {
446 return NULL;
447 }
448
449 for (int i = 0; i < order; i++) {
450 interpTable[i] = new effectsuite_t[res + 1];
451 if (!interpTable[i]) {
452 return NULL;
453 }
454 std::fill(interpTable[i], interpTable[i] + res, 1);
455 }
456
457 effectsuite_t *polynomial_normaliser = new effectsuite_t[order];
458 if (!polynomial_normaliser) {
459 return NULL;
460 }
461 std::fill(polynomial_normaliser, polynomial_normaliser + order, 1);
462 effectsuite_t *alphas = new effectsuite_t[res];
463 if (!alphas) {
464 return NULL;
465 }
466
467 for (int i = 0; i < res; i++) {
468 alphas[i] = (i / float(res)) - 0.5;
469 }
470
471 effectsuite_t *anchors = new effectsuite_t[order];
472
473 if ((order % 2) == 0) {
474 for (int i = 0; i < order; i++) {
475 anchors[i] = -(effectsuite_t(order) - 1) * 0.5 + effectsuite_t(i);
476 }
477 } else {
478 for (int i = 0; i < order; i++) {
479 anchors[i] = (-(effectsuite_t(order)) * 0.5) + effectsuite_t(i);
480 }
481 }
482
483 // loop for every value of alpha
484 for (int q = 0; q < res; q++) {
485 // loop for sub polynomial
486 for (int j = 0; j < order; j++) {
487 // loop for each point in subpoly
488 for (int m = 0; m < order; m++) {
489 if (m != j) {
490 if (q == 0) {
491 polynomial_normaliser[j] =
492 polynomial_normaliser[j] * (anchors[j] - anchors[m]);
493 }
494 interpTable[j][q] *= (alphas[q] - anchors[m]);
495 }
496 }
497 interpTable[j][q] /= polynomial_normaliser[j];
498 }
499 }
500 delete[] polynomial_normaliser;
501 delete[] alphas;
502 delete[] anchors;
503 return interpTable;
504 }
505
506 // void printInterpTable() {
507 // for (int j = 0; j < interpResolution; j++) {
508 // for (int i = 0; i < interpOrder; i++) {
509 // printf("index %d: %.2f \t", i, interpolationTable[i][j]);
510 // }
511 // printf("\n");
512 // }
513 // }
514
515protected:
522 bool setDelayBuffer(int bufferSizeSamples) {
523 maxDelayBufferSize = bufferSizeSamples;
524 delayBuffer = new effectsuite_t[maxDelayBufferSize];
525 if (!delayBuffer) {
526 return false;
527 }
529 return true;
530 }
531
536 void storeSample(effectsuite_t inputSample) {
537 delayBuffer[currentDelayWriteIndex] = inputSample;
538 }
539
544 currentDelayWriteIndex++;
545 currentDelayWriteIndex %= delayTimeSamples;
546 }
547
552 void incDelayBuffReadIndex(effectsuite_t indexInc) {
553 currentDelayReadIndex += indexInc;
554 if (currentDelayReadIndex >= effectsuite_t(delayTimeSamples)) {
555 currentDelayReadIndex = 0;
556 }
557 if (currentDelayReadIndex < 0) {
558 currentDelayReadIndex = 0;
559 }
560 }
561
566 void setDelayBuffReadIndex(effectsuite_t index) {
567 currentDelayReadIndex = index;
568 if (currentDelayReadIndex >= effectsuite_t(delayTimeSamples)) {
569 currentDelayReadIndex = 0;
570 }
571 if (currentDelayReadIndex < 0) {
572 currentDelayReadIndex = 0;
573 }
574 }
575
581 void delaySample(effectsuite_t inputSample) {
582 storeSample(inputSample);
584 }
590 effectsuite_t getInterpolatedOut(effectsuite_t bufferIndex) {
591 const int order = interpOrder;
592 const int orderHalf = order * .5;
593 const int res = interpResolution;
594 effectsuite_t interpOut = 0;
595 int intBufferIndex = floor(bufferIndex);
596 int alphaIndex = int(floor((bufferIndex - intBufferIndex) * res));
597
598 for (int i = 0; i < order; i++) {
599 int interpIndex = (i + 1 - orderHalf) + intBufferIndex;
600 if (interpIndex < 0 || (interpIndex >= maxDelayBufferSize)) {
601 if (interpIndex < 0) {
602 interpIndex = maxDelayBufferSize + interpIndex;
603 } else {
604 interpIndex = interpIndex - maxDelayBufferSize;
605 }
606 }
607
608 interpOut +=
609 (interpolationTable[i][alphaIndex]) * (delayBuffer[interpIndex]);
610 }
611 return interpOut;
612 }
613
614protected: // member variables
616 effectsuite_t *delayBuffer = 0;
618 int maxDelayBufferSize = 441000;
620 int delayTimeSamples = 44100;
621 int currentDelayWriteIndex = 0;
622 effectsuite_t currentDelayReadIndex = 0;
623 static const int interpOrder = 4;
624 static const int interpResolution = 1000;
625
627 bool error;
628};
629
639public:
642
643 FilterEffectBase(FilterEffectBase &copy) = default;
644
646 ~FilterEffectBase() = default;
647
654 virtual effectsuite_t applyFilter(effectsuite_t sampVal) {
655 effectsuite_t outSample = 0;
656 firBuffer[bufferIndex] = sampVal;
657
658 for (int j = 0; j < filterOrder; j++) {
659 int i = ((bufferIndex - j) + filterOrder) % filterOrder;
660 outSample +=
662 }
663
664 iirBuffer[bufferIndex] = outSample;
666
667 return outSample;
668 }
669
670 virtual effectsuite_t processDouble(effectsuite_t inputSample) override {
671 return applyFilter(inputSample);
672 }
673
675 virtual effect_t process(effect_t inputSample) override {
676 return active_flag ? 32767.0 * processDouble(static_cast<effectsuite_t>(inputSample)/32767.0) : inputSample;
677 }
678
684 effectsuite_t envelope(effectsuite_t sample) { return applyFilter(rms(sample)); }
685
686 // void printBuffers() {
687 // printf("FIRb\t\tIIRb\n");
688 // for (int i = 0; i < filterOrder; i++) {
689 // printf("%.4e\t%.4e\n", firBuffer[i], iirBuffer[i]);
690 // }
691 // printf("\n");
692 // }
693
694 // void printCoefs() {
695 // printf("FIR\t\tIIR\n");
696 // for (int i = 0; i < filterOrder; i++) {
697 // printf("%.4e\t%.4e\n", firCoefficients[i], iirCoefficients[i]);
698 // }
699 // printf("\n");
700 // }
701
713 bool setChebyICoefficients(effectsuite_t cutFreq, bool shelfType, effectsuite_t ripple) {
714 // NOTE: coefficient buffers must be cleared as are additive in the
715 // following code
716 std::fill(firCoefficients, firCoefficients + 22, 0);
717 std::fill(iirCoefficients, iirCoefficients + 22, 0);
718
719 effectsuite_t poles = (effectsuite_t)filterOrder - 1;
720 int order = (int)poles;
721
722 firCoefficients[2] = 1;
723 iirCoefficients[2] = 1;
724
725 effectsuite_t Es, Vx, Kx;
726 if (ripple != 0) {
727 Es = sqrt(pow(1 / (1 - ripple), 2) - 1);
728 Vx = (1 / poles) * log(1 / Es + sqrt(1 / (pow(Es, 2)) + 1));
729 Kx = (1 / poles) * log(1 / Es + sqrt(1 / (pow(Es, 2)) - 1));
730 Kx = cosh(Kx);
731 } else {
732 Vx = 1;
733 Kx = 1;
734 }
735
736 const effectsuite_t T = 2.0f * tan(.5f);
737 const effectsuite_t W = 2.0f * PI * cutFreq;
738
739 effectsuite_t K;
740
741 if (shelfType == 0)
742 {
743 K = sin(.5 - W / 2) / sin(.5 + W / 2);
744 } else
745 {
746
747 K = -cos(.5 + W / 2) / cos(W / 2 - .5);
748 }
749
751 for (int i = 0; i < (order / 2); i++) {
753 const effectsuite_t alpha = PI / (2 * poles) + (i - 1) * (PI / poles);
754
755 effectsuite_t Rp, Ip;
756 if (ripple != 0) {
757 Rp = -cos(alpha) * sinh(Vx) / Kx;
758 Ip = sin(alpha) * cosh(Vx) / Kx;
759 } else {
760 Rp = -cos(alpha);
761 Ip = sin(alpha);
762 }
763
764 const effectsuite_t M = pow(Rp, 2) + pow(Ip, 2);
765 const effectsuite_t D = 4 - 4 * Rp * T + M * T;
766
767 const effectsuite_t X0 = (pow(T, 2)) / D;
768 const effectsuite_t X1 = (2 * pow(T, 2)) / D;
769 const effectsuite_t X2 = X0;
770
771 const effectsuite_t Y1 = (8 - (2 * M * pow(T, 2))) / D;
772 const effectsuite_t Y2 = (-4 - 4 * Rp * T - M * T) / D;
773
774 // renamed and inverted from original algorithm
775 const effectsuite_t _D1 = 1 / (1 + Y1 * K - Y2 * pow(K, 2));
776
777 const effectsuite_t _A0 = (X0 - X1 * K + X2 * pow(K, 2)) * _D1;
778 effectsuite_t _A1 = (-2 * X0 * K + X1 + X1 * pow(K, 2) - 2 * X2 * K) * _D1;
779 const effectsuite_t _A2 = (X0 * pow(K, 2) - X1 * K + X2) * _D1;
780
781 effectsuite_t _B1 = (2 * K + Y1 + Y1 * pow(K, 2) - 2 * Y2 * K) * _D1;
782 const effectsuite_t B2 = (-(pow(K, 2)) - Y1 * K + Y2) * _D1;
783
784 if (shelfType == 1) {
785 _A1 = -_A1;
786 _B1 = -_B1;
787 }
788
789 for (int j = 0; j < 22; j++) {
790 firTemp[j] = firCoefficients[j];
791 iirTemp[j] = iirCoefficients[j];
792 }
793 for (int j = 2; j < 22; j++) {
794 firCoefficients[j] =
795 _A0 * firTemp[j] + _A1 * firTemp[j - 1] + _A2 * firTemp[j - 2];
796 iirCoefficients[j] =
797 iirTemp[j] - _B1 * iirTemp[j - 1] - B2 * iirTemp[j - 2];
798 }
799 }
800
801 iirCoefficients[2] = 0;
802 for (int j = 0; j < filterOrder; j++) {
804 iirCoefficients[j] = -iirCoefficients[j + 2];
805 }
807 effectsuite_t SA = 0;
808 effectsuite_t SB = 0;
809 if (shelfType == 0) {
810 for (int j = 0; j < filterOrder; j++) {
811 SA += firCoefficients[j];
812 SB += iirCoefficients[j];
813 }
814 } else {
815 for (int j = 0; j < order; j++) {
816 SA += firCoefficients[j] * pow(-1, j);
817 SB += iirCoefficients[j] * pow(-1, j);
818 }
819 }
820
821 const effectsuite_t gain = SA / (1 - SB);
822 for (int j = 0; j < filterOrder; j++) {
823 firCoefficients[j] /= gain;
824 }
825
826 return true;
827 }
828
829protected:
840 bool changeChebyICoefficients(effectsuite_t cutFreq, bool shelfType, effectsuite_t ripple,
841 int poles) {
842 filterOrder = poles + 1;
843 clearMemory();
845 setChebyICoefficients(cutFreq, shelfType, ripple);
846
847 return true;
848 }
849
854 bool setSimpleLpf(int order) {
855 filterOrder = order;
856 clearMemory();
858 firCoefficients = new effectsuite_t[filterOrder];
859 iirCoefficients = new effectsuite_t[filterOrder];
861 int coef = 1;
862 effectsuite_t gain = 0;
863 for (int j = 0; j < filterOrder; j++) {
864 if (j == 0) {
865 coef = 1;
866 } else {
867 coef = coef * (filterOrder - j) / j;
868 }
869
870 firCoefficients[j] = (effectsuite_t)coef;
871 gain += firCoefficients[j];
872 }
873
874 for (int j = 0; j <= filterOrder; j++) {
875 firCoefficients[j] /= gain;
876 }
877
878 return true;
879 }
880
881protected:
884 bufferIndex++;
886 }
887
892 void clearMemory() {
893 if (firCoefficients) {
894 delete[] firCoefficients;
895 }
896
897 if (iirCoefficients) {
898 delete[] iirCoefficients;
899 }
900 }
901
907 if (firBuffer) {
908 delete[] firBuffer;
909 }
910
911 if (iirBuffer) {
912 delete[] iirBuffer;
913 }
914 firBuffer = new effectsuite_t[filterOrder];
915 iirBuffer = new effectsuite_t[filterOrder];
916 std::fill(firBuffer, firBuffer + filterOrder, 0);
917 std::fill(iirBuffer, iirBuffer + filterOrder, 0);
918
919 if (firCoefficients) {
920 delete[] firCoefficients;
921 }
922
923 if (iirCoefficients) {
924 delete[] iirCoefficients;
925 }
926
927 if (firTemp) {
928 delete[] firTemp;
929 }
930
931 if (iirTemp) {
932 delete[] iirTemp;
933 }
934
935 firCoefficients = new effectsuite_t[22];
936 iirCoefficients = new effectsuite_t[22];
937 firTemp = new effectsuite_t[22];
938 iirTemp = new effectsuite_t[22];
939 std::fill(firCoefficients, firCoefficients + 22, 0);
940 std::fill(iirCoefficients, iirCoefficients + 22, 0);
941 std::fill(firTemp, firTemp + 22, 0);
942 std::fill(iirTemp, iirTemp + 22, 0);
943 }
944
946 effectsuite_t rms(effectsuite_t sample) {
947 rmsBuffer[rmsBufferIndex] = sample;
948 effectsuite_t rmsValue = 0;
949 for (int j = 0; j < rmsBufferIndex; j++) {
950 int i = ((rmsBufferIndex - j) + rmsWindowSize) % rmsWindowSize;
951 rmsValue += rmsBuffer[i] * rmsBuffer[i];
952 }
953
954 // printf("samp: %e\tsum: %e\n", sample, rmsValue);
955 rmsValue /= rmsWindowSize;
956 rmsValue = sqrt(rmsValue);
957
960
961 return rmsValue;
962 }
963
964protected:
969 effectsuite_t *firCoefficients = 0;
973 effectsuite_t *iirCoefficients = 0;
975 effectsuite_t *firTemp = 0;
977 effectsuite_t *iirTemp = 0;
980 effectsuite_t *firBuffer = 0;
983 effectsuite_t *iirBuffer = 0;
985 int bufferIndex = 0;
987 int filterOrder = 0;
988 /***/
989 int samplingRate = 0;
991 const int rmsWindowSize = 128;
995 effectsuite_t *rmsBuffer = new effectsuite_t[rmsWindowSize];
996
997};
998
1006public:
1013 SimpleLPF(effectsuite_t cutoff, int order) {
1014 changeChebyICoefficients(cutoff, false, .1, order);
1015 };
1016
1017 SimpleLPF(SimpleLPF &copy) = default;
1018
1020 ~SimpleLPF() = default;
1021
1022 SimpleLPF* clone(){
1023 return new SimpleLPF(*this);
1024 }
1025
1026};
1027
1037 public ModulationBaseClass,
1038 public SimpleLPF{
1039public:
1045// SimpleChorus() : SimpleLPF(0.0001, 4) {}
1046 SimpleChorus(int extSampleRate=44100) :
1047 DelayEffectBase(static_cast<int>(0.031 * extSampleRate)),
1048 ModulationBaseClass(extSampleRate),
1049 SimpleLPF(0.0001, 4) {
1050 swing = 0.005 * sampleRate;
1051 base = 0.015 * sampleRate;
1052 if (sampleRate != 0)
1053 setRandLfo();
1054 }
1055
1056 SimpleChorus(SimpleChorus &copy)=default;
1057
1058 ~SimpleChorus() = default;
1059
1065 virtual effectsuite_t processDouble(effectsuite_t inputSample) override {
1066 delaySample(inputSample);
1067 const effectsuite_t waveDelay = getModSignal();
1068 const effectsuite_t delayAmount =
1069 ((int(currentDelayWriteIndex - waveDelay) + delayTimeSamples) %
1071 ((currentDelayWriteIndex - waveDelay) -
1072 trunc(currentDelayWriteIndex - waveDelay));
1073 const effectsuite_t out = .0 * inputSample + 1. * getInterpolatedOut(delayAmount);
1074 return out;
1075 }
1076
1081 void setupChorus(effectsuite_t extSampleRate) {
1082 setupModulationBaseClass(extSampleRate);
1083 setupDelayEffectBase(effectsuite_t(extSampleRate) * .1);
1084 // SimpleLPF(0.0004,4)
1085 setChebyICoefficients(0.00005, false, 0);
1086
1087 swing = readSpeed * extSampleRate * 5;
1088 base = readSpeed * extSampleRate * 20;
1089 setRandLfo();
1090 }
1091
1097 void setSwing(effectsuite_t swingAmount) { swing = swingAmount * sampleRate; }
1098
1103 void setBase(effectsuite_t baseAmount) { base = baseAmount * sampleRate; }
1104
1105 SimpleChorus* clone() override {
1106 return new SimpleChorus(*this);
1107 }
1108
1109protected:
1113 effectsuite_t swing;
1115 effectsuite_t base;
1117 effectsuite_t modMin = .5;
1119 effectsuite_t modMax = .5;
1121 effectsuite_t modNorm = 1 / (modMax - modMin);
1122 const effectsuite_t readSpeed = ((readNoise() + 1) * .5) * .0005;
1123
1129 effectsuite_t getModSignal() { return (readTable(readSpeed) * swing) + base; }
1130
1131 void setRandLfo() {
1132 std::fill(iirBuffer, iirBuffer + filterOrder, .5);
1133 for (int i = 0; i < sampleRate; i++) {
1134 waveTable[i] = (readNoise() + 1) * .5;
1135 // waveTable[i] = applyFilter((readNoise()+1)*.5);
1136 if (waveTable[i] < modMin)
1137 modMin = waveTable[i];
1138 if (waveTable[i] > modMax) {
1139 modMax = waveTable[i];
1140 }
1141 }
1142
1143 modNorm = 1 / (modMax - modMin);
1144
1145 // normalises the delay signal
1146 for (int i = 0; i < sampleRate; i++) {
1147 waveTable[i] -= modMin;
1148 waveTable[i] *= modNorm;
1149 }
1150
1151 // setOffSine();
1152
1153 // this code fades out at the end and fades in at the start
1154 // to avoid any discontinuities int the signal.
1155 // const int fadeSize = 10000;
1156 // const effectsuite_t fadeSpeed = 2*M_PI/fadeSize;
1157 // for (int i = 0; i < fadeSize; i++)
1158 // {
1159 // const int fadeIndex = ((sampleRate-fadeSize/2)+i)%sampleRate;
1160 // waveTable[fadeIndex] *= (1+cos(fadeSpeed*i))*.5;
1161 // }
1162 }
1163};
1164
1172public:
1174 FilteredDelay(int delayInSamples, int sample_rate=44100) : DelayEffectBase(sample_rate) {
1175 delayTimeSamples = delayInSamples;
1176 changeChebyICoefficients(.05, true, .1, 4);
1177 };
1178
1179 FilteredDelay(FilteredDelay&copy) = default;
1180
1182 ~FilteredDelay() = default;
1183
1190 void setDelayGain(effectsuite_t gain) {
1191 capGain(gain);
1192 delayGain = gain;
1193 }
1194
1202 void setFeedbackGain(effectsuite_t gain) {
1203 capGain(gain);
1204 feedbackGain = gain;
1205 }
1206
1208 effectsuite_t processDouble(effectsuite_t inputSample) override {
1210 applyFilter((inputSample * delayGain) +
1211 feedbackGain * getInterpolatedOut(currentDelayWriteIndex)));
1212 const effectsuite_t out = getInterpolatedOut(currentDelayWriteIndex) + inputSample;
1213 return out;
1214 }
1215
1216 effect_t process(effect_t inputSample) override {
1217 return active_flag ? 32767.0 * processDouble(static_cast<effectsuite_t>(inputSample)/32767.0) : inputSample;
1218 }
1219
1220 FilteredDelay *clone() override {
1221 return new FilteredDelay(*this);
1222 }
1223
1224protected:
1229 void capGain(effectsuite_t &gain) {
1230 if (gain > 1.) {
1231 gain = 1.;
1232 } else if (gain < -1.) {
1233 gain = -1.;
1234 }
1235 return;
1236 }
1237
1238protected:
1239 effectsuite_t delayGain = .707, feedbackGain = 0.0;
1240};
1241
1252public:
1258 SimpleDelay(int maxDelayInSamples=8810, int samplingRate=44100) {
1259 writeHeadIndex = 0;
1260 readHeadIndex = 1;
1261 currentDelaySamples = maxDelayInSamples;
1262 targetDelaySamples = maxDelayInSamples;
1264 }
1265
1266 SimpleDelay(SimpleDelay &copy) = default;
1267
1269 ~SimpleDelay() = default;
1270
1278 void setDelayGain(effectsuite_t gain) {
1279 capGain(gain);
1280 delayGain = gain;
1281 }
1282
1290 void setFeedbackGain(effectsuite_t gain) {
1291 capGain(gain);
1292 feedbackGain = gain;
1293 }
1294
1300 effectsuite_t processDouble(effectsuite_t inputSample) override {
1301 // write sample
1302 delayBuffer[writeHeadIndex] = inputSample;
1303 writeHeadIndex++;
1304 writeHeadIndex %= maxDelayBufferSize;
1305
1306 // read sample
1307 effectsuite_t outSample = getSplineOut(readHeadIndex) + (inputSample * 1);
1308 if (delayTimeChanged) {
1309 count++;
1310 const effectsuite_t difference = (currentDelaySamples - targetDelaySamples);
1311 const effectsuite_t increment = delayIncrement * (difference / fabs(difference));
1312 currentDelaySamples -= increment;
1313 readHeadIndex += 1 + increment;
1314 readHeadIndex = std::fmod(readHeadIndex, maxDelayBufferSize);
1315 if (count > floor(delayTransitionTimeInSamples)) {
1316 currentDelaySamples = targetDelaySamples;
1317 readHeadIndex = floor(readHeadIndex);
1318 delayTimeChanged = false;
1319 }
1320 } else {
1321 readHeadIndex++;
1322 readHeadIndex = std::fmod(readHeadIndex, maxDelayBufferSize);
1323 }
1324 return outSample;
1325 }
1326
1327 effect_t process(effect_t inputSample) override {
1328 return active_flag ? 32767.0 * processDouble(static_cast<effectsuite_t>(inputSample)/32767.0) : inputSample;
1329 }
1330
1335 void setupSimpleDelay(int delayInSamples) {
1336 setupDelayEffectBase(delayInSamples);
1337 }
1342 void setDelayTime(effectsuite_t delayInSamples) {
1343 delayTimeChanged = true;
1344 targetDelaySamples = delayInSamples;
1345 const effectsuite_t delayTimeDifference = currentDelaySamples - targetDelaySamples;
1346 delayIncrement = delayTimeDifference / delayTransitionTimeInSamples;
1347 count = 0;
1348 }
1353 void setDelayTransitionTime(effectsuite_t seconds) {
1354 delayTransitionTime = seconds;
1355 delayTransitionTimeInSamples = seconds * sampleRate;
1356 }
1357
1358 SimpleDelay* clone() override {
1359 return new SimpleDelay(*this);
1360 }
1361
1362protected:
1367 void capGain(effectsuite_t &gain) {
1368 if (gain > 1.) {
1369 gain = 1.;
1370 } else if (gain < -1.) {
1371 gain = -1.;
1372 }
1373 return;
1374 }
1383 effectsuite_t getSplineOut(effectsuite_t bufferIndex) {
1384 const int n0 = floor(bufferIndex);
1385 const int n1 = (n0 + 1) % maxDelayBufferSize;
1386 const int n2 = (n0 + 2) % maxDelayBufferSize;
1387 const effectsuite_t alpha = bufferIndex - n0;
1388
1389 const effectsuite_t a = delayBuffer[n1];
1390 const effectsuite_t c = ((3 * (delayBuffer[n2] - delayBuffer[n1])) -
1391 (3 * (delayBuffer[n1] - delayBuffer[n0]))) *
1392 0.25;
1393 const effectsuite_t b = (delayBuffer[n2] - delayBuffer[n1]) - (2 * c * 0.33333);
1394 const effectsuite_t d = (-c) * 0.33333;
1395 return a + (b * alpha) + (c * alpha * alpha) + (d * alpha * alpha * alpha);
1396 }
1397
1398protected: // member vairables
1399 effectsuite_t delayGain = .707;
1400 effectsuite_t feedbackGain = 0.;
1401 effectsuite_t readHeadIndex;
1402 unsigned int writeHeadIndex;
1403 effectsuite_t currentDelaySamples;
1404 effectsuite_t targetDelaySamples;
1407 effectsuite_t delayIncrement;
1410 effectsuite_t invDelayIncrement;
1412 effectsuite_t delayTransitionTime;
1413 effectsuite_t delayTransitionTimeInSamples;
1414 int sampleRate;
1415 int count = 0;
1416 bool delayTimeChanged = false;
1417};
1418
1430public:
1435 SimpleFlanger() = default;
1436 SimpleFlanger(SimpleFlanger&copy) = default;
1437 SimpleFlanger(effectsuite_t extSampleRate=44100)
1438 : DelayEffectBase(static_cast<int>(extSampleRate * 0.02)) {}
1439
1441 ~SimpleFlanger() = default;
1442
1449 void setEffectGain(effectsuite_t gain) { effectGain = capGain(gain); }
1450
1455 void setDepth(const effectsuite_t depth) {
1456 if (depth > effectsuite_t(delayTimeSamples))
1457 modulationDepth = effectsuite_t(delayTimeSamples) - 1;
1458 else
1459 modulationDepth = depth;
1460 }
1461
1466 void setRate(const effectsuite_t rate) {
1467 modulationRate = rate;
1468 setAngleDelta();
1469 }
1470
1477 void setEffectParams(effectsuite_t gain, effectsuite_t depth, effectsuite_t rate) {
1478 setEffectGain(gain);
1479 setDepth(depth);
1480 setRate(rate);
1481 }
1482
1484 effectsuite_t processDouble(effectsuite_t inputSample) override {
1485 delaySample(inputSample);
1486 const effectsuite_t out = ((1 - fabs(effectGain * .2)) * (inputSample) +
1487 (effectGain * getInterpolatedOut(modulationIndex)));
1489 return out;
1490 }
1491
1492 void setupSimpleFlanger(effectsuite_t extSampleRate) {
1493 setupDelayEffectBase(extSampleRate * .02);
1494 timeStep = 1. / extSampleRate;
1495 setEffectParams(.707, extSampleRate * .02, .1);
1496 }
1497
1498 SimpleFlanger* clone() override {
1499 return new SimpleFlanger(*this);
1500 }
1501
1502protected:
1507 effectsuite_t capGain(effectsuite_t gain) {
1508 if (gain > 1.) {
1509 gain = 1.;
1510 } else if (gain < -1.) {
1511 gain = -1.;
1512 }
1513 return gain;
1514 }
1515
1520 const effectsuite_t cyclesPerSample = modulationRate * timeStep;
1521 angleDelta = cyclesPerSample * 2.0f * PI;
1522 }
1523
1528 modulationAngle += angleDelta;
1529 modulationIndex = (currentDelayWriteIndex -
1530 (modulationDepth * (1 + (sin(modulationAngle))))) -
1531 12;
1532 modulationIndex =
1533 ((int(modulationIndex) + delayTimeSamples) % delayTimeSamples) +
1534 (modulationIndex - floor(modulationIndex));
1535 }
1536
1537protected:
1538
1539 effectsuite_t modulationDepth = 1000, modulationRate = 0, effectGain = .01;
1540
1541 effectsuite_t modulationIndex = 0;
1542
1544 effectsuite_t timeStep = 1. / 44100.;
1545
1547 effectsuite_t modulationConstant, modulationAngle = 0;
1548
1549 // const effectsuite_t cyclesPerSample = modulationRate * timeStep;
1551 effectsuite_t angleDelta = 2.0f * PI * timeStep;
1552};
1553
1561public:
1564 // NOTE: Initialising chebyshev coeffcients allocates memory, perhaps alter
1565 // so that memory is already pre allocated
1566 changeChebyICoefficients(.01, false, .1, 4);
1567 envelopeFollower.setChebyICoefficients(.00006, false, 0);
1568 };
1569
1571 ~EnvelopeFilter() = default;
1578 effectsuite_t processDouble(effectsuite_t sample) {
1579 setChebyICoefficients(0.001 + envelopeFollower.envelope(2 * sample), false,
1580 .1); // Offset avoids zero cutoff value
1581 return applyFilter(sample);
1582 }
1583
1584protected:
1590};
1591
1592} // namespace effectsuite_tools
1593
Abstract Base class for Sound Effects.
Definition AudioEffect.h:21
A Base class for delay based digital effects. Provides the basic methods that are shared amongst Flan...
Definition AudioEffectsSuite.h:403
void setDelayBuffReadIndex(effectsuite_t index)
Definition AudioEffectsSuite.h:566
~DelayEffectBase()
Definition AudioEffectsSuite.h:419
void storeSample(effectsuite_t inputSample)
Definition AudioEffectsSuite.h:536
static effectsuite_t ** setInterpolationTable()
Definition AudioEffectsSuite.h:441
void incDelayBuffWriteIndex()
Definition AudioEffectsSuite.h:543
bool error
Definition AudioEffectsSuite.h:627
void setupDelayEffectBase(const int bufferSizeSamples)
Definition AudioEffectsSuite.h:428
int delayTimeSamples
Definition AudioEffectsSuite.h:620
int maxDelayBufferSize
Definition AudioEffectsSuite.h:618
bool setDelayBuffer(int bufferSizeSamples)
Definition AudioEffectsSuite.h:522
effectsuite_t * delayBuffer
Definition AudioEffectsSuite.h:616
effectsuite_t getInterpolatedOut(effectsuite_t bufferIndex)
Definition AudioEffectsSuite.h:590
void delaySample(effectsuite_t inputSample)
Definition AudioEffectsSuite.h:581
void incDelayBuffReadIndex(effectsuite_t indexInc)
Definition AudioEffectsSuite.h:552
Base Class for Effects.
Definition AudioEffectsSuite.h:45
EnvelopeFilter.
Definition AudioEffectsSuite.h:1560
SimpleLPF envelopeFollower
Definition AudioEffectsSuite.h:1589
EnvelopeFilter()
Definition AudioEffectsSuite.h:1563
effectsuite_t processDouble(effectsuite_t sample)
Definition AudioEffectsSuite.h:1578
A Base class for filter based effects including methods for simple high, low and band pass filtering.
Definition AudioEffectsSuite.h:638
effectsuite_t * firCoefficients
Definition AudioEffectsSuite.h:969
effectsuite_t * firTemp
Definition AudioEffectsSuite.h:975
effectsuite_t * iirBuffer
Definition AudioEffectsSuite.h:983
bool setSimpleLpf(int order)
Definition AudioEffectsSuite.h:854
virtual effectsuite_t applyFilter(effectsuite_t sampVal)
Definition AudioEffectsSuite.h:654
effectsuite_t * firBuffer
Definition AudioEffectsSuite.h:980
int bufferIndex
Definition AudioEffectsSuite.h:985
bool changeChebyICoefficients(effectsuite_t cutFreq, bool shelfType, effectsuite_t ripple, int poles)
Definition AudioEffectsSuite.h:840
effectsuite_t envelope(effectsuite_t sample)
Definition AudioEffectsSuite.h:684
bool setChebyICoefficients(effectsuite_t cutFreq, bool shelfType, effectsuite_t ripple)
Definition AudioEffectsSuite.h:713
effectsuite_t * iirTemp
Definition AudioEffectsSuite.h:977
virtual effect_t process(effect_t inputSample) override
see applyFilter
Definition AudioEffectsSuite.h:675
int filterOrder
Definition AudioEffectsSuite.h:987
effectsuite_t * iirCoefficients
Definition AudioEffectsSuite.h:973
FilterEffectBase()
Definition AudioEffectsSuite.h:641
int rmsBufferIndex
Definition AudioEffectsSuite.h:993
const int rmsWindowSize
Definition AudioEffectsSuite.h:991
void allocateBufferMemory()
Definition AudioEffectsSuite.h:906
void clearMemory()
Definition AudioEffectsSuite.h:892
effectsuite_t rms(effectsuite_t sample)
Definition AudioEffectsSuite.h:946
void incBufferIndex()
Definition AudioEffectsSuite.h:883
virtual effectsuite_t processDouble(effectsuite_t inputSample) override
Main process block for applying audio effect.
Definition AudioEffectsSuite.h:670
effectsuite_t * rmsBuffer
Definition AudioEffectsSuite.h:995
Delay effect that filters the repeat delay.
Definition AudioEffectsSuite.h:1171
effectsuite_t processDouble(effectsuite_t inputSample) override
Definition AudioEffectsSuite.h:1208
FilteredDelay(int delayInSamples, int sample_rate=44100)
Definition AudioEffectsSuite.h:1174
effect_t process(effect_t inputSample) override
see applyFilter
Definition AudioEffectsSuite.h:1216
void capGain(effectsuite_t &gain)
Definition AudioEffectsSuite.h:1229
void setDelayGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1190
void setFeedbackGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1202
Class provides a wave table that can be populated with a number of preallocated waveforms....
Definition AudioEffectsSuite.h:74
effectsuite_t readNoise()
Definition AudioEffectsSuite.h:181
void clipWave(effectsuite_t amp)
Definition AudioEffectsSuite.h:193
effectsuite_t tableIndex
Definition AudioEffectsSuite.h:351
void setRamp()
Definition AudioEffectsSuite.h:173
effectsuite_t getInterpOut(effectsuite_t bufferIndex)
Definition AudioEffectsSuite.h:305
void setupModulationBaseClass(effectsuite_t extSampRate)
setup the class with a given sample rate. Basically reperforming the constructor
Definition AudioEffectsSuite.h:96
void setSine()
Definition AudioEffectsSuite.h:143
void setSawtooth()
Definition AudioEffectsSuite.h:132
bool setInterpTable()
Definition AudioEffectsSuite.h:233
void setDC()
Definition AudioEffectsSuite.h:168
void setSquare()
Definition AudioEffectsSuite.h:121
effectsuite_t getSplineOut(effectsuite_t bufferIndex, int freq)
Definition AudioEffectsSuite.h:332
effectsuite_t * waveTable
Definition AudioEffectsSuite.h:357
effectsuite_t timeStep
Definition AudioEffectsSuite.h:355
bool allocateMemory()
Definition AudioEffectsSuite.h:290
int sampleRate
Definition AudioEffectsSuite.h:353
effectsuite_t readTable(effectsuite_t freq)
Definition AudioEffectsSuite.h:208
void setOffSine()
Definition AudioEffectsSuite.h:151
ModulationBaseClass()
Definition AudioEffectsSuite.h:77
void setTriangle()
Definition AudioEffectsSuite.h:108
Simple Chorus effect with a single delay voice and mono output Chorus is effective between 15 and 20 ...
Definition AudioEffectsSuite.h:1038
effectsuite_t base
Definition AudioEffectsSuite.h:1115
void setBase(effectsuite_t baseAmount)
Definition AudioEffectsSuite.h:1103
void setupChorus(effectsuite_t extSampleRate)
Definition AudioEffectsSuite.h:1081
void setSwing(effectsuite_t swingAmount)
Definition AudioEffectsSuite.h:1097
effectsuite_t modMax
Definition AudioEffectsSuite.h:1119
effectsuite_t swing
Definition AudioEffectsSuite.h:1113
effectsuite_t getModSignal()
Definition AudioEffectsSuite.h:1129
SimpleChorus(int extSampleRate=44100)
Definition AudioEffectsSuite.h:1046
virtual effectsuite_t processDouble(effectsuite_t inputSample) override
Definition AudioEffectsSuite.h:1065
effectsuite_t modNorm
Definition AudioEffectsSuite.h:1121
effectsuite_t modMin
Definition AudioEffectsSuite.h:1117
Simple Delay effect consiting of a single tap delay with Effect Gain and feed back controls Construct...
Definition AudioEffectsSuite.h:1251
effectsuite_t processDouble(effectsuite_t inputSample) override
Definition AudioEffectsSuite.h:1300
effectsuite_t getSplineOut(effectsuite_t bufferIndex)
Definition AudioEffectsSuite.h:1383
void setDelayTransitionTime(effectsuite_t seconds)
Definition AudioEffectsSuite.h:1353
void setDelayTime(effectsuite_t delayInSamples)
Definition AudioEffectsSuite.h:1342
void setupSimpleDelay(int delayInSamples)
Definition AudioEffectsSuite.h:1335
effectsuite_t delayIncrement
Definition AudioEffectsSuite.h:1407
SimpleDelay(int maxDelayInSamples=8810, int samplingRate=44100)
Definition AudioEffectsSuite.h:1258
effect_t process(effect_t inputSample) override
Definition AudioEffectsSuite.h:1327
effectsuite_t delayTransitionTime
Definition AudioEffectsSuite.h:1412
void capGain(effectsuite_t &gain)
Definition AudioEffectsSuite.h:1367
void setDelayGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1278
void setFeedbackGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1290
effectsuite_t invDelayIncrement
Definition AudioEffectsSuite.h:1410
Simple Flanger Effect Consistig of a single voice flanger The flanger has an effective range between ...
Definition AudioEffectsSuite.h:1429
void updateModulation()
Definition AudioEffectsSuite.h:1527
effectsuite_t processDouble(effectsuite_t inputSample) override
Definition AudioEffectsSuite.h:1484
effectsuite_t modulationConstant
Definition AudioEffectsSuite.h:1547
void setRate(const effectsuite_t rate)
Definition AudioEffectsSuite.h:1466
void setEffectGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1449
effectsuite_t capGain(effectsuite_t gain)
Definition AudioEffectsSuite.h:1507
void setEffectParams(effectsuite_t gain, effectsuite_t depth, effectsuite_t rate)
Definition AudioEffectsSuite.h:1477
void setDepth(const effectsuite_t depth)
Definition AudioEffectsSuite.h:1455
effectsuite_t angleDelta
Definition AudioEffectsSuite.h:1551
effectsuite_t timeStep
Definition AudioEffectsSuite.h:1544
void setAngleDelta()
Definition AudioEffectsSuite.h:1519
SimpleLPF.
Definition AudioEffectsSuite.h:1005
SimpleLPF(effectsuite_t cutoff, int order)
Definition AudioEffectsSuite.h:1013
Base class to define the abstract interface for the sound generating classes.
Definition SoundGenerator.h:28
SoundGenerator using the ModulationBaseClass to generate the samples.
Definition AudioEffectsSuite.h:373
virtual T readSample() override
Provides a single sample.
Definition AudioEffectsSuite.h:383
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
static effectsuite_t ** interpolationTable
Table of interpolation values as a 2D array indexed by interpolationTable[pointIndex][alphaIndex].
Definition AudioEffectsSuite.h:38
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59