@@ -133,6 +133,7 @@ static uint8_t binNum = 8; // Used to select the bin for FFT based bea
133133
134134#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
135135#include < arduinoFFT.h> // ArduinoFFT library for FFT and window functions
136+ #undef UM_AUDIOREACTIVE_USE_INTEGER_FFT // arduinoFFT has not integer support
136137#else
137138#include " dsps_fft2r.h" // ESP-IDF DSP library for FFT and window functions
138139#ifdef FFT_PREFER_EXACT_PEAKS
@@ -145,22 +146,23 @@ static uint8_t binNum = 8; // Used to select the bin for FFT based bea
145146#endif
146147#endif
147148
148- // These are the input and output vectors. Input vectors receive computed results from FFT.
149149#if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
150- static float * valFFT = nullptr ;
150+ using FFTsampleType = float ;
151+ using FFTmathType = float ;
152+ #define FFTabs fabsf
151153#else
152- static int16_t * valFFT = nullptr ;
154+ using FFTsampleType = int16_t ;
155+ using FFTmathType = int32_t ;
156+ #define FFTabs abs
153157#endif
158+ // These are the input and output vectors. Input vectors receive computed results from FFT.
159+ static FFTsampleType* valFFT = nullptr ;
154160#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
155161static float * vImag = nullptr ; // imaginary part of FFT results
156162#endif
157163
158164// pre-computed window function
159- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
160- __attribute__ ((aligned(16 ))) float* windowFFT;
161- #else
162- __attribute__ ((aligned(16 ))) int16_t* windowFFT;
163- #endif
165+ FFTsampleType* windowFFT;
164166
165167// use audio source class (ESP32 specific)
166168#include " audio_source.h"
@@ -211,11 +213,7 @@ static bool useMicFilter = false; // if true, enables a
211213// some prototypes, to ensure consistent interfaces
212214static float fftAddAvg (int from, int to); // average of several FFT result bins
213215void FFTcode (void * parameter); // audio processing task: read samples, run FFT, fill GEQ channels from FFT results
214- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
215- static void runMicFilter (uint16_t numSamples, float *sampleBuffer); // pre-filtering of raw samples (band-pass)
216- #else
217- static void runMicFilter (uint16_t numSamples, int16_t *sampleBuffer);
218- #endif
216+ static void runMicFilter (uint16_t numSamples, FFTsampleType *sampleBuffer);
219217static void postProcessFFTResults (bool noiseGateOpen, int numberOfChannels); // post-processing and post-amp of GEQ channels
220218
221219static TaskHandle_t FFT_Task = nullptr ;
@@ -270,18 +268,15 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul
270268
271269// compute average of several FFT result bins
272270static float fftAddAvg (int from, int to) {
273- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
274- float result = 0 .0f ;
271+ FFTmathType result = 0 ;
275272 for (int i = from; i <= to; i++) {
276273 result += valFFT[i];
277274 }
278- #else
279- int32_t result = 0 ;
280- for (int i = from; i <= to; i++) {
281- result += valFFT[i];
282- }
283- result *= 32 ; // scale result to match float values. note: scaling value between float and int is 512, float version is scaled down by 16
284- #endif
275+ #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
276+ result = result * 0.0625 ; // divide by 16 to reduce magnitude. Want end result to be scaled linear and ~4096 max.
277+ #else
278+ result *= 32 ; // scale result to match float values. note: raw scaling value between float and int is 512, float version is scaled down by 16
279+ #endif
285280 return float (result) / float (to - from + 1 ); // return average as float
286281}
287282
@@ -383,21 +378,12 @@ void FFTcode(void * parameter)
383378 // downside: frequencies below 100Hz will be ignored
384379 if (useMicFilter) runMicFilter (samplesFFT, valFFT);
385380 // find highest sample in the batch
386- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
387- float maxSample = 0 .0f ; // max sample from FFT batch
388- for (int i=0 ; i < samplesFFT; i++) {
389- // pick our our current mic sample - we take the max value from all samples that go into FFT
390- if ((valFFT[i] <= (INT16_MAX - 1024 )) && (valFFT[i] >= (INT16_MIN + 1024 ))) // skip extreme values - normally these are artefacts
391- if (fabsf ((float )valFFT[i]) > maxSample) maxSample = fabsf ((float )valFFT[i]);
392- }
393- #else
394- int32_t maxSample = 0 ; // max sample from FFT batch
381+ FFTsampleType maxSample = 0 ; // max sample from FFT batch
395382 for (int i=0 ; i < samplesFFT; i++) {
396383 // pick our our current mic sample - we take the max value from all samples that go into FFT
397384 if ((valFFT[i] <= (INT16_MAX - 1024 )) && (valFFT[i] >= (INT16_MIN + 1024 ))) // skip extreme values - normally these are artefacts
398- if (abs (valFFT[i]) > maxSample) maxSample = abs (valFFT[i]);
385+ if (FFTabs (valFFT[i]) > maxSample) maxSample = FFTabs (valFFT[i]);
399386 }
400- #endif
401387 // release highest sample to volume reactive effects early - not strictly necessary here - could also be done at the end of the function
402388 // early release allows the filters (getSample() and agcAvg()) to work with fresh values - we will have matching gain and noise gate values when we want to process the FFT results.
403389 micDataReal = maxSample;
@@ -421,16 +407,15 @@ void FFTcode(void * parameter)
421407 FFT.complexToMagnitude (); // Compute magnitudes
422408 valFFT[0 ] = 0 ; // The remaining DC offset on the signal produces a strong spike on position 0 that should be eliminated to avoid issues.
423409 FFT.majorPeak (&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant
424- for (int i = 1 ; i < samplesFFT_2; i++) { // skip [0] as it is DC offset
425- valFFT[i] = valFFT[i] / 16 .0f ; // Reduce magnitude. Want end result to be scaled linear and ~4096 max.
426- }
427- #elif !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
410+ // note: scaling is done in fftAddAvg(), so we don't scale here
411+ #else
428412 // run run float DSP FFT (takes ~x ms on ESP32, ~x ms on ESP32-S2, , ~x ms on ESP32-C3) TODO: test and fill in these values
429413 // remove DC offset
430- float sum = 0 ;
414+ FFTmathType sum = 0 ;
431415 for (int i = 0 ; i < samplesFFT; i++) sum += valFFT[i];
432- float mean = sum / samplesFFT;
416+ FFTmathType mean = sum / (FFTmathType) samplesFFT;
433417 for (int i = 0 ; i < samplesFFT; i++) valFFT[i] -= mean;
418+ #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
434419 // apply window function to samples and fill buffer with interleaved complex values [Re,Im,Re,Im,...]
435420 for (int i = samplesFFT - 1 ; i >= 0 ; i--) {
436421 // fill the buffer back to front to avoid overwriting samples
@@ -458,15 +443,10 @@ void FFTcode(void * parameter)
458443 FFT_Magnitude = valFFT[i];
459444 FFT_MajorPeak = i*(SAMPLE_RATE/samplesFFT);
460445 }
461- valFFT[i] = valFFT[i] / 16 . 0f ; // Reduce magnitude. Want end result to be scaled linear and ~4096 max.
446+ // note: scaling is done in fftAddAvg(), so we don't scale here
462447 }
463448#else
464449 // run integer DSP FFT (takes ~x ms on ESP32, ~x ms on ESP32-S2, , ~1.5 ms on ESP32-C3) TODO: test and fill in these values
465- // remove DC offset
466- int32_t sum = 0 ;
467- for (int i = 0 ; i < samplesFFT; i++) sum += valFFT[i];
468- int32_t mean = sum / samplesFFT;
469- for (int i = 0 ; i < samplesFFT; i++) valFFT[i] -= mean;
470450 // apply window function to samples and fill buffer with interleaved complex values [Re,Im,Re,Im,...]
471451 for (int i = samplesFFT - 1 ; i >= 0 ; i--) {
472452 // fill the buffer back to front to avoid overwriting samples
@@ -488,23 +468,18 @@ void FFTcode(void * parameter)
488468 FFT_Magnitude_int = valFFT[i] * 512 ; // scale to match raw float value
489469 FFT_MajorPeak_int = ((i * SAMPLE_RATE)/samplesFFT);
490470 }
491- // note: scaling is done when converting to float in fftAddAvg(), so we don't scale here
471+ // note: scaling is done in fftAddAvg(), so we don't scale here
492472 }
493473 FFT_MajorPeak = FFT_MajorPeak_int;
494474 FFT_Magnitude = FFT_Magnitude_int;
495-
475+ # endif
496476#endif
497477 FFT_MajorPeak = constrain (FFT_MajorPeak, 1 .0f , 11025 .0f ); // restrict value to range expected by effects
498478#if defined(WLED_DEBUG) || defined(SR_DEBUG)
499479 haveDoneFFT = true ;
500480#endif
501- } else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this.
502- // only lower half of buffer contains FFT results, so only clear that part
503- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
504- memset (valFFT, 0 , samplesFFT * sizeof (float ));
505- #else
506- memset (valFFT, 0 , samplesFFT * sizeof (int16_t ));
507- #endif
481+ } else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this -> set all samples to 0
482+ memset (valFFT, 0 , samplesFFT * sizeof (FFTsampleType));
508483 FFT_MajorPeak = 1 ;
509484 FFT_Magnitude = 0.001 ;
510485 }
@@ -601,9 +576,9 @@ void FFTcode(void * parameter)
601576// Pre / Postprocessing //
602577// /////////////////////////
603578
604- #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
605- static void runMicFilter (uint16_t numSamples, float *sampleBuffer) // pre-filtering of raw samples (band-pass)
579+ static void runMicFilter (uint16_t numSamples, FFTsampleType *sampleBuffer) // pre-filtering of raw samples (band-pass)
606580{
581+ #if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
607582 // low frequency cutoff parameter - see https://dsp.stackexchange.com/questions/40462/exponential-moving-average-cut-off-frequency (alpha = 2π × fc / fs)
608583 // constexpr float alpha = 0.04f; // 150Hz
609584 // constexpr float alpha = 0.03f; // 110Hz
@@ -633,10 +608,7 @@ static void runMicFilter(uint16_t numSamples, float *sampleBuffer) // p
633608 lowfilt += alpha * (sampleBuffer[i] - lowfilt);
634609 sampleBuffer[i] = sampleBuffer[i] - lowfilt;
635610 }
636- }
637611#else
638- static void runMicFilter (uint16_t numSamples, int16_t *sampleBuffer) // pre-filtering of raw samples (band-pass)
639- {
640612 // low frequency cutoff parameter 17.15 fixed point format
641613 // constexpr int32_t ALPHA_FP = 1311; // 0.04f * (1<<15) (150Hz)
642614 // constexpr int32_t ALPHA_FP = 983; // 0.03f * (1<<15) (110Hz)
0 commit comments