From fc9f3a1c24cd9d73810f20770cdd73de15b7548b Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 20 Mar 2023 21:43:58 +0100 Subject: [PATCH] audio processing: minor updates - small optimizations - remove overlapping in fft bin -> geq channel mapping - move "freqRMS" to last position in the UI list --- usermods/audioreactive/audio_reactive.h | 65 +++++++++++++------------ wled00/const.h | 2 +- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index df693f24..bc7a4660 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -124,8 +124,12 @@ static volatile bool disableSoundProcessing = false; // if true, sound proc static bool useBandPassFilter = false; // if true, enables a bandpass filter 80Hz-16Khz to remove noise. Applies before FFT. //WLEDMM add experimental settings -static uint8_t micLevelMethod = 0; // 0=old "floating" miclev, 1=new "freeze" mode -static uint8_t averageByRMS = false; // false: use mean value, true: use RMS (root mean squared) +static uint8_t micLevelMethod = 1; // 0=old "floating" miclev, 1=new "freeze" mode +#if defined(CONFIG_IDF_TARGET_ESP32S2) || !defined(CONFIG_IDF_TARGET_ESP32C3) +static uint8_t averageByRMS = false; // false: use mean value, true: use RMS (root mean squared). use simpler method on slower MCUs. +#else +static uint8_t averageByRMS = true; // false: use mean value, true: use RMS (root mean squared). use better method on fast MCUs. +#endif static uint8_t freqDist = 0; // 0=old 1=rightshift mode // audioreactive variables shared with FFT task @@ -270,7 +274,7 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul // the following are observed values, supported by a bit of "educated guessing" //#define FFT_DOWNSCALE 0.65f // 20kHz - downscaling factor for FFT results - "Flat-Top" window @20Khz, old freq channels //#define FFT_DOWNSCALE 0.46f // downscaling factor for FFT results - for "Flat-Top" window @22Khz, new freq channels -#define FFT_DOWNSCALE 0.40f // downscaling factor for FFT results, RMS averaging +#define FFT_DOWNSCALE 0.36f // downscaling factor for FFT results, RMS averaging #define LOG_256 5.54517744f // log(256) // These are the input and output vectors. Input vectors receive computed results from FFT. @@ -327,8 +331,9 @@ static float fftAddAvgRMS(int from, int to) { } static float fftAddAvg(int from, int to) { - if (averageByRMS) return fftAddAvgRMS(from, to); - else return fftAddAvgLin(from, to); + if (from == to) return vReal[from]; // small optimization + if (averageByRMS) return fftAddAvgRMS(from, to); // use SMS + else return fftAddAvgLin(from, to); // use linear average } #if defined(CONFIG_IDF_TARGET_ESP32C3) @@ -524,35 +529,35 @@ void FFTcode(void * parameter) #else //WLEDMM: different distributions if (freqDist == 0) { - /* new mapping, optimized for 22050 Hz by softhack007 */ + /* new mapping, optimized for 22050 Hz by softhack007 --- update: removed overlap */ // bins frequency range if (useBandPassFilter) { // skip frequencies below 100hz - fftCalc[ 0] = 0.8f * fftAddAvg(3,4); - fftCalc[ 1] = 0.9f * fftAddAvg(4,5); - fftCalc[ 2] = fftAddAvg(5,6); - fftCalc[ 3] = fftAddAvg(6,7); + fftCalc[ 0] = 0.8f * fftAddAvg(3,3); + fftCalc[ 1] = 0.9f * fftAddAvg(4,4); + fftCalc[ 2] = fftAddAvg(5,5); + fftCalc[ 3] = fftAddAvg(6,6); // don't use the last bins from 206 to 255. fftCalc[15] = fftAddAvg(165,205) * 0.75f; // 40 7106 - 8828 high -- with some damping } else { - fftCalc[ 0] = fftAddAvg(1,2); // 1 43 - 86 sub-bass - fftCalc[ 1] = fftAddAvg(2,3); // 1 86 - 129 bass - fftCalc[ 2] = fftAddAvg(3,5); // 2 129 - 216 bass - fftCalc[ 3] = fftAddAvg(5,7); // 2 216 - 301 bass + midrange + fftCalc[ 0] = fftAddAvg(1,1); // 1 43 - 86 sub-bass + fftCalc[ 1] = fftAddAvg(2,2); // 1 86 - 129 bass + fftCalc[ 2] = fftAddAvg(3,4); // 2 129 - 216 bass + fftCalc[ 3] = fftAddAvg(5,6); // 2 216 - 301 bass + midrange // don't use the last bins from 216 to 255. They are usually contaminated by aliasing (aka noise) fftCalc[15] = fftAddAvg(165,215) * 0.70f; // 50 7106 - 9259 high -- with some damping } - fftCalc[ 4] = fftAddAvg(7,10); // 3 301 - 430 midrange - fftCalc[ 5] = fftAddAvg(10,13); // 3 430 - 560 midrange - fftCalc[ 6] = fftAddAvg(13,19); // 5 560 - 818 midrange - fftCalc[ 7] = fftAddAvg(19,26); // 7 818 - 1120 midrange -- 1Khz should always be the center ! - fftCalc[ 8] = fftAddAvg(26,33); // 7 1120 - 1421 midrange - fftCalc[ 9] = fftAddAvg(33,44); // 9 1421 - 1895 midrange - fftCalc[10] = fftAddAvg(44,56); // 12 1895 - 2412 midrange + high mid - fftCalc[11] = fftAddAvg(56,70); // 14 2412 - 3015 high mid - fftCalc[12] = fftAddAvg(70,86); // 16 3015 - 3704 high mid - fftCalc[13] = fftAddAvg(86,104); // 18 3704 - 4479 high mid - fftCalc[14] = fftAddAvg(104,165) * 0.88f; // 61 4479 - 7106 high mid + high -- with slight damping + fftCalc[ 4] = fftAddAvg(7,9); // 3 301 - 430 midrange + fftCalc[ 5] = fftAddAvg(10,12); // 3 430 - 560 midrange + fftCalc[ 6] = fftAddAvg(13,18); // 5 560 - 818 midrange + fftCalc[ 7] = fftAddAvg(19,25); // 7 818 - 1120 midrange -- 1Khz should always be the center ! + fftCalc[ 8] = fftAddAvg(26,32); // 7 1120 - 1421 midrange + fftCalc[ 9] = fftAddAvg(33,43); // 9 1421 - 1895 midrange + fftCalc[10] = fftAddAvg(44,55); // 12 1895 - 2412 midrange + high mid + fftCalc[11] = fftAddAvg(56,69); // 14 2412 - 3015 high mid + fftCalc[12] = fftAddAvg(70,85); // 16 3015 - 3704 high mid + fftCalc[13] = fftAddAvg(86,103); // 18 3704 - 4479 high mid + 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) { @@ -2024,9 +2029,9 @@ class AudioReactive : public Usermod { //WLEDMM: experimental settings JsonObject poweruser = top.createNestedObject("experiments"); - poweruser[F("freqRMS")] = averageByRMS; poweruser[F("micLev")] = micLevelMethod; poweruser[F("freqDist")] = freqDist; + poweruser[F("freqRMS")] = averageByRMS; JsonObject dynLim = top.createNestedObject("dynamics"); dynLim[F("limiter")] = limiterOn; @@ -2095,9 +2100,9 @@ class AudioReactive : public Usermod { configComplete &= getJsonValue(top["config"][F("AGC")], soundAgc); //WLEDMM: experimental settings - configComplete &= getJsonValue(top["experiments"][F("freqRMS")], averageByRMS); configComplete &= getJsonValue(top["experiments"][F("micLev")], micLevelMethod); configComplete &= getJsonValue(top["experiments"][F("freqDist")], freqDist); + configComplete &= getJsonValue(top["experiments"][F("freqRMS")], averageByRMS); configComplete &= getJsonValue(top["dynamics"][F("limiter")], limiterOn); configComplete &= getJsonValue(top["dynamics"][F("rise")], attackTime); @@ -2181,12 +2186,12 @@ class AudioReactive : public Usermod { oappend(SET_F("dd=addDropdown('AudioReactive','experiments:micLev');")); oappend(SET_F("addOption(dd,'Floating (⎌)',0);")); oappend(SET_F("addOption(dd,'Freeze',1);")); - oappend(SET_F("dd=addDropdown('AudioReactive','experiments:freqRMS');")); - oappend(SET_F("addOption(dd,'Off (⎌)',0);")); - oappend(SET_F("addOption(dd,'On',1);")); oappend(SET_F("dd=addDropdown('AudioReactive','experiments:freqDist');")); oappend(SET_F("addOption(dd,'Normal (⎌)',0);")); oappend(SET_F("addOption(dd,'RightShift',1);")); + oappend(SET_F("dd=addDropdown('AudioReactive','experiments:freqRMS');")); + oappend(SET_F("addOption(dd,'Off (⎌)',0);")); + oappend(SET_F("addOption(dd,'On',1);")); oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');")); oappend(SET_F("addOption(dd,'Off',0);")); diff --git a/wled00/const.h b/wled00/const.h index 9b0be676..922d9ffc 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -363,7 +363,7 @@ #define MAX_LEDS_PER_BUS 2048 // may not be enough for fast LEDs (i.e. APA102) #endif -// string temp buffer (now stored in stack locally) +// string temp buffer (now stored in stack locally) // WLEDMM ...which is actually not the greatest design choice on ESP32 #ifdef ESP8266 #define SETTINGS_STACK_BUF_SIZE 2048 #else