@@ -49,8 +49,12 @@ struct AudioFFTConfig : public AudioInfo {
49
49
uint8_t channel_used = 0 ;
50
50
int length = 8192 ;
51
51
int stride = 0 ;
52
- // / Optional window function
52
+ // / Optional window function for both fft and ifft
53
53
WindowFunction *window_function = nullptr ;
54
+ // / Optional window function for fft only
55
+ WindowFunction *window_function_fft = nullptr ;
56
+ // / Optional window function for ifft only
57
+ WindowFunction *window_function_ifft = nullptr ;
54
58
// / TX_MODE = FFT, RX_MODE = IFFT
55
59
RxTxMode rxtx_mode = TX_MODE;
56
60
};
@@ -96,18 +100,19 @@ class FFTInverseOverlapAdder {
96
100
// adds the values to the array (by applying the window function)
97
101
void add (float value, int pos, WindowFunction *window_function) {
98
102
float add_value = value;
99
- if (window_function != nullptr )
103
+ if (window_function != nullptr ) {
100
104
add_value = value * window_function->factor (pos);
105
+ }
101
106
data[pos] += add_value;
102
107
}
103
108
104
109
// gets the scaled audio data as result
105
- void getStepData (float *result, int step_size , float maxResult) {
106
- for (int j = 0 ; j < step_size ; j++) {
110
+ void getStepData (float *result, int stride , float maxResult) {
111
+ for (int j = 0 ; j < stride ; j++) {
107
112
// determine max value to scale
108
- if (rfft_max < data[j]) rfft_max = data[j];
113
+ if (data[j] > rfft_max ) rfft_max = data[j];
109
114
}
110
- for (int j = 0 ; j < step_size ; j++) {
115
+ for (int j = 0 ; j < stride ; j++) {
111
116
result[j] = data[j] / rfft_max * maxResult;
112
117
// clip
113
118
if (result[j] > maxResult) {
@@ -118,17 +123,21 @@ class FFTInverseOverlapAdder {
118
123
}
119
124
}
120
125
// copy data to head
121
- for (int j = 0 ; j < len - step_size ; j++) {
122
- data[j] = data[j + step_size ];
126
+ for (int j = 0 ; j < len - stride ; j++) {
127
+ data[j] = data[j + stride ];
123
128
}
124
129
// clear tail
125
- for (int j = len - step_size ; j < len; j++) {
130
+ for (int j = len - stride ; j < len; j++) {
126
131
data[j] = 0.0 ;
127
132
}
128
133
}
129
134
130
135
int size () { return data.size (); }
131
136
137
+ void begin (){
138
+ rfft_max = 0 ;
139
+ }
140
+
132
141
protected:
133
142
Vector<float > data{0 };
134
143
int len = 0 ;
@@ -200,24 +209,32 @@ class AudioFFTBase : public AudioStream {
200
209
// / starts the processing
201
210
bool begin () override {
202
211
bins = cfg.length / 2 ;
212
+ // define window functions
213
+ if (cfg.window_function_fft ==nullptr ) cfg.window_function_fft = cfg.window_function ;
214
+ if (cfg.window_function_ifft ==nullptr ) cfg.window_function_ifft = cfg.window_function ;
215
+ // define default stride value if not defined
216
+ if (cfg.stride == 0 ) cfg.stride = cfg.length ;
217
+
203
218
if (!isPowerOfTwo (cfg.length )) {
204
219
LOGE (" Len must be of the power of 2: %d" , cfg.length );
205
220
return false ;
206
221
}
207
222
if (!p_driver->begin (cfg.length )) {
208
223
LOGE (" Not enough memory" );
209
224
}
210
- int step_size = cfg.stride > 0 ? cfg.stride : cfg.length ;
211
- if (cfg.window_function != nullptr ) {
212
- cfg.window_function ->begin (step_size);
225
+
226
+ if (cfg.window_function_fft != nullptr ) {
227
+ cfg.window_function_fft ->begin (cfg.length );
228
+ }
229
+ if (cfg.window_function_ifft != nullptr ) {
230
+ cfg.window_function_ifft ->begin (cfg.length );
213
231
}
214
232
233
+ int step_size = cfg.stride > 0 ? cfg.stride : cfg.length ;
215
234
bool is_valid_rxtx = false ;
216
235
if (cfg.rxtx_mode == TX_MODE || cfg.rxtx_mode == RXTX_MODE) {
217
- if (cfg.stride > 0 && cfg.stride < cfg.length ) {
218
- // holds last N bytes that need to be reprocessed
219
- stride_buffer.resize ((cfg.length - cfg.stride ) * bytesPerSample ());
220
- }
236
+ // holds last N bytes that need to be reprocessed
237
+ stride_buffer.resize ((cfg.length ) * bytesPerSample ());
221
238
is_valid_rxtx = true ;
222
239
}
223
240
if (cfg.rxtx_mode == RX_MODE || cfg.rxtx_mode == RXTX_MODE) {
@@ -238,8 +255,11 @@ class AudioFFTBase : public AudioStream {
238
255
// / Just resets the current_pos e.g. to start a new cycle
239
256
void reset () {
240
257
current_pos = 0 ;
241
- if (cfg.window_function != nullptr ) {
242
- cfg.window_function ->begin (length ());
258
+ if (cfg.window_function_fft != nullptr ) {
259
+ cfg.window_function_fft ->begin (cfg.length );
260
+ }
261
+ if (cfg.window_function_ifft != nullptr ) {
262
+ cfg.window_function_ifft ->begin (cfg.length );
243
263
}
244
264
}
245
265
@@ -290,7 +310,7 @@ class AudioFFTBase : public AudioStream {
290
310
291
311
// / Provides the result of a reverse FFT
292
312
size_t readBytes (uint8_t *data, size_t len) override {
293
- LOGD ( " setup ifft data " );
313
+ TRACED ( );
294
314
if (rfft_data.size () == 0 ) return 0 ;
295
315
// execute rfft when we consumed all data
296
316
if (has_rfft_data && rfft_data.available () == 0 ) {
@@ -432,7 +452,7 @@ class AudioFFTBase : public AudioStream {
432
452
AudioFFTConfig cfg;
433
453
unsigned long timestamp_begin = 0l ;
434
454
unsigned long timestamp = 0l ;
435
- RingBuffer <uint8_t > stride_buffer{0 };
455
+ SingleBuffer <uint8_t > stride_buffer{0 };
436
456
Vector<float > l_magnitudes{0 };
437
457
Vector<float > step_data{0 };
438
458
int bins = 0 ;
@@ -445,35 +465,35 @@ class AudioFFTBase : public AudioStream {
445
465
void processSamples (const void *data, size_t samples) {
446
466
T *dataT = (T *)data;
447
467
T sample;
448
- float sample_windowed;
449
468
for (int j = 0 ; j < samples; j += cfg.channels ) {
450
469
sample = dataT[j + cfg.channel_used ];
451
- p_driver->setValue (current_pos, windowedSample (sample, current_pos));
452
- writeStrideBuffer ((uint8_t *)&sample, sizeof (T));
453
- if (++current_pos >= cfg.length ) {
454
- fft<T>();
455
- current_pos = 0 ;
456
-
457
- // reprocess data in stride buffer
458
- if (stride_buffer.size () > 0 ) {
459
- // reload data from stride buffer
460
- while (stride_buffer.available ()) {
461
- T sample;
462
- stride_buffer.readArray ((uint8_t *)&sample, sizeof (T));
463
- p_driver->setValue (current_pos,
464
- windowedSample (sample, current_pos));
465
- current_pos++;
466
- }
470
+ if (writeStrideBuffer ((uint8_t *)&sample, sizeof (T))){
471
+ // process data if buffer is full
472
+ T* samples = (T*) stride_buffer.data ();
473
+ int sample_count = stride_buffer.size () / sizeof (T);
474
+ assert (sample_count == cfg.length );
475
+ for (int j=0 ; j< sample_count; j++){
476
+ T out_sample = samples[j];
477
+ p_driver->setValue (j, windowedSample (out_sample, j));
467
478
}
479
+
480
+ fft<T>();
481
+
482
+ // remove stride samples
483
+ stride_buffer.clearArray (cfg.stride * sizeof (T));
484
+
485
+ // validate available data in stride buffer
486
+ if (cfg.stride == cfg.length ) assert (stride_buffer.available ()==0 );
487
+
468
488
}
469
489
}
470
490
}
471
491
472
492
template <typename T>
473
493
T windowedSample (T sample, int pos) {
474
494
T result = sample;
475
- if (cfg.window_function != nullptr ) {
476
- result = cfg.window_function ->factor (pos) * sample;
495
+ if (cfg.window_function_fft != nullptr ) {
496
+ result = cfg.window_function_fft ->factor (pos) * sample;
477
497
}
478
498
return result;
479
499
}
@@ -498,35 +518,34 @@ class AudioFFTBase : public AudioStream {
498
518
// add data to sum buffer
499
519
for (int j = 0 ; j < cfg.length ; j++) {
500
520
float value = p_driver->getValue (j);
501
- rfft_add.add (value, j, cfg.window_function );
521
+ rfft_add.add (value, j, cfg.window_function_ifft );
502
522
}
503
523
// get result data from sum buffer
504
524
rfftWriteData (rfft_data);
505
525
}
506
526
507
527
// / write reverse fft result to buffer to make it available for readBytes
508
528
void rfftWriteData (BaseBuffer<uint8_t > &data) {
509
- int step_size = cfg.stride > 0 ? cfg.stride : cfg.length ;
510
529
// get data to result buffer
511
- step_data.resize (step_size );
512
- for (int j = 0 ; j < step_size ; j++) {
530
+ step_data.resize (cfg. stride );
531
+ for (int j = 0 ; j < cfg. stride ; j++) {
513
532
step_data[j] = 0.0 ;
514
533
}
515
- rfft_add.getStepData (step_data.data (), step_size ,
534
+ rfft_add.getStepData (step_data.data (), cfg. stride ,
516
535
NumberConverter::maxValue (cfg.bits_per_sample ));
517
536
518
537
switch (cfg.bits_per_sample ) {
519
538
case 8 :
520
- writeIFFT<int8_t >(step_data.data (), step_size );
539
+ writeIFFT<int8_t >(step_data.data (), cfg. stride );
521
540
break ;
522
541
case 16 :
523
- writeIFFT<int16_t >(step_data.data (), step_size );
542
+ writeIFFT<int16_t >(step_data.data (), cfg. stride );
524
543
break ;
525
544
case 24 :
526
- writeIFFT<int24_t >(step_data.data (), step_size );
545
+ writeIFFT<int24_t >(step_data.data (), cfg. stride );
527
546
break ;
528
547
case 32 :
529
- writeIFFT<int32_t >(step_data.data (), step_size );
548
+ writeIFFT<int32_t >(step_data.data (), cfg. stride );
530
549
break ;
531
550
default :
532
551
LOGE (" Unsupported bits: %d" , cfg.bits_per_sample );
@@ -567,18 +586,10 @@ class AudioFFTBase : public AudioStream {
567
586
}
568
587
}
569
588
570
- void writeStrideBuffer (uint8_t *buffer, size_t len) {
571
- if (stride_buffer.size () > 0 ) {
572
- int available = stride_buffer.availableForWrite ();
573
- if (len > available) {
574
- // clear oldest values to make space
575
- int diff = len - available;
576
- for (int j = 0 ; j < diff; j++) {
577
- stride_buffer.read ();
578
- }
579
- }
580
- stride_buffer.writeArray (buffer, len);
581
- }
589
+ // adds samples to stride buffer, returns true if the buffer is full
590
+ bool writeStrideBuffer (uint8_t *buffer, size_t len) {
591
+ stride_buffer.writeArray (buffer, len);
592
+ return stride_buffer.isFull ();
582
593
}
583
594
584
595
bool isPowerOfTwo (uint16_t x) { return (x & (x - 1 )) == 0 ; }
0 commit comments