arduino-audio-tools
Loading...
Searching...
No Matches
AudioFFT.h
Go to the documentation of this file.
1#pragma once
2
6
12
13namespace audio_tools {
14
15// forward declaration
16class AudioFFTBase;
18
24 int bin = 0;
25 float magnitude = 0.0f;
26 float frequency = 0.0f;
27
28 int frequencyAsInt() { return round(frequency); }
29 const char *frequencyAsNote() { return AudioFFTNotes.note(frequency); }
30 const char *frequencyAsNote(float &diff) {
31 return AudioFFTNotes.note(frequency, diff);
32 }
33};
34
45struct AudioFFTConfig : public AudioInfo {
47 channels = 2;
48 bits_per_sample = 16;
49 sample_rate = 44100;
50 }
51
52 void (*callback)(AudioFFTBase &fft) = nullptr;
54 uint8_t channel_used = 0;
55 int length = 8192;
56 int stride = 0;
66 void *ref = nullptr;
67};
68
70struct FFTBin {
71 float real;
72 float img;
73
74 FFTBin() = default;
75
76 FFTBin(float r, float i) {
77 real = r;
78 img = i;
79 }
80
81 void multiply(float f) {
82 real *= f;
83 img *= f;
84 }
85
86 void conjugate() { img = -img; }
87
88 void clear() { real = img = 0.0f; }
89};
90
93 public:
95 if (size > 0) resize(size);
96 }
97
99 bool resize(size_t size) {
100 // reset max for new scaling
101 rfft_max = 0.0;
102 // define new size
103 len = size;
104 // Vector::resize() also returns false if the size did not change (e.g.
105 // resize(0) from end() when the inverse FFT was never used)
106 data.resize(size);
107 if (size > 0 && data.data() == nullptr) {
108 LOGE("Could not resize data");
109 return false;
110 }
111 for (int j = 0; j < data.size(); j++) {
112 data[j] = 0.0;
113 }
114 return true;
115 }
116
117 // adds the values to the array (by applying the window function)
118 void add(float value, int pos, WindowFunction *window_function) {
119 float add_value = value;
120 if (window_function != nullptr) {
121 add_value = value * window_function->factor(pos);
122 }
123 assert(pos < len);
124 data[pos] += add_value;
125 }
126
127 // gets the scaled audio data as result
128 void getStepData(float *result, int stride, float maxResult) {
129 for (int j = 0; j < stride; j++) {
130 // determine max value to scale
131 if (data[j] > rfft_max) rfft_max = data[j];
132 }
133 for (int j = 0; j < stride; j++) {
134 result[j] = data[j] / rfft_max * maxResult;
135 // clip
136 if (result[j] > maxResult) {
137 result[j] = maxResult;
138 }
139 if (result[j] < -maxResult) {
140 result[j] = -maxResult;
141 }
142 }
143 // copy data to head
144 for (int j = 0; j < len - stride; j++) {
145 data[j] = data[j + stride];
146 }
147 // clear tail
148 for (int j = len - stride; j < len; j++) {
149 data[j] = 0.0;
150 }
151 }
152
154 int size() { return data.size(); }
155
156 protected:
158 int len = 0;
159 float rfft_max = 0;
160};
161
169 public:
170 virtual ~FFTDriver() = default;
171 virtual bool begin(int len) = 0;
172 virtual void end() = 0;
174 virtual void setValue(int pos, float value) = 0;
176 virtual void fft() = 0;
178 virtual float magnitude(int idx) = 0;
180 virtual float magnitudeFast(int idx) = 0;
181 virtual bool isValid() = 0;
183 virtual bool isReverseFFT() { return false; }
185 virtual void rfft() { LOGE("Not implemented"); }
187 virtual float getValue(int pos) = 0;
189 virtual bool setBin(int idx, float real, float img) { return false; }
191 bool setBin(int pos, FFTBin &bin) { return setBin(pos, bin.real, bin.img); }
193 virtual bool getBin(int pos, FFTBin &bin) { return false; }
194};
195
204class AudioFFTBase : public AudioStream {
205 public:
211 AudioFFTBase(const AudioFFTBase &) = delete;
213
215 end();
216 delete p_driver;
217 }
218
222 info.rxtx_mode = mode;
223 return info;
224 }
225
228 cfg = info;
229 return begin();
230 }
231
233 bool begin() override {
234 bins = cfg.length / 2;
235 // define window functions
236 if (cfg.window_function_fft == nullptr)
237 cfg.window_function_fft = cfg.window_function;
238 if (cfg.window_function_ifft == nullptr)
239 cfg.window_function_ifft = cfg.window_function;
240 // define default stride value if not defined
241 if (cfg.stride == 0) cfg.stride = cfg.length;
242
243 if (!isPowerOfTwo(cfg.length)) {
244 LOGE("Len must be of the power of 2: %d", cfg.length);
245 return false;
246 }
247 if (!p_driver->begin(cfg.length)) {
248 LOGE("Not enough memory");
249 }
250
251 if (cfg.window_function_fft != nullptr) {
252 cfg.window_function_fft->begin(cfg.length);
253 }
254 if (cfg.window_function_ifft != nullptr &&
255 cfg.window_function_ifft != cfg.window_function_fft) {
256 cfg.window_function_ifft->begin(cfg.length);
257 }
258
259 bool is_valid_rxtx = false;
260 if (cfg.rxtx_mode == TX_MODE || cfg.rxtx_mode == RXTX_MODE) {
261 // holds last N bytes that need to be reprocessed
262 stride_buffer.resize((cfg.length) * bytesPerSample());
263 is_valid_rxtx = true;
264 }
265 if (cfg.rxtx_mode == RX_MODE || cfg.rxtx_mode == RXTX_MODE) {
266 rfft_data.resize(cfg.channels * bytesPerSample() * cfg.stride);
267 rfft_add.resize(cfg.length);
268 step_data.resize(cfg.stride);
269 is_valid_rxtx = true;
270 }
271
272 if (!is_valid_rxtx) {
273 LOGE("Invalid rxtx_mode");
274 return false;
275 }
276
277 current_pos = 0;
278 return p_driver->isValid();
279 }
280
282 void reset() {
283 current_pos = 0;
284 // drop partially collected input so the next frame starts from scratch
285 stride_buffer.reset();
286 if (cfg.window_function_fft != nullptr) {
287 cfg.window_function_fft->begin(cfg.length);
288 }
289 if (cfg.window_function_ifft != nullptr) {
290 cfg.window_function_ifft->begin(cfg.length);
291 }
292 }
293
294 operator bool() override {
295 return p_driver != nullptr && p_driver->isValid();
296 }
297
299 void setAudioInfo(AudioInfo info) override {
300 cfg.bits_per_sample = info.bits_per_sample;
301 cfg.sample_rate = info.sample_rate;
302 cfg.channels = info.channels;
303 begin(cfg);
304 }
305
307 void end() override {
308 p_driver->end();
309 l_magnitudes.resize(0);
310 rfft_data.resize(0);
311 rfft_add.resize(0);
312 step_data.resize(0);
313 mel_filters.resize(0);
314 mel_weights.resize(0);
315 mel_n_bins = 0;
316 }
317
319 size_t write(const uint8_t *data, size_t len) override {
320 if (!p_driver->isValid()) return 0;
321 // only complete frames are consumed: a partial frame at the end is
322 // reported as not written (the caller sends it again with the rest)
323 int frame_bytes = bytesPerSample() * cfg.channels;
324 size_t samples = frame_bytes > 0 ? len / frame_bytes * cfg.channels : 0;
325 switch (cfg.bits_per_sample) {
326 case 8:
327 processSamples<int8_t>(data, samples);
328 break;
329 case 16:
330 processSamples<int16_t>(data, samples);
331 break;
332 case 24:
333 processSamples<int24_t>(data, samples);
334 break;
335 case 32:
336 processSamples<int32_t>(data, samples);
337 break;
338 default:
339 LOGE("Unsupported bits_per_sample: %d", cfg.bits_per_sample);
340 return 0;
341 }
342 return samples * bytesPerSample();
343 }
344
346 size_t readBytes(uint8_t *data, size_t len) override {
347 TRACED();
348 if (rfft_data.size() == 0) return 0;
349
350 // get data via callback if there is no more data
351 if (cfg.rxtx_mode == RX_MODE && cfg.callback != nullptr &&
352 rfft_data.available() == 0) {
353 cfg.callback(*this);
354 }
355
356 // execute rfft when we consumed all data
357 if (has_rfft_data && rfft_data.available() == 0) {
358 rfft();
359 }
360 return rfft_data.readArray(data, len);
361 }
362
364 int availableForWrite() override {
365 return cfg.length * cfg.channels * bytesPerSample();
366 }
367
369 int available() override {
370 assert(cfg.stride != 0);
371 return cfg.stride * cfg.channels * bytesPerSample();
372 }
373
375 int size() { return bins; }
376
378 int length() { return cfg.length; }
379
382 unsigned long resultTime() { return timestamp; }
384 unsigned long resultTimeBegin() { return timestamp_begin; }
385
388 AudioFFTResult ret_value;
389 ret_value.magnitude = 0.0f;
390 ret_value.bin = 0;
391 // find max value and index
392 for (int j = 0; j < size(); j++) {
393 float m = magnitude(j);
394 if (m > ret_value.magnitude) {
395 ret_value.magnitude = m;
396 ret_value.bin = j;
397 }
398 }
399 ret_value.frequency = frequency(ret_value.bin);
400 return ret_value;
401 }
402
404 template <int N>
406 // initialize to negative value
407 for (int j = 0; j < N; j++) {
408 result[j].magnitude = -1000000;
409 }
410 // find top n values
411 AudioFFTResult act;
412 for (int j = 0; j < size(); j++) {
413 act.magnitude = magnitude(j);
414 act.bin = j;
415 act.frequency = frequency(j);
417 }
418 }
419
427 float *toMEL(int n_bins, float min_freq = 0.0f, float max_freq = 0.0f,
428 bool power = false) {
429 if (n_bins <= 0) n_bins = size();
430 if (!updateMelFilterbank(n_bins, min_freq, max_freq)) return nullptr;
431 mel_bins.resize(n_bins);
432 // one pass over the bins (each bin belongs to up to two filters)
433 const float *mags = power ? magnitudesFast() : magnitudes();
434 for (int i = 0; i < n_bins; i++) {
435 const MelFilter &filter = mel_filters[i];
436 const float *weights = mel_weights.data() + filter.weight_offset;
437 const float *m = mags + filter.start_bin;
438 float mel_sum = 0.0f;
439 for (int j = 0; j < filter.count; j++) mel_sum += m[j] * weights[j];
440 mel_bins[i] = mel_sum;
441 }
442 return mel_bins.data();
443 }
444
453 bool fromMEL(float *values, int n_bins, float min_freq = 0.0f,
454 float max_freq = 0.0f) {
455 if (n_bins <= 0 || values == nullptr) return false;
456 if (!updateMelFilterbank(n_bins, min_freq, max_freq)) return false;
457
458 // Distribute MEL energy back to linear frequency bins
459 Vector<float> linear_magnitudes;
460 linear_magnitudes.resize(bins);
461 for (int i = 0; i < bins; i++) linear_magnitudes[i] = 0.0f;
462 for (int i = 0; i < n_bins; i++) {
463 const MelFilter &filter = mel_filters[i];
464 const float *weights = mel_weights.data() + filter.weight_offset;
465 for (int j = 0; j < filter.count; j++) {
466 linear_magnitudes[filter.start_bin + j] += values[i] * weights[j];
467 }
468 }
469
470 // Set magnitude values and create simple phase (all zeros)
471 for (int i = 0; i < bins; i++) {
472 FFTBin bin;
473 bin.clear();
474 bin.real = linear_magnitudes[i];
475 setBin(i, bin);
476 }
477 return true;
478 }
479
482 FFTDriver *driver() { return p_driver; }
483
485 float frequency(int bin) {
486 if (bin >= bins) {
487 LOGE("Invalid bin %d", bin);
488 return 0;
489 }
490 return static_cast<float>(bin) * cfg.sample_rate / cfg.length;
491 }
492
494 int frequencyToBin(int freq) {
495 int max_freq = cfg.sample_rate / 2;
496 return map(freq, 0, max_freq, 0, size());
497 }
498
501 float magnitude(int bin) {
502 if (bin >= bins) {
503 LOGE("Invalid bin %d", bin);
504 return 0;
505 }
506 return p_driver->magnitude(bin);
507 }
508
509 float magnitudeFast(int bin) {
510 if (bin >= bins) {
511 LOGE("Invalid bin %d", bin);
512 return 0;
513 }
514 return p_driver->magnitudeFast(bin);
515 }
516
518 float phase(int bin) {
519 FFTBin fft_bin;
520 getBin(bin, fft_bin);
521 return atan2(fft_bin.img, fft_bin.real);
522 }
523
526 float *magnitudes() {
527 // the FFT length may have changed with a new begin()
528 if (l_magnitudes.size() != size()) {
529 l_magnitudes.resize(size());
530 }
531 for (int j = 0; j < size(); j++) {
532 l_magnitudes[j] = magnitude(j);
533 }
534 return l_magnitudes.data();
535 }
536
539 float *magnitudesFast() {
540 // the FFT length may have changed with a new begin()
541 if (l_magnitudes.size() != size()) {
542 l_magnitudes.resize(size());
543 }
544 for (int j = 0; j < size(); j++) {
546 }
547 return l_magnitudes.data();
548 }
549
551 bool setBin(int idx, float real, float img) {
552 has_rfft_data = true;
553 if (idx < 0 || idx >= size()) return false;
554 bool rc_first_half = p_driver->setBin(idx, real, img);
555 bool rc_2nd_half = p_driver->setBin(cfg.length - idx, real, img);
556 return rc_first_half && rc_2nd_half;
557 }
558
559 bool setBin(int pos, FFTBin &bin) { return setBin(pos, bin.real, bin.img); }
561 bool getBin(int pos, FFTBin &bin) { return p_driver->getBin(pos, bin); }
562
564 void clearBins() {
565 FFTBin empty{0, 0};
566 for (int j = 0; j < size(); j++) {
567 setBin(j, empty);
568 }
569 }
570
572 AudioFFTConfig &config() { return cfg; }
573
575 template <typename T>
577 return *((T*)cfg.ref);
578 }
579
580 protected:
581 FFTDriver *p_driver = nullptr;
582 int current_pos = 0;
583 int bins = 0;
584 unsigned long timestamp_begin = 0l;
585 unsigned long timestamp = 0l;
592 struct MelFilter {
593 int start_bin = 0;
594 int count = 0;
596 };
599 int mel_n_bins = 0;
600 float mel_min_freq = -1.0f;
601 float mel_max_freq = -1.0f;
602 int mel_length = 0;
604
605 static float hzToMel(float hz) { return 2595.0f * log10f(1.0f + hz / 700.0f); }
606 static float melToHz(float mel) {
607 return 700.0f * (powf(10.0f, mel / 2595.0f) - 1.0f);
608 }
609
611 bool updateMelFilterbank(int n_bins, float min_freq, float max_freq) {
612 if (bins <= 0 || cfg.sample_rate <= 0) return false;
613 if (min_freq <= 0.0f) min_freq = frequency(0);
614 if (max_freq <= 0.0f) max_freq = frequency(size() - 1);
615 if (n_bins == mel_n_bins && min_freq == mel_min_freq &&
616 max_freq == mel_max_freq && cfg.length == mel_length &&
617 (int)cfg.sample_rate == mel_sample_rate)
618 return true;
619
620 float min_mel = hzToMel(min_freq);
621 float mel_step = (hzToMel(max_freq) - min_mel) / (n_bins + 1);
622 float bin_hz = (float)cfg.sample_rate / cfg.length;
623
624 // band edges (n_bins + 2 points) and the bin range of every filter
625 Vector<float> edges;
626 edges.resize(n_bins + 2);
627 for (int i = 0; i < n_bins + 2; i++) edges[i] = melToHz(min_mel + i * mel_step);
628 mel_filters.resize(n_bins);
629 int total = 0;
630 for (int i = 0; i < n_bins; i++) {
631 MelFilter &filter = mel_filters[i];
632 // bins strictly inside (left, right)
633 int first = (int)(edges[i] / bin_hz) + 1;
634 int last = (int)ceilf(edges[i + 2] / bin_hz) - 1;
635 if (last >= bins) last = bins - 1;
636 if (first <= last) {
637 filter.start_bin = first;
638 filter.count = last - first + 1;
639 } else {
640 // narrower than one FFT bin: use the bin closest to the center so
641 // the band still carries energy instead of being constant zero
642 int j = (int)(edges[i + 1] / bin_hz + 0.5f);
643 filter.start_bin = j >= bins ? bins - 1 : j;
644 filter.count = 0;
645 }
646 filter.weight_offset = total;
647 total += filter.count > 0 ? filter.count : 1;
648 }
649 // one allocation for all weights
650 mel_weights.resize(total);
651 for (int i = 0; i < n_bins; i++) {
652 MelFilter &filter = mel_filters[i];
653 float *w = mel_weights.data() + filter.weight_offset;
654 if (filter.count == 0) {
655 w[0] = 1.0f;
656 filter.count = 1;
657 continue;
658 }
659 float left = edges[i], center = edges[i + 1], right = edges[i + 2];
660 for (int k = 0; k < filter.count; k++) {
661 float f = (filter.start_bin + k) * bin_hz;
662 w[k] = f <= center ? (f - left) / (center - left) : (right - f) / (right - center);
663 }
664 }
665 mel_n_bins = n_bins;
666 mel_min_freq = min_freq;
667 mel_max_freq = max_freq;
668 mel_length = cfg.length;
669 mel_sample_rate = cfg.sample_rate;
670 return true;
671 }
674 bool has_rfft_data = false;
675
676 // Add samples to input data p_x - and process them if full
677 template <typename T>
678 void processSamples(const void *data, size_t count) {
679 T *dataT = (T *)data;
680 if (cfg.channels == 1) {
681 // mono: copy contiguous runs instead of one sample per call
682 size_t pos = 0;
683 while (pos < count) {
684 size_t room = stride_buffer.availableForWrite() / sizeof(T);
685 size_t n = count - pos < room ? count - pos : room;
686 stride_buffer.writeArray((uint8_t *)(dataT + pos), n * sizeof(T));
687 pos += n;
689 }
690 return;
691 }
692 T sample;
693 for (int j = 0; j < count; j += cfg.channels) {
694 sample = dataT[j + cfg.channel_used];
695 if (writeStrideBuffer((uint8_t *)&sample, sizeof(T))) processStrideBuffer<T>();
696 }
697 }
698
700 template <typename T>
702 T *samples = (T *)stride_buffer.data();
703 int sample_count = stride_buffer.size() / sizeof(T);
704 assert(sample_count == cfg.length);
705 const float scale = 1.0f / NumberConverter::maxValueT<T>();
706 for (int j = 0; j < sample_count; j++) {
707 T windowed_sample = windowedSample(samples[j], j);
708 p_driver->setValue(j, scale * windowed_sample);
709 }
710
711 fft<T>();
712
713 // remove stride samples
714 stride_buffer.clearArray(cfg.stride * sizeof(T));
715
716 // validate available data in stride buffer
717 if (cfg.stride == cfg.length) assert(stride_buffer.available() == 0);
718 }
719
720
721 template <typename T>
722 T windowedSample(T sample, int pos) {
723 T result = sample;
724 if (cfg.window_function_fft != nullptr) {
725 result = cfg.window_function_fft->factor(pos) * sample;
726 }
727 return result;
728 }
729
730 template <typename T>
731 void fft() {
733 p_driver->fft();
734 has_rfft_data = true;
735 timestamp = millis();
736 if (cfg.callback != nullptr) {
737 cfg.callback(*this);
738 }
739 }
740
742 void rfft() {
743 TRACED();
744 // execute reverse fft
745 p_driver->rfft();
746 has_rfft_data = false;
747 // add data to sum buffer
748 for (int j = 0; j < cfg.length; j++) {
749 float value = p_driver->getValue(j);
750 rfft_add.add(value, j, cfg.window_function_ifft);
751 }
752 // get result data from sum buffer
754 }
755
758 // get data to result buffer
759 // for (int j = 0; j < cfg.stride; j++) {
760 // step_data[j] = 0.0;
761 // }
762 rfft_add.getStepData(step_data.data(), cfg.stride,
763 NumberConverter::maxValue(cfg.bits_per_sample));
764
765 switch (cfg.bits_per_sample) {
766 case 8:
767 writeIFFT<int8_t>(step_data.data(), cfg.stride);
768 break;
769 case 16:
770 writeIFFT<int16_t>(step_data.data(), cfg.stride);
771 break;
772 case 24:
773 writeIFFT<int24_t>(step_data.data(), cfg.stride);
774 break;
775 case 32:
776 writeIFFT<int32_t>(step_data.data(), cfg.stride);
777 break;
778 default:
779 LOGE("Unsupported bits: %d", cfg.bits_per_sample);
780 }
781 }
782
783 template <typename T>
784 void writeIFFT(float *data, int len) {
785 for (int j = 0; j < len; j++) {
786 T sample = data[j];
787 T out_data[cfg.channels];
788 for (int ch = 0; ch < cfg.channels; ch++) {
789 out_data[ch] = sample;
790 }
791 int result = rfft_data.writeArray((uint8_t *)out_data, sizeof(out_data));
792 assert(result == sizeof(out_data));
793 }
794 }
795
798 inline int bytesPerSample() {
799 return cfg.bits_per_sample == 24 ? (int)sizeof(int24_t) : cfg.bits_per_sample / 8;
800 }
801
803 template <int N>
805 // find place where we need to insert new record
806 for (int j = 0; j < N; j++) {
807 // insert when biggen then current record
808 if (tmp.magnitude > result[j].magnitude) {
809 // shift existing values right
810 for (int i = N - 2; i >= j; i--) {
811 result[i + 1] = result[i];
812 }
813 // insert new value
814 result[j] = tmp;
815 // stop after we found the correct index
816 break;
817 }
818 }
819 }
820
821 // adds samples to stride buffer, returns true if the buffer is full
822 bool writeStrideBuffer(uint8_t *buffer, size_t len) {
823 assert(stride_buffer.availableForWrite() >= len);
824 stride_buffer.writeArray(buffer, len);
825 return stride_buffer.isFull();
826 }
827
828 bool isPowerOfTwo(uint16_t x) { return (x & (x - 1)) == 0; }
829};
830
831} // namespace audio_tools
#define TRACED()
#define assert(T)
#define LOGE(...)
Different Window functions that can be used by FFT.
Executes FFT using audio data privded by write() and/or an inverse FFT where the samples are made ava...
Definition AudioFFT.h:204
unsigned long resultTimeBegin()
time before the fft
Definition AudioFFT.h:384
unsigned long timestamp_begin
Definition AudioFFT.h:584
void clearBins()
clears the fft data
Definition AudioFFT.h:564
Vector< MelFilter > mel_filters
Definition AudioFFT.h:597
static float hzToMel(float hz)
Definition AudioFFT.h:605
float magnitude(int bin)
Definition AudioFFT.h:501
T windowedSample(T sample, int pos)
Definition AudioFFT.h:722
float * magnitudesFast()
Definition AudioFFT.h:539
unsigned long resultTime()
Definition AudioFFT.h:382
bool writeStrideBuffer(uint8_t *buffer, size_t len)
Definition AudioFFT.h:822
int mel_n_bins
Definition AudioFFT.h:599
int mel_length
Definition AudioFFT.h:602
int length()
The number of samples.
Definition AudioFFT.h:378
static float melToHz(float mel)
Definition AudioFFT.h:606
void fft()
Definition AudioFFT.h:731
void processStrideBuffer()
FFT of the full stride buffer, then drop stride samples.
Definition AudioFFT.h:701
FFTDriver * p_driver
Definition AudioFFT.h:581
size_t readBytes(uint8_t *data, size_t len) override
Provides the result of a reverse FFT.
Definition AudioFFT.h:346
RingBuffer< uint8_t > rfft_data
Definition AudioFFT.h:673
bool updateMelFilterbank(int n_bins, float min_freq, float max_freq)
(Re)builds the cached sparse filterbank if any parameter changed
Definition AudioFFT.h:611
void writeIFFT(float *data, int len)
Definition AudioFFT.h:784
AudioFFTBase(const AudioFFTBase &)=delete
void end() override
Release the allocated memory.
Definition AudioFFT.h:307
bool has_rfft_data
Definition AudioFFT.h:674
int available() override
Data available for reverse fft.
Definition AudioFFT.h:369
AudioFFTBase(FFTDriver *driver)
Definition AudioFFT.h:210
AudioFFTConfig & config()
Provides the actual configuration.
Definition AudioFFT.h:572
size_t write(const uint8_t *data, size_t len) override
Provide the audio data as FFT input.
Definition AudioFFT.h:319
bool isPowerOfTwo(uint16_t x)
Definition AudioFFT.h:828
FFTDriver * driver()
Definition AudioFFT.h:482
~AudioFFTBase()
Definition AudioFFT.h:214
int frequencyToBin(int freq)
Determine the bin number from the frequency.
Definition AudioFFT.h:494
bool setBin(int idx, float real, float img)
sets the value of a bin
Definition AudioFFT.h:551
int bytesPerSample()
Definition AudioFFT.h:798
int availableForWrite() override
We try to fill the buffer at once.
Definition AudioFFT.h:364
float phase(int bin)
calculates the phase
Definition AudioFFT.h:518
Vector< float > step_data
Definition AudioFFT.h:589
AudioFFTConfig defaultConfig(RxTxMode mode=TX_MODE)
Provides the default configuration.
Definition AudioFFT.h:220
SingleBuffer< uint8_t > stride_buffer
Definition AudioFFT.h:672
T & reference()
Provides the reference pointer.
Definition AudioFFT.h:576
bool fromMEL(float *values, int n_bins, float min_freq=0.0f, float max_freq=0.0f)
Convert MEL spectrum back to linear frequency spectrum, using the same (cached) filterbank as toMEL()...
Definition AudioFFT.h:453
bool begin(AudioFFTConfig info)
starts the processing
Definition AudioFFT.h:227
float * magnitudes()
Definition AudioFFT.h:526
float * toMEL(int n_bins, float min_freq=0.0f, float max_freq=0.0f, bool power=false)
Definition AudioFFT.h:427
int mel_sample_rate
Definition AudioFFT.h:603
bool getBin(int pos, FFTBin &bin)
gets the value of a bin
Definition AudioFFT.h:561
FFTInverseOverlapAdder rfft_add
Definition AudioFFT.h:587
AudioFFTResult result()
Determines the result values in the max magnitude bin.
Definition AudioFFT.h:387
float frequency(int bin)
Determines the frequency of the indicated bin.
Definition AudioFFT.h:485
int current_pos
Definition AudioFFT.h:582
AudioFFTBase & operator=(const AudioFFTBase &)=delete
Vector< float > mel_weights
Definition AudioFFT.h:598
void rfft()
reverse fft
Definition AudioFFT.h:742
bool setBin(int pos, FFTBin &bin)
sets the value of a bin
Definition AudioFFT.h:559
AudioFFTConfig cfg
Definition AudioFFT.h:586
void insertSorted(AudioFFTResult(&result)[N], AudioFFTResult tmp)
make sure that we do not reuse already found results
Definition AudioFFT.h:804
bool begin() override
starts the processing
Definition AudioFFT.h:233
unsigned long timestamp
Definition AudioFFT.h:585
void setAudioInfo(AudioInfo info) override
Notify change of audio information.
Definition AudioFFT.h:299
void reset()
Just resets the current_pos e.g. to start a new cycle.
Definition AudioFFT.h:282
void processSamples(const void *data, size_t count)
Definition AudioFFT.h:678
float magnitudeFast(int bin)
Definition AudioFFT.h:509
Vector< float > mel_bins
Definition AudioFFT.h:590
void resultArray(AudioFFTResult(&result)[N])
Determines the N biggest result values.
Definition AudioFFT.h:405
float mel_min_freq
Definition AudioFFT.h:600
int size()
The number of bins used by the FFT which are relevant for the result.
Definition AudioFFT.h:375
int bins
Definition AudioFFT.h:583
Vector< float > l_magnitudes
Definition AudioFFT.h:588
void rfftWriteData(BaseBuffer< uint8_t > &data)
write reverse fft result to buffer to make it available for readBytes
Definition AudioFFT.h:757
float mel_max_freq
Definition AudioFFT.h:601
Shared functionality of all buffers.
Definition Buffers.h:23
Abstract Class which defines the basic FFT functionality.
Definition AudioFFT.h:168
virtual float magnitude(int idx)=0
Calculate the magnitude (fft result) at index (sqr(i² + r²)).
virtual bool isValid()=0
virtual bool setBin(int idx, float real, float img)
sets the value of a bin
Definition AudioFFT.h:189
virtual void fft()=0
Perform FFT.
virtual float magnitudeFast(int idx)=0
Calculate the magnitude w/o sqare root.
virtual bool isReverseFFT()
Returns true if reverse FFT is supported.
Definition AudioFFT.h:183
virtual void end()=0
virtual void rfft()
Calculate reverse FFT.
Definition AudioFFT.h:185
bool setBin(int pos, FFTBin &bin)
sets the value of a bin
Definition AudioFFT.h:191
virtual ~FFTDriver()=default
virtual void setValue(int pos, float value)=0
Sets the real value.
virtual bool getBin(int pos, FFTBin &bin)
gets the value of a bin
Definition AudioFFT.h:193
virtual float getValue(int pos)=0
Get result value from Reverse FFT.
virtual bool begin(int len)=0
Inverse FFT Overlapp Add.
Definition AudioFFT.h:92
void getStepData(float *result, int stride, float maxResult)
Definition AudioFFT.h:128
Vector< float > data
Definition AudioFFT.h:157
float rfft_max
Definition AudioFFT.h:159
FFTInverseOverlapAdder(int size=0)
Definition AudioFFT.h:94
void add(float value, int pos, WindowFunction *window_function)
Definition AudioFFT.h:118
bool resize(size_t size)
Initilze data by defining new size.
Definition AudioFFT.h:99
int size()
provides the actual size
Definition AudioFFT.h:154
int len
Definition AudioFFT.h:158
Determination of the frequency of a music note.
Definition MusicalNotes.h:125
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:303
static float maxValueT()
provides the biggest number for the indicated type
Definition AudioTypes.h:319
Implements a typed Ringbuffer.
Definition Buffers.h:363
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:194
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
FFT Window Function.
Definition FFTWindows.h:28
float factor(int idx)
Definition FFTWindows.h:41
AudioInfo info
Definition CodecOpusOgg.h:171
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:26
@ RXTX_MODE
Definition AudioTypes.h:26
@ TX_MODE
Definition AudioTypes.h:26
@ RX_MODE
Definition AudioTypes.h:26
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
int24_4bytes_t int24_t
Definition int24_t.h:12
static MusicalNotes AudioFFTNotes
Definition AudioFFT.h:17
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition CodecOpusOgg.h:183
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
One triangular mel filter: weights for bins [start_bin, start_bin+count).
Definition AudioFFT.h:592
int weight_offset
Definition AudioFFT.h:595
int count
Definition AudioFFT.h:594
int start_bin
Definition AudioFFT.h:593
Configuration for AudioFFT. If there are more then 1 channel the channel_used is defining which chann...
Definition AudioFFT.h:45
int stride
Definition AudioFFT.h:56
void * ref
caller
Definition AudioFFT.h:66
WindowFunction * window_function_ifft
Optional window function for ifft only.
Definition AudioFFT.h:62
uint8_t channel_used
Channel which is used as input.
Definition AudioFFT.h:54
WindowFunction * window_function_fft
Optional window function for fft only.
Definition AudioFFT.h:60
WindowFunction * window_function
Optional window function for both fft and ifft.
Definition AudioFFT.h:58
int length
Definition AudioFFT.h:55
void(* callback)(AudioFFTBase &fft)
Callback method which is called after we got a new result.
Definition AudioFFT.h:52
AudioFFTConfig()
Definition AudioFFT.h:46
RxTxMode rxtx_mode
TX_MODE = FFT, RX_MODE = IFFT.
Definition AudioFFT.h:64
Result of the FFT.
Definition AudioFFT.h:23
const char * frequencyAsNote(float &diff)
Definition AudioFFT.h:30
const char * frequencyAsNote()
Definition AudioFFT.h:29
int frequencyAsInt()
Definition AudioFFT.h:28
float magnitude
Definition AudioFFT.h:25
int bin
Definition AudioFFT.h:24
float frequency
Definition AudioFFT.h:26
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
And individual FFT Bin.
Definition AudioFFT.h:70
float real
Definition AudioFFT.h:71
float img
Definition AudioFFT.h:72
void conjugate()
Definition AudioFFT.h:86
FFTBin(float r, float i)
Definition AudioFFT.h:76
void clear()
Definition AudioFFT.h:88
void multiply(float f)
Definition AudioFFT.h:81
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition CodecOpusOgg.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition CodecOpusOgg.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits).
Definition CodecOpusOgg.h:62
AudioInfo()=default
Default constructor.