audioreactive: experimental options for sound processing

- micLev:  "freeze" mode - should help to prevent short "dropout" wen music is playing
- freqRMS: if set to "On", will use a different method for averaging higher frequencies. May give you more action in GEQ. Could lead to GEQ "overshooting" as Mic Profiles are not adjusted to this method.

* const.h: static json buffer (usermod settings pages) was getting tight, added some margin
This commit is contained in:
Frank
2023-03-20 14:11:12 +01:00
parent feb5542046
commit c0be44e07f
3 changed files with 50 additions and 10 deletions

View File

@@ -123,6 +123,9 @@ 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 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)
// audioreactive variables shared with FFT task
static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point
static float multAgc = 1.0f; // sample * multAgc = sampleAgc. Our AGC multiplier
@@ -264,7 +267,8 @@ constexpr uint16_t samplesFFT = 512; // Samples in an FFT batch - Thi
constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT results - only the "lower half" contains useful information.
// 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.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 LOG_256 5.54517744f // log(256)
// These are the input and output vectors. Input vectors receive computed results from FFT.
@@ -303,23 +307,27 @@ static float mapf(float x, float in_min, float in_max, float out_min, float out_
}
// compute average of several FFT resut bins
#if 1 // linear average
static float fftAddAvg(int from, int to) {
// linear average
static float fftAddAvgLin(int from, int to) {
float result = 0.0f;
for (int i = from; i <= to; i++) {
result += vReal[i];
}
return result / float(to - from + 1);
}
#else // RMS average
static float fftAddAvg(int from, int to) {
// RMS average
static float fftAddAvgRMS(int from, int to) {
double result = 0.0;
for (int i = from; i <= to; i++) {
result += vReal[i] * vReal[i];
}
return sqrtf(result / float(to - from + 1));
}
#endif
static float fftAddAvg(int from, int to) {
if (averageByRMS) return fftAddAvgRMS(from, to);
else return fftAddAvgLin(from, to);
}
#if defined(CONFIG_IDF_TARGET_ESP32C3)
constexpr bool skipSecondFFT = true;
@@ -1057,6 +1065,9 @@ class AudioReactive : public Usermod {
const float weighting = 0.2f; // Exponential filter weighting. Will be adjustable in a future release.
const float weighting2 = 0.073f; // Exponential filter weighting, for rising signal (a bit more robust against spikes)
const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function
static bool isFrozen = false;
static bool haveSilence = true;
static unsigned long lastSoundTime = 0; // for delaying un-freeze
#ifdef WLED_DISABLE_SOUND
micIn = inoise8(millis(), millis()); // Simulated analog read
@@ -1079,8 +1090,14 @@ class AudioReactive : public Usermod {
#endif
#endif
micLev += (micDataReal-micLev) / 12288.0f;
if(micIn < micLev) micLev = ((micLev * 31.0f) + micDataReal) / 32.0f; // align MicLev to lowest input signal
if ((micLevelMethod < 1) || !isFrozen) {
micLev += (micDataReal-micLev) / 12288.0f;
}
if(micIn < micLev) {
micLev = ((micLev * 31.0f) + micDataReal) / 32.0f; // align MicLev to lowest input signal
if (!haveSilence) isFrozen = true;
}
micIn -= micLev; // Let's center it to 0 now
// Using an exponential filter to smooth out the signal. We'll add controls for this in a future release.
@@ -1097,6 +1114,15 @@ class AudioReactive : public Usermod {
expAdjF = (expAdjF <= soundSquelch) ? 0: expAdjF; // simple noise gate
if ((soundSquelch == 0) && (expAdjF < 0.25f)) expAdjF = 0; // do something meaningfull when "squelch = 0"
if (expAdjF <= 0.5f)
haveSilence = true;
else {
lastSoundTime = millis();
haveSilence = false;
}
// un-freeze after 8 sec of silence
if (isFrozen && ((millis() - lastSoundTime) > 8000)) isFrozen = false;
tmpSample = expAdjF;
micIn = abs(micIn); // And get the absolute value of each sample
@@ -1962,6 +1988,10 @@ class AudioReactive : public Usermod {
cfg[F("gain")] = sampleGain;
cfg[F("AGC")] = soundAgc;
JsonObject poweruser = top.createNestedObject("experiments");
poweruser[F("freqRMS")] = averageByRMS;
poweruser[F("micLev")] = micLevelMethod;
JsonObject dynLim = top.createNestedObject("dynamics");
dynLim[F("limiter")] = limiterOn;
dynLim[F("rise")] = attackTime;
@@ -2028,6 +2058,9 @@ class AudioReactive : public Usermod {
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
configComplete &= getJsonValue(top["config"][F("AGC")], soundAgc);
configComplete &= getJsonValue(top["experiments"][F("freqRMS")], averageByRMS);
configComplete &= getJsonValue(top["experiments"][F("micLev")], micLevelMethod);
configComplete &= getJsonValue(top["dynamics"][F("limiter")], limiterOn);
configComplete &= getJsonValue(top["dynamics"][F("rise")], attackTime);
configComplete &= getJsonValue(top["dynamics"][F("fall")], decayTime);
@@ -2106,6 +2139,13 @@ class AudioReactive : public Usermod {
oappend(SET_F("addOption(dd,'Vivid',2);"));
oappend(SET_F("addOption(dd,'Lazy',3);"));
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','dynamics:limiter');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'On',1);"));

View File

@@ -367,7 +367,7 @@
#ifdef ESP8266
#define SETTINGS_STACK_BUF_SIZE 2048
#else
#define SETTINGS_STACK_BUF_SIZE 3096
#define SETTINGS_STACK_BUF_SIZE 3712 // WLEDMM added 512 bytes of margin (was 3096)
#endif
#ifdef WLED_USE_ETHERNET

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2303191
#define VERSION 2303201
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG