Skip to content

Commit f8b1af0

Browse files
committed
moved ifdefs to correct place, separated sample filter & FFT filter application
post FFT band pass and IIR applied to samples are now separated: I found in testing that applying the sample filter helps with aliasing into base-bands, there is no need to hard-cut the lowest frequencies after FFT.
1 parent 90637eb commit f8b1af0

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

usermods/audioreactive/audio_reactive.cpp

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,44 @@ static uint8_t maxVol = 31; // (was 10) Reasonable value for constant v
123123
static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
124124

125125
#ifdef ARDUINO_ARCH_ESP32
126+
#if !defined(UM_AUDIOREACTIVE_USE_ESPDSP_FFT) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32))
127+
#define UM_AUDIOREACTIVE_USE_ARDUINO_FFT // use ArduinoFFT library for FFT instead of ESP-IDF DSP library by default on ESP32 and S3
128+
#endif
129+
130+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0)
131+
#define UM_AUDIOREACTIVE_USE_ARDUINO_FFT // DSP FFT library is not available in ESP-IDF < 4.4
132+
#endif
133+
134+
#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
135+
#include <arduinoFFT.h> // ArduinoFFT library for FFT and window functions
136+
#else
137+
#include "dsps_fft2r.h" // ESP-IDF DSP library for FFT and window functions
138+
#ifdef FFT_PREFER_EXACT_PEAKS
139+
#include "dsps_wind_blackman_harris.h"
140+
#else
141+
#include "dsps_wind_flat_top.h"
142+
#endif
143+
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
144+
#define UM_AUDIOREACTIVE_USE_INTEGER_FFT // always use integer FFT on ESP32-S2 and ESP32-C3
145+
#endif
146+
#endif
147+
148+
// These are the input and output vectors. Input vectors receive computed results from FFT.
149+
#if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
150+
static float* valFFT = nullptr;
151+
#else
152+
static int16_t* valFFT = nullptr;
153+
#endif
154+
#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
155+
static float* vImag = nullptr; // imaginary part of FFT results
156+
#endif
157+
158+
// 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
126164

127165
// use audio source class (ESP32 specific)
128166
#include "audio_source.h"
@@ -164,51 +202,12 @@ const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; //
164202
// AGC presets end
165203

166204
static AudioSource *audioSource = nullptr;
167-
static bool useBandPassFilter = false; // if true, enables a bandpass filter 80Hz-16Khz to remove noise. Applies before FFT.
168-
205+
static bool useBandPassFilter = false; // if true, enables a hard cutoff bandpass filter. Applies after FFT.
206+
static bool useMicFilter = false; // if true, enables a IIR bandpass filter 80Hz-20Khz to remove noise. Applies before FFT.
169207
////////////////////
170208
// Begin FFT Code //
171209
////////////////////
172210

173-
#if !defined(UM_AUDIOREACTIVE_USE_ESPDSP_FFT) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32))
174-
#define UM_AUDIOREACTIVE_USE_ARDUINO_FFT // use ArduinoFFT library for FFT instead of ESP-IDF DSP library by default on ESP32 and S3
175-
#endif
176-
177-
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0)
178-
#define UM_AUDIOREACTIVE_USE_ARDUINO_FFT // DSP FFT library is not available in ESP-IDF < 4.4
179-
#endif
180-
181-
#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
182-
#include <arduinoFFT.h> // ArduinoFFT library for FFT and window functions
183-
#else
184-
#include "dsps_fft2r.h" // ESP-IDF DSP library for FFT and window functions
185-
#ifdef FFT_PREFER_EXACT_PEAKS
186-
#include "dsps_wind_blackman_harris.h"
187-
#else
188-
#include "dsps_wind_flat_top.h"
189-
#endif
190-
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
191-
#define UM_AUDIOREACTIVE_USE_INTEGER_FFT // always use integer FFT on ESP32-S2 and ESP32-C3
192-
#endif
193-
#endif
194-
195-
// These are the input and output vectors. Input vectors receive computed results from FFT.
196-
#if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
197-
static float* valFFT = nullptr;
198-
#else
199-
static int16_t* valFFT = nullptr;
200-
#endif
201-
#ifdef UM_AUDIOREACTIVE_USE_ARDUINO_FFT
202-
static float* vImag = nullptr; // imaginary part of FFT results
203-
#endif
204-
205-
// pre-computed window function
206-
#if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
207-
__attribute__((aligned(16))) float* windowFFT;
208-
#else
209-
__attribute__((aligned(16))) int16_t* windowFFT;
210-
#endif
211-
212211
// some prototypes, to ensure consistent interfaces
213212
static float fftAddAvg(int from, int to); // average of several FFT result bins
214213
void FFTcode(void * parameter); // audio processing task: read samples, run FFT, fill GEQ channels from FFT results
@@ -382,8 +381,7 @@ void FFTcode(void * parameter)
382381

383382
// band pass filter - can reduce noise floor by a factor of 50 and avoid aliasing effects to base & high frequency bands
384383
// downside: frequencies below 100Hz will be ignored
385-
if (useBandPassFilter) runMicFilter(samplesFFT, valFFT);
386-
384+
if (useMicFilter) runMicFilter(samplesFFT, valFFT);
387385
// find highest sample in the batch
388386
#if !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
389387
float maxSample = 0.0f; // max sample from FFT batch
@@ -1400,7 +1398,8 @@ class AudioReactive : public Usermod {
14001398
periph_module_reset(PERIPH_I2S0_MODULE); // not possible on -C3
14011399
#endif
14021400
delay(100); // Give that poor microphone some time to setup.
1403-
useBandPassFilter = true; // filter fixes aliasing to base & highest frequency bands and reduces noise floor (use for all mic inputs)
1401+
useBandPassFilter = false; // filter cuts lowest and highest frequency bands from FFT result (use on very noisy mic inputs)
1402+
useMicFilter = true; // filter fixes aliasing to base & highest frequency bands and reduces noise floor (recommended for all mic inputs)
14041403

14051404
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
14061405
if ((i2sckPin == I2S_PIN_NO_CHANGE) && (i2ssdPin >= 0) && (i2swsPin >= 0) && ((dmType == 1) || (dmType == 4)) ) dmType = 5; // dummy user support: SCK == -1 --means--> PDM microphone
@@ -1435,21 +1434,23 @@ class AudioReactive : public Usermod {
14351434
case 4:
14361435
DEBUGSR_PRINT(F("AR: Generic I2S Microphone with Master Clock - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
14371436
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/24.0f);
1437+
useMicFilter = false; // I2S with Master Clock is mostly used for line-in, skip sample filtering
14381438
delay(100);
14391439
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
14401440
break;
14411441
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
14421442
case 5:
14431443
DEBUGSR_PRINT(F("AR: I2S PDM Microphone - ")); DEBUGSR_PRINTLN(F(I2S_PDM_MIC_CHANNEL_TEXT));
14441444
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/4.0f);
1445+
useBandPassFilter = true; // this reduces the noise floor on SPM1423 from 5% Vpp (~380) down to 0.05% Vpp (~5)
14451446
delay(100);
14461447
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
14471448
break;
14481449
#endif
14491450
case 6:
14501451
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
14511452
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
1452-
useBandPassFilter = false;
1453+
useMicFilter = false;
14531454
delay(100);
14541455
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
14551456
break;

0 commit comments

Comments
 (0)