4#include "AudioTools/CoreAudio/AudioStreams.h"
5#include "AudioTools/CoreAudio/MusicalNotes.h"
17static MusicalNotes AudioFFTNotes;
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);
76 void multiply(
float f) {
81 void conjugate() { img = -img; }
83 void clear() { real = img = 0.0f; }
100 for (
int j = 0; j < data.size(); j++) {
107 float add_value = value;
108 if (window_function !=
nullptr) {
109 add_value = value * window_function->
factor(pos);
112 data[pos] += add_value;
116 void getStepData(
float *result,
int stride,
float maxResult) {
117 for (
int j = 0; j < stride; j++) {
119 if (data[j] > rfft_max) rfft_max = data[j];
121 for (
int j = 0; j < stride; j++) {
122 result[j] = data[j] / rfft_max * maxResult;
124 if (result[j] > maxResult) {
125 result[j] = maxResult;
127 if (result[j] < -maxResult) {
128 result[j] = -maxResult;
132 for (
int j = 0; j < len - stride; j++) {
133 data[j] = data[j + stride];
136 for (
int j = len - stride; j < len; j++) {
142 int size() {
return data.size(); }
158 virtual bool begin(
int len) = 0;
159 virtual void end() = 0;
168 virtual bool isValid() = 0;
172 virtual void rfft() { LOGE(
"Not implemented"); }
176 virtual bool setBin(
int idx,
float real,
float img) {
return false; }
214 bins = cfg.length / 2;
219 if (cfg.stride == 0) cfg.stride = cfg.length;
221 if (!isPowerOfTwo(cfg.length)) {
222 LOGE(
"Len must be of the power of 2: %d", cfg.length);
225 if (!p_driver->begin(cfg.length)) {
226 LOGE(
"Not enough memory");
237 bool is_valid_rxtx =
false;
240 stride_buffer.resize((cfg.length) * bytesPerSample());
241 is_valid_rxtx =
true;
244 rfft_data.resize(cfg.
channels * bytesPerSample() * cfg.stride);
245 rfft_add.
resize(cfg.length);
246 step_data.resize(cfg.stride);
247 is_valid_rxtx =
true;
251 LOGE(
"Invalid rxtx_mode");
256 return p_driver->isValid();
270 operator bool()
override {
return p_driver !=
nullptr && p_driver->isValid(); }
283 l_magnitudes.resize(0);
290 size_t write(
const uint8_t *data,
size_t len)
override {
292 if (p_driver->isValid()) {
296 processSamples<int8_t>(data, len);
299 processSamples<int16_t>(data, len / 2);
302 processSamples<int24_t>(data, len / 3);
305 processSamples<int32_t>(data, len / 4);
290 size_t write(
const uint8_t *data,
size_t len)
override {
…}
318 if (rfft_data.
size() == 0)
return 0;
326 if (has_rfft_data && rfft_data.
available() == 0) {
334 return cfg.length * cfg.
channels * bytesPerSample();
339 assert(cfg.stride != 0);
340 return cfg.stride * cfg.
channels * bytesPerSample();
359 ret_value.magnitude = 0;
362 for (
int j = 0; j <
size(); j++) {
364 if (m > ret_value.magnitude) {
365 ret_value.magnitude = m;
369 ret_value.frequency =
frequency(ret_value.bin);
377 for (
int j = 0; j < N; j++) {
378 result[j].magnitude = -1000000;
382 for (
int j = 0; j <
size(); j++) {
386 insertSorted<N>(
result, act);
397 LOGE(
"Invalid bin %d", bin);
400 return static_cast<float>(bin) * cfg.
sample_rate / cfg.length;
406 return map(freq, 0, max_freq, 0,
size());
413 LOGE(
"Invalid bin %d", bin);
419 float magnitudeFast(
int bin) {
421 LOGE(
"Invalid bin %d", bin);
431 return atan2(fft_bin.img, fft_bin.real);
437 if (l_magnitudes.size() == 0) {
438 l_magnitudes.resize(
size());
440 for (
int j = 0; j <
size(); j++) {
443 return l_magnitudes.data();
449 if (l_magnitudes.size() == 0) {
450 l_magnitudes.resize(
size());
452 for (
int j = 0; j <
size(); j++) {
453 l_magnitudes[j] = magnitudeFast(j);
455 return l_magnitudes.data();
459 bool setBin(
int idx,
float real,
float img) {
460 has_rfft_data =
true;
461 if (idx < 0 || idx >=
size())
return false;
462 bool rc_first_half = p_driver->
setBin(idx, real, img);
463 bool rc_2nd_half = p_driver->
setBin(cfg.length - idx, real, img);
464 return rc_first_half && rc_2nd_half;
459 bool setBin(
int idx,
float real,
float img) {
…}
468 return setBin(pos, bin.real, bin.img);
476 for (
int j=0; j<
size(); j++){
488 unsigned long timestamp_begin = 0l;
489 unsigned long timestamp = 0l;
492 Vector<float> l_magnitudes{0};
493 Vector<float> step_data{0};
494 SingleBuffer<uint8_t> stride_buffer{0};
495 RingBuffer<uint8_t> rfft_data{0};
496 bool has_rfft_data =
false;
499 template <
typename T>
500 void processSamples(
const void *data,
size_t count) {
501 T *dataT = (T *)data;
503 for (
int j = 0; j < count; j += cfg.
channels) {
505 if (writeStrideBuffer((uint8_t *)&sample,
sizeof(T))){
507 T* samples = (T*) stride_buffer.
data();
508 int sample_count = stride_buffer.size() /
sizeof(T);
509 assert(sample_count == cfg.length);
510 for (
int j=0; j< sample_count; j++){
511 T out_sample = samples[j];
512 p_driver->
setValue(j, windowedSample(out_sample, j));
518 stride_buffer.
clearArray(cfg.stride *
sizeof(T));
521 if (cfg.stride == cfg.length) assert(stride_buffer.
available()==0);
527 template <
typename T>
528 T windowedSample(T sample,
int pos) {
536 template <
typename T>
538 timestamp_begin =
millis();
540 has_rfft_data =
true;
552 has_rfft_data =
false;
554 for (
int j = 0; j < cfg.length; j++) {
555 float value = p_driver->
getValue(j);
568 rfft_add.getStepData(step_data.data(), cfg.stride,
573 writeIFFT<int8_t>(step_data.data(), cfg.stride);
576 writeIFFT<int16_t>(step_data.data(), cfg.stride);
579 writeIFFT<int24_t>(step_data.data(), cfg.stride);
582 writeIFFT<int32_t>(step_data.data(), cfg.stride);
589 template <
typename T>
590 void writeIFFT(
float *data,
int len) {
591 for (
int j = 0; j < len; j++) {
594 for (
int ch = 0; ch < cfg.
channels; ch++) {
595 out_data[ch] = sample;
598 assert(
result ==
sizeof(out_data));
608 for (
int j = 0; j < N; j++) {
610 if (tmp.magnitude >
result[j].magnitude) {
612 for (
int i = N - 2; i >= j; i--) {
624 bool writeStrideBuffer(uint8_t *buffer,
size_t len) {
627 return stride_buffer.
isFull();
630 bool isPowerOfTwo(uint16_t x) {
return (x & (x - 1)) == 0; }
Different Window functions that can be used by FFT.
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:28