low-cut audio input filtering
* 40Hz low-cut and DC blocker filter - will remove any signal offsets and also removes rumbling noise up to 12db * DC blocker set as default for all sources (prerequisite for later measuring sound pressure) additional filtering options are in the making :-)
This commit is contained in:
@@ -121,7 +121,7 @@ const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; //
|
||||
|
||||
static AudioSource *audioSource = nullptr;
|
||||
static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks.
|
||||
static bool useBandPassFilter = false; // if true, enables a bandpass filter 80Hz-16Khz to remove noise. Applies before FFT.
|
||||
static uint8_t useInputFilter = 0; // enables low-cut filtering. Applies before FFT.
|
||||
|
||||
//WLEDMM add experimental settings
|
||||
static uint8_t micLevelMethod = 0; // 0=old "floating" miclev, 1=new "freeze" mode, 2=fast freeze mode (mode 2 may not work for you)
|
||||
@@ -183,7 +183,7 @@ static TaskHandle_t FFT_Task = nullptr;
|
||||
static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = {
|
||||
{ 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f }, // 0 default from SR WLED
|
||||
// { 1.30f, 1.32f, 1.40f, 1.46f, 1.52f, 1.57f, 1.68f, 1.80f, 1.89f, 2.00f, 2.11f, 2.21f, 2.30f, 2.39f, 3.09f, 4.34f }, // - Line-In Generic -> pink noise adjustment only
|
||||
{ 1.24f, 1.20f, 1.30f, 1.40f, 1.48f, 1.57f, 1.68f, 1.80f, 1.89f, 2.00f, 2.14f, 2.26f, 2.60f, 3.00f, 3.70f, 5.20f }, // 1 Line-In CS5343
|
||||
{ 2.35f, 1.32f, 1.32f, 1.40f, 1.48f, 1.57f, 1.68f, 1.80f, 1.89f, 1.95f, 2.14f, 2.26f, 2.50f, 2.90f, 4.20f, 6.50f }, // 1 Line-In CS5343 + DC blocker
|
||||
|
||||
{ 1.82f, 1.72f, 1.70f, 1.50f, 1.52f, 1.57f, 1.68f, 1.80f, 1.89f, 2.00f, 2.11f, 2.21f, 2.30f, 2.90f, 3.86f, 6.29f}, // 2 IMNP441 datasheet response profile * pink noise
|
||||
{ 2.80f, 2.20f, 1.30f, 1.15f, 1.55f, 2.45f, 4.20f, 2.80f, 3.20f, 3.60f, 4.20f, 4.90f, 5.70f, 6.05f,10.50f,14.85f}, // 3 IMNP441 - big speaker, strong bass
|
||||
@@ -341,6 +341,23 @@ constexpr bool skipSecondFFT = true;
|
||||
#else
|
||||
constexpr bool skipSecondFFT = false;
|
||||
#endif
|
||||
|
||||
// High-Pass "DC blocker" filter
|
||||
// see https://www.dsprelated.com/freebooks/filters/DC_Blocker.html
|
||||
static void runDCBlocker(uint_fast16_t numSamples, float *sampleBuffer) {
|
||||
constexpr float filterR = 0.990f; // around 40hz
|
||||
static float xm1 = 0.0f;
|
||||
static float ym1 = 0.0f;
|
||||
|
||||
for (unsigned i=0; i < numSamples; i++) {
|
||||
float value = sampleBuffer[i];
|
||||
float filtered = value-xm1 + filterR*ym1;
|
||||
xm1 = value;
|
||||
ym1 = filtered;
|
||||
sampleBuffer[i] = filtered;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FFT main task
|
||||
//
|
||||
@@ -410,7 +427,12 @@ void FFTcode(void * parameter)
|
||||
|
||||
// band pass filter - can reduce noise floor by a factor of 50
|
||||
// downside: frequencies below 100Hz will be ignored
|
||||
if (useBandPassFilter) runMicFilter(samplesFFT, vReal);
|
||||
if ((useInputFilter > 0) && (useInputFilter < 99)) {
|
||||
switch(useInputFilter) {
|
||||
case 1: runMicFilter(samplesFFT, vReal); break; // PDM microphone bandpass
|
||||
case 2: runDCBlocker(samplesFFT, vReal); break; // generic Low-Cut + DC blocker (~40hz cut-off)
|
||||
}
|
||||
}
|
||||
|
||||
// find highest sample in the batch
|
||||
float maxSample = 0.0f; // max sample from FFT batch
|
||||
@@ -531,7 +553,7 @@ void FFTcode(void * parameter)
|
||||
if (freqDist == 0) {
|
||||
/* new mapping, optimized for 22050 Hz by softhack007 --- update: removed overlap */
|
||||
// bins frequency range
|
||||
if (useBandPassFilter) {
|
||||
if (useInputFilter==1) {
|
||||
// skip frequencies below 100hz
|
||||
fftCalc[ 0] = 0.8f * fftAddAvg(3,3);
|
||||
fftCalc[ 1] = 0.9f * fftAddAvg(4,4);
|
||||
@@ -560,7 +582,7 @@ void FFTcode(void * parameter)
|
||||
fftCalc[14] = fftAddAvg(104,164) * 0.88f; // 61 4479 - 7106 high mid + high -- with slight damping
|
||||
}
|
||||
else if (freqDist == 1) { //WLEDMM: Rightshft: note ewowi: frequencies in comments are not correct
|
||||
if (useBandPassFilter) {
|
||||
if (useInputFilter==1) {
|
||||
// skip frequencies below 100hz
|
||||
fftCalc[ 0] = 0.8f * fftAddAvg(1,1);
|
||||
fftCalc[ 1] = 0.9f * fftAddAvg(2,2);
|
||||
@@ -1429,7 +1451,7 @@ class AudioReactive : public Usermod {
|
||||
#endif
|
||||
delay(100); // Give that poor microphone some time to setup.
|
||||
|
||||
useBandPassFilter = false;
|
||||
useInputFilter = 2; // default: DC blocker
|
||||
switch (dmType) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// stub cases for not-yet-supported I2S modes on other ESP32 chips
|
||||
@@ -1447,7 +1469,7 @@ class AudioReactive : public Usermod {
|
||||
break;
|
||||
case 2:
|
||||
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
||||
//useBandPassFilter = true;
|
||||
//useInputFilter = 0; // in case you need to disable low-cut software filtering
|
||||
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
@@ -1460,7 +1482,6 @@ class AudioReactive : public Usermod {
|
||||
break;
|
||||
case 4:
|
||||
DEBUGSR_PRINT(F("AR: Generic I2S Microphone with Master Clock - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
||||
//useBandPassFilter = true;
|
||||
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/24.0f);
|
||||
//audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/24.0f, false); // I2S SLAVE mode - does not work, unfortunately
|
||||
delay(100);
|
||||
@@ -1470,21 +1491,22 @@ class AudioReactive : public Usermod {
|
||||
case 5:
|
||||
DEBUGSR_PRINT(F("AR: I2S PDM Microphone - ")); DEBUGSR_PRINTLN(F(I2S_PDM_MIC_CHANNEL_TEXT));
|
||||
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/4.0f);
|
||||
useBandPassFilter = true; // this reduces the noise floor on SPM1423 from 5% Vpp (~380) down to 0.05% Vpp (~5)
|
||||
useInputFilter = 1; // PDM bandpass filter - this reduces the noise floor on SPM1423 from 5% Vpp (~380) down to 0.05% Vpp (~5)
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
|
||||
break;
|
||||
case 51:
|
||||
DEBUGSR_PRINT(F("AR: Legacy PDM Microphone - ")); DEBUGSR_PRINTLN(F(I2S_PDM_MIC_CHANNEL_TEXT));
|
||||
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f);
|
||||
useBandPassFilter = true;
|
||||
useInputFilter = 1; // PDM bandpass filter
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
|
||||
break;
|
||||
#endif
|
||||
case 6:
|
||||
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
|
||||
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
|
||||
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f);
|
||||
//useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||
break;
|
||||
@@ -1494,7 +1516,7 @@ class AudioReactive : public Usermod {
|
||||
case 0:
|
||||
default:
|
||||
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
|
||||
useBandPassFilter = true;
|
||||
useInputFilter = 1; // PDM bandpass filter seems to work well for analog, too
|
||||
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
|
||||
delay(100);
|
||||
if (audioSource) audioSource->initialize(audioPin);
|
||||
@@ -2102,8 +2124,8 @@ class AudioReactive : public Usermod {
|
||||
if (dmType == 51) dmType = SR_DMTYPE; // MCU does not support legacy PDM
|
||||
#endif
|
||||
#else
|
||||
if (dmType == 5) useBandPassFilter = true; // enable filter for PDM
|
||||
if (dmType == 51) useBandPassFilter = true /*false*/; // switch on filter for legacy PDM
|
||||
if (dmType == 5) useInputFilter = 1; // enable filter for PDM
|
||||
if (dmType == 51) useInputFilter = 1; // switch on filter for legacy PDM
|
||||
#endif
|
||||
|
||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][0], i2ssdPin);
|
||||
|
||||
Reference in New Issue
Block a user