arduino-audio-tools
Loading...
Searching...
No Matches
AudioFFT.h
Go to the documentation of this file.
1#pragma once
2
6
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 }
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 if (!data.resize(size)) {
105 LOGE("Could not resize data");
106 return false;
107 }
108 for (int j = 0; j < data.size(); j++) {
109 data[j] = 0.0;
110 }
111 return true;
112 }
113
114 // adds the values to the array (by applying the window function)
115 void add(float value, int pos, WindowFunction *window_function) {
116 float add_value = value;
117 if (window_function != nullptr) {
118 add_value = value * window_function->factor(pos);
119 }
120 assert(pos < len);
121 data[pos] += add_value;
122 }
123
124 // gets the scaled audio data as result
125 void getStepData(float *result, int stride, float maxResult) {
126 for (int j = 0; j < stride; j++) {
127 // determine max value to scale
128 if (data[j] > rfft_max) rfft_max = data[j];
129 }
130 for (int j = 0; j < stride; j++) {
131 result[j] = data[j] / rfft_max * maxResult;
132 // clip
133 if (result[j] > maxResult) {
134 result[j] = maxResult;
135 }
136 if (result[j] < -maxResult) {
137 result[j] = -maxResult;
138 }
139 }
140 // copy data to head
141 for (int j = 0; j < len - stride; j++) {
142 data[j] = data[j + stride];
143 }
144 // clear tail
145 for (int j = len - stride; j < len; j++) {
146 data[j] = 0.0;
147 }
148 }
149
151 int size() { return data.size(); }
152
153 protected:
155 int len = 0;
156 float rfft_max = 0;
157};
158
166 public:
167 virtual bool begin(int len) = 0;
168 virtual void end() = 0;
170 virtual void setValue(int pos, float value) = 0;
172 virtual void fft() = 0;
174 virtual float magnitude(int idx) = 0;
176 virtual float magnitudeFast(int idx) = 0;
177 virtual bool isValid() = 0;
179 virtual bool isReverseFFT() { return false; }
181 virtual void rfft() { LOGE("Not implemented"); }
183 virtual float getValue(int pos) = 0;
185 virtual bool setBin(int idx, float real, float img) { return false; }
187 bool setBin(int pos, FFTBin &bin) { return setBin(pos, bin.real, bin.img); }
189 virtual bool getBin(int pos, FFTBin &bin) { return false; }
190};
191
200class AudioFFTBase : public AudioStream {
201 public:
205
207
211 info.rxtx_mode = mode;
212 return info;
213 }
214
217 cfg = info;
218 return begin();
219 }
220
222 bool begin() override {
223 bins = cfg.length / 2;
224 // define window functions
225 if (cfg.window_function_fft == nullptr)
227 if (cfg.window_function_ifft == nullptr)
229 // define default stride value if not defined
230 if (cfg.stride == 0) cfg.stride = cfg.length;
231
232 if (!isPowerOfTwo(cfg.length)) {
233 LOGE("Len must be of the power of 2: %d", cfg.length);
234 return false;
235 }
236 if (!p_driver->begin(cfg.length)) {
237 LOGE("Not enough memory");
238 }
239
240 if (cfg.window_function_fft != nullptr) {
242 }
243 if (cfg.window_function_ifft != nullptr &&
246 }
247
248 bool is_valid_rxtx = false;
250 // holds last N bytes that need to be reprocessed
252 is_valid_rxtx = true;
253 }
258 is_valid_rxtx = true;
259 }
260
261 if (!is_valid_rxtx) {
262 LOGE("Invalid rxtx_mode");
263 return false;
264 }
265
266 current_pos = 0;
267 return p_driver->isValid();
268 }
269
271 void reset() {
272 current_pos = 0;
273 if (cfg.window_function_fft != nullptr) {
275 }
276 if (cfg.window_function_ifft != nullptr) {
278 }
279 }
280
281 operator bool() override {
282 return p_driver != nullptr && p_driver->isValid();
283 }
284
292
294 void end() override {
295 p_driver->end();
297 rfft_data.resize(0);
298 rfft_add.resize(0);
299 step_data.resize(0);
300 }
301
303 size_t write(const uint8_t *data, size_t len) override {
304 size_t result = 0;
305 if (p_driver->isValid()) {
306 result = len;
307 switch (cfg.bits_per_sample) {
308 case 8:
309 processSamples<int8_t>(data, len);
310 break;
311 case 16:
312 processSamples<int16_t>(data, len / 2);
313 break;
314 case 24:
315 processSamples<int24_t>(data, len / 3);
316 break;
317 case 32:
318 processSamples<int32_t>(data, len / 4);
319 break;
320 default:
321 LOGE("Unsupported bits_per_sample: %d", cfg.bits_per_sample);
322 break;
323 }
324 }
325 return result;
326 }
327
329 size_t readBytes(uint8_t *data, size_t len) override {
330 TRACED();
331 if (rfft_data.size() == 0) return 0;
332
333 // get data via callback if there is no more data
334 if (cfg.rxtx_mode == RX_MODE && cfg.callback != nullptr &&
335 rfft_data.available() == 0) {
336 cfg.callback(*this);
337 }
338
339 // execute rfft when we consumed all data
340 if (has_rfft_data && rfft_data.available() == 0) {
341 rfft();
342 }
343 return rfft_data.readArray(data, len);
344 }
345
347 int availableForWrite() override {
348 return cfg.length * cfg.channels * bytesPerSample();
349 }
350
352 int available() override {
353 assert(cfg.stride != 0);
354 return cfg.stride * cfg.channels * bytesPerSample();
355 }
356
358 int size() { return bins; }
359
361 int length() { return cfg.length; }
362
365 unsigned long resultTime() { return timestamp; }
367 unsigned long resultTimeBegin() { return timestamp_begin; }
368
371 AudioFFTResult ret_value;
372 ret_value.magnitude = 0.0f;
373 ret_value.bin = 0;
374 // find max value and index
375 for (int j = 0; j < size(); j++) {
376 float m = magnitude(j);
377 if (m > ret_value.magnitude) {
378 ret_value.magnitude = m;
379 ret_value.bin = j;
380 }
381 }
382 ret_value.frequency = frequency(ret_value.bin);
383 return ret_value;
384 }
385
387 template <int N>
389 // initialize to negative value
390 for (int j = 0; j < N; j++) {
391 result[j].magnitude = -1000000;
392 }
393 // find top n values
394 AudioFFTResult act;
395 for (int j = 0; j < size(); j++) {
396 act.magnitude = magnitude(j);
397 act.bin = j;
398 act.frequency = frequency(j);
399 insertSorted<N>(result, act);
400 }
401 }
402
404 float *toMEL(int n_bins, float min_freq = 0.0f, float max_freq = 0.0f) {
405 // calculate mel bins
406 if (n_bins <= 0) n_bins = size();
407 if (min_freq <= 0.0f) min_freq = frequency(0);
408 if (max_freq <= 0.0f) max_freq = frequency(size() - 1);
409 mel_bins.resize(n_bins);
410
411 // Convert min and max frequencies to MEL scale
412 float min_mel = 2595.0f * log10(1.0f + (min_freq / 700.0f));
413 float max_mel = 2595.0f * log10(1.0f + (max_freq / 700.0f));
414
415 // Create equally spaced points in the MEL scale
416 Vector<float> mel_points;
417 mel_points.resize(n_bins + 2); // +2 for the endpoints
418
419 float mel_step = (max_mel - min_mel) / (n_bins + 1);
420 for (int i = 0; i < n_bins + 2; i++) {
421 mel_points[i] = min_mel + i * mel_step;
422 }
423
424 // Convert MEL points back to frequency
425 Vector<float> freq_points;
426 freq_points.resize(n_bins + 2);
427 for (int i = 0; i < n_bins + 2; i++) {
428 freq_points[i] = 700.0f * (pow(10.0f, mel_points[i] / 2595.0f) - 1.0f);
429 }
430
431 // Convert frequency points to FFT bin indices
432 Vector<int> bin_indices;
433 bin_indices.resize(n_bins + 2);
434 for (int i = 0; i < n_bins + 2; i++) {
435 bin_indices[i] = round(freq_points[i] * cfg.length / cfg.sample_rate);
436 // Ensure bin index is within valid range
437 if (bin_indices[i] >= bins) bin_indices[i] = bins - 1;
438 if (bin_indices[i] < 0) bin_indices[i] = 0;
439 }
440
441 // Create and apply triangular filters
442 for (int i = 0; i < n_bins; i++) {
443 float mel_sum = 0.0f;
444
445 int start_bin = bin_indices[i];
446 int mid_bin = bin_indices[i + 1];
447 int end_bin = bin_indices[i + 2];
448
449 // Apply first half of triangle filter (ascending)
450 for (int j = start_bin; j < mid_bin; j++) {
451 if (j >= bins) break;
452 float weight = (j - start_bin) / float(mid_bin - start_bin);
453 mel_sum += magnitude(j) * weight;
454 }
455
456 // Apply second half of triangle filter (descending)
457 for (int j = mid_bin; j < end_bin; j++) {
458 if (j >= bins) break;
459 float weight = (end_bin - j) / float(end_bin - mid_bin);
460 mel_sum += magnitude(j) * weight;
461 }
462
463 mel_bins[i] = mel_sum;
464 }
465
466 return mel_bins.data();
467 }
468
476 bool fromMEL(float *values, int n_bins, float min_freq = 0.0f,
477 float max_freq = 0.0f) {
478 if (n_bins <= 0 || values == nullptr) return false;
479
480 // Use default frequency range if not specified
481 if (min_freq <= 0.0f) min_freq = frequency(0);
482 if (max_freq <= 0.0f) max_freq = frequency(size() - 1);
483
484 // Clear the current magnitude array
485 for (int i = 0; i < bins; i++) {
486 FFTBin bin;
487 bin.clear();
488 setBin(i, bin);
489 }
490
491 // Convert min and max frequencies to MEL scale
492 float min_mel = 2595.0f * log10(1.0f + (min_freq / 700.0f));
493 float max_mel = 2595.0f * log10(1.0f + (max_freq / 700.0f));
494
495 // Create equally spaced points in the MEL scale
496 Vector<float> mel_points;
497 mel_points.resize(n_bins + 2); // +2 for the endpoints
498
499 float mel_step = (max_mel - min_mel) / (n_bins + 1);
500 for (int i = 0; i < n_bins + 2; i++) {
501 mel_points[i] = min_mel + i * mel_step;
502 }
503
504 // Convert MEL points back to frequency
505 Vector<float> freq_points;
506 freq_points.resize(n_bins + 2);
507 for (int i = 0; i < n_bins + 2; i++) {
508 freq_points[i] = 700.0f * (pow(10.0f, mel_points[i] / 2595.0f) - 1.0f);
509 }
510
511 // Convert frequency points to FFT bin indices
512 Vector<int> bin_indices;
513 bin_indices.resize(n_bins + 2);
514 for (int i = 0; i < n_bins + 2; i++) {
515 bin_indices[i] = round(freq_points[i] * cfg.length / cfg.sample_rate);
516 // Ensure bin index is within valid range
517 if (bin_indices[i] >= bins) bin_indices[i] = bins - 1;
518 if (bin_indices[i] < 0) bin_indices[i] = 0;
519 }
520
521 // Distribute MEL energy back to linear frequency bins
522 Vector<float> linear_magnitudes;
523 linear_magnitudes.resize(bins);
524
525 for (int i = 0; i < n_bins; i++) {
526 int start_bin = bin_indices[i];
527 int mid_bin = bin_indices[i + 1];
528 int end_bin = bin_indices[i + 2];
529
530 // Apply first half of triangle (ascending)
531 for (int j = start_bin; j < mid_bin; j++) {
532 if (j >= bins) break;
533 float weight = (j - start_bin) / float(mid_bin - start_bin);
534 linear_magnitudes[j] += values[i] * weight;
535 }
536
537 // Apply second half of triangle (descending)
538 for (int j = mid_bin; j < end_bin; j++) {
539 if (j >= bins) break;
540 float weight = (end_bin - j) / float(end_bin - mid_bin);
541 linear_magnitudes[j] += values[i] * weight;
542 }
543 }
544
545 // Set magnitude values and create simple phase (all zeros)
546 for (int i = 0; i < bins; i++) {
547 if (linear_magnitudes[i] > 0) {
548 FFTBin bin;
549 bin.real = linear_magnitudes[i];
550 bin.img = 0.0f;
551 setBin(i, bin);
552 }
553 }
554
555 return true;
556 }
557
560 FFTDriver *driver() { return p_driver; }
561
563 float frequency(int bin) {
564 if (bin >= bins) {
565 LOGE("Invalid bin %d", bin);
566 return 0;
567 }
568 return static_cast<float>(bin) * cfg.sample_rate / cfg.length;
569 }
570
572 int frequencyToBin(int freq) {
573 int max_freq = cfg.sample_rate / 2;
574 return map(freq, 0, max_freq, 0, size());
575 }
576
579 float magnitude(int bin) {
580 if (bin >= bins) {
581 LOGE("Invalid bin %d", bin);
582 return 0;
583 }
584 return p_driver->magnitude(bin);
585 }
586
587 float magnitudeFast(int bin) {
588 if (bin >= bins) {
589 LOGE("Invalid bin %d", bin);
590 return 0;
591 }
592 return p_driver->magnitudeFast(bin);
593 }
594
596 float phase(int bin) {
597 FFTBin fft_bin;
598 getBin(bin, fft_bin);
599 return atan2(fft_bin.img, fft_bin.real);
600 }
601
604 float *magnitudes() {
605 if (l_magnitudes.size() == 0) {
607 }
608 for (int j = 0; j < size(); j++) {
609 l_magnitudes[j] = magnitude(j);
610 }
611 return l_magnitudes.data();
612 }
613
616 float *magnitudesFast() {
617 if (l_magnitudes.size() == 0) {
619 }
620 for (int j = 0; j < size(); j++) {
622 }
623 return l_magnitudes.data();
624 }
625
627 bool setBin(int idx, float real, float img) {
628 has_rfft_data = true;
629 if (idx < 0 || idx >= size()) return false;
630 bool rc_first_half = p_driver->setBin(idx, real, img);
631 bool rc_2nd_half = p_driver->setBin(cfg.length - idx, real, img);
632 return rc_first_half && rc_2nd_half;
633 }
635 bool setBin(int pos, FFTBin &bin) { return setBin(pos, bin.real, bin.img); }
637 bool getBin(int pos, FFTBin &bin) { return p_driver->getBin(pos, bin); }
638
640 void clearBins() {
641 FFTBin empty{0, 0};
642 for (int j = 0; j < size(); j++) {
643 setBin(j, empty);
644 }
645 }
646
648 AudioFFTConfig &config() { return cfg; }
649
651 template <typename T>
653 return *((T*)cfg.ref);
654 }
655
656 protected:
657 FFTDriver *p_driver = nullptr;
658 int current_pos = 0;
659 int bins = 0;
660 unsigned long timestamp_begin = 0l;
661 unsigned long timestamp = 0l;
669 bool has_rfft_data = false;
670
671 // Add samples to input data p_x - and process them if full
672 template <typename T>
673 void processSamples(const void *data, size_t count) {
674 T *dataT = (T *)data;
675 T sample;
676 for (int j = 0; j < count; j += cfg.channels) {
677 sample = dataT[j + cfg.channel_used];
678 if (writeStrideBuffer((uint8_t *)&sample, sizeof(T))) {
679 // process data if buffer is full
680 T *samples = (T *)stride_buffer.data();
681 int sample_count = stride_buffer.size() / sizeof(T);
682 assert(sample_count == cfg.length);
683 for (int j = 0; j < sample_count; j++) {
684 T out_sample = samples[j];
685 T windowed_sample = windowedSample(out_sample, j);
686 float scaled_sample =
687 1.0f / NumberConverter::maxValueT<T>() * windowed_sample;
688 p_driver->setValue(j, scaled_sample);
689 }
690
691 fft<T>();
692
693 // remove stride samples
694 stride_buffer.clearArray(cfg.stride * sizeof(T));
695
696 // validate available data in stride buffer
698 }
699 }
700 }
701
702 template <typename T>
703 T windowedSample(T sample, int pos) {
704 T result = sample;
705 if (cfg.window_function_fft != nullptr) {
706 result = cfg.window_function_fft->factor(pos) * sample;
707 }
708 return result;
709 }
710
711 template <typename T>
712 void fft() {
714 p_driver->fft();
715 has_rfft_data = true;
716 timestamp = millis();
717 if (cfg.callback != nullptr) {
718 cfg.callback(*this);
719 }
720 }
721
723 void rfft() {
724 TRACED();
725 // execute reverse fft
726 p_driver->rfft();
727 has_rfft_data = false;
728 // add data to sum buffer
729 for (int j = 0; j < cfg.length; j++) {
730 float value = p_driver->getValue(j);
732 }
733 // get result data from sum buffer
735 }
736
739 // get data to result buffer
740 // for (int j = 0; j < cfg.stride; j++) {
741 // step_data[j] = 0.0;
742 // }
745
746 switch (cfg.bits_per_sample) {
747 case 8:
748 writeIFFT<int8_t>(step_data.data(), cfg.stride);
749 break;
750 case 16:
751 writeIFFT<int16_t>(step_data.data(), cfg.stride);
752 break;
753 case 24:
754 writeIFFT<int24_t>(step_data.data(), cfg.stride);
755 break;
756 case 32:
757 writeIFFT<int32_t>(step_data.data(), cfg.stride);
758 break;
759 default:
760 LOGE("Unsupported bits: %d", cfg.bits_per_sample);
761 }
762 }
763
764 template <typename T>
765 void writeIFFT(float *data, int len) {
766 for (int j = 0; j < len; j++) {
767 T sample = data[j];
768 T out_data[cfg.channels];
769 for (int ch = 0; ch < cfg.channels; ch++) {
770 out_data[ch] = sample;
771 }
772 int result = rfft_data.writeArray((uint8_t *)out_data, sizeof(out_data));
773 assert(result == sizeof(out_data));
774 }
775 }
776
777 inline int bytesPerSample() { return cfg.bits_per_sample / 8; }
778
780 template <int N>
782 // find place where we need to insert new record
783 for (int j = 0; j < N; j++) {
784 // insert when biggen then current record
785 if (tmp.magnitude > result[j].magnitude) {
786 // shift existing values right
787 for (int i = N - 2; i >= j; i--) {
788 result[i + 1] = result[i];
789 }
790 // insert new value
791 result[j] = tmp;
792 // stop after we found the correct index
793 break;
794 }
795 }
796 }
797
798 // adds samples to stride buffer, returns true if the buffer is full
799 bool writeStrideBuffer(uint8_t *buffer, size_t len) {
801 stride_buffer.writeArray(buffer, len);
802 return stride_buffer.isFull();
803 }
804
805 bool isPowerOfTwo(uint16_t x) { return (x & (x - 1)) == 0; }
806};
807
808} // namespace audio_tools
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition Arduino.h:182
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Different Window functions that can be used by FFT.
#define assert(T)
Definition avr.h:10
Executes FFT using audio data privded by write() and/or an inverse FFT where the samples are made ava...
Definition AudioFFT.h:200
unsigned long resultTimeBegin()
time before the fft
Definition AudioFFT.h:367
unsigned long timestamp_begin
Definition AudioFFT.h:660
void clearBins()
clears the fft data
Definition AudioFFT.h:640
float magnitude(int bin)
Definition AudioFFT.h:579
T windowedSample(T sample, int pos)
Definition AudioFFT.h:703
float * magnitudesFast()
Definition AudioFFT.h:616
unsigned long resultTime()
Definition AudioFFT.h:365
bool writeStrideBuffer(uint8_t *buffer, size_t len)
Definition AudioFFT.h:799
int length()
The number of samples.
Definition AudioFFT.h:361
void fft()
Definition AudioFFT.h:712
FFTDriver * p_driver
Definition AudioFFT.h:657
size_t readBytes(uint8_t *data, size_t len) override
Provides the result of a reverse FFT.
Definition AudioFFT.h:329
RingBuffer< uint8_t > rfft_data
Definition AudioFFT.h:668
void writeIFFT(float *data, int len)
Definition AudioFFT.h:765
void end() override
Release the allocated memory.
Definition AudioFFT.h:294
bool has_rfft_data
Definition AudioFFT.h:669
int available() override
Data available for reverse fft.
Definition AudioFFT.h:352
AudioFFTBase(FFTDriver *driver)
Definition AudioFFT.h:204
AudioFFTConfig & config()
Provides the actual configuration.
Definition AudioFFT.h:648
size_t write(const uint8_t *data, size_t len) override
Provide the audio data as FFT input.
Definition AudioFFT.h:303
bool isPowerOfTwo(uint16_t x)
Definition AudioFFT.h:805
FFTDriver * driver()
Definition AudioFFT.h:560
~AudioFFTBase()
Definition AudioFFT.h:206
int frequencyToBin(int freq)
Determine the bin number from the frequency.
Definition AudioFFT.h:572
bool setBin(int idx, float real, float img)
sets the value of a bin
Definition AudioFFT.h:627
int bytesPerSample()
Definition AudioFFT.h:777
int availableForWrite() override
We try to fill the buffer at once.
Definition AudioFFT.h:347
float phase(int bin)
calculates the phase
Definition AudioFFT.h:596
Vector< float > step_data
Definition AudioFFT.h:665
AudioFFTConfig defaultConfig(RxTxMode mode=TX_MODE)
Provides the default configuration.
Definition AudioFFT.h:209
SingleBuffer< uint8_t > stride_buffer
Definition AudioFFT.h:667
T & reference()
Provides the reference pointer.
Definition AudioFFT.h:652
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.
Definition AudioFFT.h:476
bool begin(AudioFFTConfig info)
starts the processing
Definition AudioFFT.h:216
float * magnitudes()
Definition AudioFFT.h:604
bool getBin(int pos, FFTBin &bin)
gets the value of a bin
Definition AudioFFT.h:637
FFTInverseOverlapAdder rfft_add
Definition AudioFFT.h:663
AudioFFTResult result()
Determines the result values in the max magnitude bin.
Definition AudioFFT.h:370
float frequency(int bin)
Determines the frequency of the indicated bin.
Definition AudioFFT.h:563
int current_pos
Definition AudioFFT.h:658
void rfft()
reverse fft
Definition AudioFFT.h:723
bool setBin(int pos, FFTBin &bin)
sets the value of a bin
Definition AudioFFT.h:635
AudioFFTConfig cfg
Definition AudioFFT.h:662
void insertSorted(AudioFFTResult(&result)[N], AudioFFTResult tmp)
make sure that we do not reuse already found results
Definition AudioFFT.h:781
bool begin() override
starts the processing
Definition AudioFFT.h:222
unsigned long timestamp
Definition AudioFFT.h:661
void setAudioInfo(AudioInfo info) override
Notify change of audio information.
Definition AudioFFT.h:286
void reset()
Just resets the current_pos e.g. to start a new cycle.
Definition AudioFFT.h:271
void processSamples(const void *data, size_t count)
Definition AudioFFT.h:673
float magnitudeFast(int bin)
Definition AudioFFT.h:587
Vector< float > mel_bins
Definition AudioFFT.h:666
void resultArray(AudioFFTResult(&result)[N])
Determines the N biggest result values.
Definition AudioFFT.h:388
float * toMEL(int n_bins, float min_freq=0.0f, float max_freq=0.0f)
Convert the FFT result to MEL spectrum.
Definition AudioFFT.h:404
int size()
The number of bins used by the FFT which are relevant for the result.
Definition AudioFFT.h:358
int bins
Definition AudioFFT.h:659
Vector< float > l_magnitudes
Definition AudioFFT.h:664
void rfftWriteData(BaseBuffer< uint8_t > &data)
write reverse fft result to buffer to make it available for readBytes
Definition AudioFFT.h:738
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
AudioInfo info
Definition BaseStream.h:171
Shared functionality of all buffers.
Definition Buffers.h:23
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:34
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:56
Abstract Class which defines the basic FFT functionality.
Definition AudioFFT.h:165
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:185
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:179
virtual void end()=0
virtual void rfft()
Calculate reverse FFT.
Definition AudioFFT.h:181
bool setBin(int pos, FFTBin &bin)
sets the value of a bin
Definition AudioFFT.h:187
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:189
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:125
Vector< float > data
Definition AudioFFT.h:154
float rfft_max
Definition AudioFFT.h:156
FFTInverseOverlapAdder(int size=0)
Definition AudioFFT.h:94
void add(float value, int pos, WindowFunction *window_function)
Definition AudioFFT.h:115
bool resize(size_t size)
Initilze data by defining new size.
Definition AudioFFT.h:99
int size()
provides the actual size
Definition AudioFFT.h:151
int len
Definition AudioFFT.h:155
Determination of the frequency of a music note.
Definition MusicalNotes.h:125
const char * note(float frequency, float &diff) const
Determines the closes note for a frequency. We also return the frequency difference.
Definition MusicalNotes.h:169
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition AudioTypes.h:297
Implements a typed Ringbuffer.
Definition Buffers.h:353
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:440
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:430
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:422
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:184
size_t size() override
Definition Buffers.h:315
int available() override
provides the number of entries that are available to read
Definition Buffers.h:245
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:250
bool isFull() override
checks if the buffer is full
Definition Buffers.h:252
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:213
T * data()
Provides address of actual data.
Definition Buffers.h:296
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:317
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:264
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
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
FFT Window Function.
Definition FFTWindows.h:28
virtual void begin(int samples)
Setup the window function providing the fft length.
Definition FFTWindows.h:33
float factor(int idx)
Definition FFTWindows.h:41
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
static MusicalNotes AudioFFTNotes
Definition AudioFFT.h:17
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:256
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:51
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57
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