AR: added dynamics limiter usermod cfg options
- On/Off controls the complete feature - Rise Time and Fall Time are the minimum times (in milliseconds) for "volume" to go from 0% to 80% and back. - when "On" we also use some filtering to smooth FFTResults[]. Rise and Fall Times do not affect Frequency reactive effects otherwise.
This commit is contained in:
parent
991fad02d7
commit
d92a93f1d5
@ -27,9 +27,6 @@
|
|||||||
// #define NO_MIC_LOGGER // exclude MIC_LOGGER from SR_DEBUG
|
// #define NO_MIC_LOGGER // exclude MIC_LOGGER from SR_DEBUG
|
||||||
|
|
||||||
// hackers corner
|
// hackers corner
|
||||||
#if !defined(SOUND_DYNAMICS_LIMITER) && !defined(NO_SOUND_DYNAMICS_LIMITER)
|
|
||||||
#define SOUND_DYNAMICS_LIMITER // experimental: define to enable a dynamics limiter that avoids "sudden flashes" at onsets. Makes some effects look more "smooth and fluent"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SR_DEBUG
|
#ifdef SR_DEBUG
|
||||||
#define DEBUGSR_PRINT(x) Serial.print(x)
|
#define DEBUGSR_PRINT(x) Serial.print(x)
|
||||||
@ -64,8 +61,9 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - non
|
|||||||
static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value)
|
static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value)
|
||||||
|
|
||||||
// user settable parameters for limitSoundDynamics()
|
// user settable parameters for limitSoundDynamics()
|
||||||
static int attackTime = 80; // int: attack time in milliseconds. Default 0.1sec
|
static bool limiterOn = true; // bool: enable / disable dynamics limiter
|
||||||
static int decayTime = 1400; // int: decay time in milliseconds. Default 1.4sec
|
static uint16_t attackTime = 80; // int: attack time in milliseconds. Default 0.08sec
|
||||||
|
static uint16_t decayTime = 1400; // int: decay time in milliseconds. Default 1.40sec
|
||||||
|
|
||||||
//
|
//
|
||||||
// AGC presets
|
// AGC presets
|
||||||
@ -289,11 +287,10 @@ void FFTcode(void * parameter)
|
|||||||
//fftAvg[i] = fftCalc[i]*0.05f + 0.95f*fftAvg[i]; // will need approx 10 cycles (250ms) for converging against fftCalc[i]
|
//fftAvg[i] = fftCalc[i]*0.05f + 0.95f*fftAvg[i]; // will need approx 10 cycles (250ms) for converging against fftCalc[i]
|
||||||
|
|
||||||
// Now, let's dump it all into fftResult. Need to do this, otherwise other routines might grab fftResult values prematurely.
|
// Now, let's dump it all into fftResult. Need to do this, otherwise other routines might grab fftResult values prematurely.
|
||||||
#if !defined(SOUND_DYNAMICS_LIMITER)
|
if(limiterOn == true)
|
||||||
fftResult[i] = constrain((int)fftCalc[i], 0, 254);
|
|
||||||
#else
|
|
||||||
fftResult[i] = constrain((int)fftAvg[i], 0, 254);
|
fftResult[i] = constrain((int)fftAvg[i], 0, 254);
|
||||||
#endif
|
else
|
||||||
|
fftResult[i] = constrain((int)fftCalc[i], 0, 254);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
@ -695,11 +692,12 @@ class AudioReactive : public Usermod {
|
|||||||
*/
|
*/
|
||||||
// effects: Gravimeter, Gravcenter, Gravcentric, Noisefire, Plasmoid, Freqpixels, Freqwave, Gravfreq, (2D Swirl, 2D Waverly)
|
// effects: Gravimeter, Gravcenter, Gravcentric, Noisefire, Plasmoid, Freqpixels, Freqwave, Gravfreq, (2D Swirl, 2D Waverly)
|
||||||
void limitSampleDynamics(void) {
|
void limitSampleDynamics(void) {
|
||||||
#ifdef SOUND_DYNAMICS_LIMITER
|
|
||||||
const float bigChange = 196; // just a representative number - a large, expected sample value
|
const float bigChange = 196; // just a representative number - a large, expected sample value
|
||||||
static unsigned long last_time = 0;
|
static unsigned long last_time = 0;
|
||||||
static float last_volumeSmth = 0.0f;
|
static float last_volumeSmth = 0.0f;
|
||||||
|
|
||||||
|
if(limiterOn == false) return;
|
||||||
|
|
||||||
long delta_time = millis() - last_time;
|
long delta_time = millis() - last_time;
|
||||||
delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> sily lil hick-up
|
delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> sily lil hick-up
|
||||||
float deltaSample = volumeSmth - last_volumeSmth;
|
float deltaSample = volumeSmth - last_volumeSmth;
|
||||||
@ -717,7 +715,6 @@ class AudioReactive : public Usermod {
|
|||||||
|
|
||||||
last_volumeSmth = volumeSmth;
|
last_volumeSmth = volumeSmth;
|
||||||
last_time = millis();
|
last_time = millis();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1080,10 +1077,10 @@ class AudioReactive : public Usermod {
|
|||||||
// peak sample from last 5 seconds
|
// peak sample from last 5 seconds
|
||||||
if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) {
|
if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) {
|
||||||
sampleMaxTimer = millis();
|
sampleMaxTimer = millis();
|
||||||
maxSample5sec = (0.25 * maxSample5sec) + 0.75 *((soundAgc) ? sampleAgc : sampleAvg); // reset, with some smoothing
|
maxSample5sec = (0.15 * maxSample5sec) + 0.85 *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing
|
||||||
if (sampleAvg < 1) maxSample5sec = 0; // noise gate
|
if (sampleAvg < 1) maxSample5sec = 0; // noise gate
|
||||||
} else {
|
} else {
|
||||||
maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? sampleAgc : sampleAvg); // follow maximum
|
if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume
|
||||||
}
|
}
|
||||||
//UDP Microphone Sync - transmit mode
|
//UDP Microphone Sync - transmit mode
|
||||||
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) {
|
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) {
|
||||||
@ -1370,6 +1367,11 @@ class AudioReactive : public Usermod {
|
|||||||
cfg[F("gain")] = sampleGain;
|
cfg[F("gain")] = sampleGain;
|
||||||
cfg[F("AGC")] = soundAgc;
|
cfg[F("AGC")] = soundAgc;
|
||||||
|
|
||||||
|
JsonObject dynLim = top.createNestedObject("dynamics");
|
||||||
|
dynLim[F("Limiter")] = limiterOn;
|
||||||
|
dynLim[F("Rise")] = attackTime;
|
||||||
|
dynLim[F("Fall")] = decayTime;
|
||||||
|
|
||||||
JsonObject sync = top.createNestedObject("sync");
|
JsonObject sync = top.createNestedObject("sync");
|
||||||
sync[F("port")] = audioSyncPort;
|
sync[F("port")] = audioSyncPort;
|
||||||
sync[F("mode")] = audioSyncEnabled;
|
sync[F("mode")] = audioSyncEnabled;
|
||||||
@ -1412,6 +1414,10 @@ class AudioReactive : public Usermod {
|
|||||||
configComplete &= getJsonValue(top["cfg"][F("gain")], sampleGain);
|
configComplete &= getJsonValue(top["cfg"][F("gain")], sampleGain);
|
||||||
configComplete &= getJsonValue(top["cfg"][F("AGC")], soundAgc);
|
configComplete &= getJsonValue(top["cfg"][F("AGC")], soundAgc);
|
||||||
|
|
||||||
|
configComplete &= getJsonValue(top["dynamics"][F("Limiter")], limiterOn);
|
||||||
|
configComplete &= getJsonValue(top["dynamics"][F("Rise")], attackTime);
|
||||||
|
configComplete &= getJsonValue(top["dynamics"][F("Fall")], decayTime);
|
||||||
|
|
||||||
configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort);
|
configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort);
|
||||||
configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled);
|
configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled);
|
||||||
|
|
||||||
@ -1433,6 +1439,16 @@ class AudioReactive : public Usermod {
|
|||||||
oappend(SET_F("addOption(dd,'Normal',1);"));
|
oappend(SET_F("addOption(dd,'Normal',1);"));
|
||||||
oappend(SET_F("addOption(dd,'Vivid',2);"));
|
oappend(SET_F("addOption(dd,'Vivid',2);"));
|
||||||
oappend(SET_F("addOption(dd,'Lazy',3);"));
|
oappend(SET_F("addOption(dd,'Lazy',3);"));
|
||||||
|
|
||||||
|
oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:Limiter');"));
|
||||||
|
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||||
|
oappend(SET_F("addOption(dd,'On',1);"));
|
||||||
|
oappend(SET_F("addInfo('AudioReactive:dynamics:Limiter',0,' Limiter On ');")); // 0 is field type, 1 is actual field
|
||||||
|
//oappend(SET_F("addInfo('AudioReactive:dynamics:Rise',0,'min. ');"));
|
||||||
|
oappend(SET_F("addInfo('AudioReactive:dynamics:Rise',1,' ms <br /><i>(volume reactive FX only)</i>');"));
|
||||||
|
//oappend(SET_F("addInfo('AudioReactive:dynamics:Fall',0,'min. ');"));
|
||||||
|
oappend(SET_F("addInfo('AudioReactive:dynamics:Fall',1,' ms <br /><i>(volume reactive FX only)</i>');"));
|
||||||
|
|
||||||
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
|
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
|
||||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||||
oappend(SET_F("addOption(dd,'Send',1);"));
|
oappend(SET_F("addOption(dd,'Send',1);"));
|
||||||
|
Loading…
Reference in New Issue
Block a user