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++) {
108 if (window_function !=
nullptr) {
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");
240 stride_buffer.resize((cfg.length) * bytesPerSample());
244 rfft_data.resize(cfg.
channels * bytesPerSample() * cfg.stride);
245 rfft_add.
resize(cfg.length);
246 step_data.resize(cfg.stride);
251 LOGE(
"Invalid rxtx_mode");
256 return p_driver->isValid();
270 operator bool() {
return p_driver !=
nullptr && p_driver->isValid(); }
283 l_magnitudes.resize(0);
292 if (p_driver->isValid()) {
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();
362 for (
int j = 0;
j <
size();
j++) {
377 for (
int j = 0;
j <
N;
j++) {
378 result[
j].magnitude = -1000000;
382 for (
int j = 0;
j <
size();
j++) {
397 LOGE(
"Invalid bin %d", bin);
400 return static_cast<float>(bin) * cfg.
sample_rate / cfg.length;
413 LOGE(
"Invalid bin %d", bin);
419 float magnitudeFast(
int bin) {
421 LOGE(
"Invalid bin %d", bin);
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;
459 bool setBin(
int idx,
float real,
float img) {
…}
468 return setBin(pos, bin.real, bin.img);
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++) {
568 rfft_add.getStepData(step_data.data(), cfg.stride,
589 template <
typename T>
590 void writeIFFT(
float *data,
int len) {
591 for (
int j = 0;
j < len;
j++) {
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