Merge branch 'mdev' into ES8388

This commit is contained in:
Will Tatam
2023-04-03 19:20:41 +01:00
115 changed files with 8166 additions and 11703 deletions

View File

@@ -29,9 +29,9 @@
// #define SR_DEBUG // generic SR DEBUG messages
#ifdef SR_DEBUG
#define DEBUGSR_PRINT(x) DEBUGOUT.print(x)
#define DEBUGSR_PRINTLN(x) DEBUGOUT.println(x)
#define DEBUGSR_PRINTF(x...) DEBUGOUT.printf(x)
#define DEBUGSR_PRINT(x) DEBUGOUT(x)
#define DEBUGSR_PRINTLN(x) DEBUGOUTLN(x)
#define DEBUGSR_PRINTF(x...) DEBUGOUTF(x)
#else
#define DEBUGSR_PRINT(x)
#define DEBUGSR_PRINTLN(x)
@@ -55,10 +55,10 @@
#endif
#if defined(MIC_LOGGER) || defined(FFT_SAMPLING_LOG)
#define PLOT_PRINT(x) DEBUGOUT.print(x)
#define PLOT_PRINTLN(x) DEBUGOUT.println(x)
#define PLOT_PRINTF(x...) DEBUGOUT.printf(x)
#define PLOT_FLUSH() DEBUGOUT.flush()
#define PLOT_PRINT(x) DEBUGOUT(x)
#define PLOT_PRINTLN(x) DEBUGOUTLN(x)
#define PLOT_PRINTF(x...) DEBUGOUTF(x)
#define PLOT_FLUSH() DEBUGOUTFlush()
#else
#define PLOT_PRINT(x)
#define PLOT_PRINTLN(x)
@@ -123,6 +123,15 @@ 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.
//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)
#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
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
@@ -136,7 +145,7 @@ static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending
// peak detection
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
static uint8_t maxVol = 31; // (was 10) Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
@@ -182,7 +191,7 @@ static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = {
{ 12.0f, 6.60f, 2.60f, 1.15f, 1.35f, 2.05f, 2.85f, 2.50f, 2.85f, 3.30f, 2.25f, 4.35f, 3.80f, 3.75f, 6.50f, 9.00f}, // 4 IMNP441 - voice, or small speaker
{ 2.75f, 1.60f, 1.40f, 1.46f, 1.52f, 1.57f, 1.68f, 1.80f, 1.89f, 2.00f, 2.11f, 2.21f, 2.30f, 1.75f, 2.55f, 3.60f }, // 5 ICS-43434 datasheet response * pink noise
{ 2.25f, 1.20f, 1.00f, 1.20f, 1.80f, 3.20f, 5.10f, 5.50f, 4.00f, 4.80f, 6.70f, 6.40f, 5.80f, 3.90f, 6.00f, 5.10f }, // 6 ICS-43434 - big speaker, strong bass
{ 2.90f, 1.25f, 0.75f, 1.08f, 2.35f, 3.55f, 3.60f, 3.40f, 2.75f, 3.45f, 4.40f, 6.35f, 6.80f, 6.80f, 8.50f,10.64f }, // 6 ICS-43434 - big speaker, strong bass
{ 1.65f, 1.00f, 1.05f, 1.30f, 1.48f, 1.30f, 1.80f, 3.00f, 1.50f, 1.65f, 2.56f, 3.00f, 2.60f, 2.30f, 5.00f, 3.00f }, // 7 SPM1423
{ 2.25f, 1.60f, 1.30f, 1.60f, 2.20f, 3.20f, 3.06f, 2.60f, 2.85f, 3.50f, 4.10f, 4.80f, 5.70f, 6.05f,10.50f,14.85f }, // 8 userdef #1 for ewowi (enhance median/high freqs)
@@ -264,7 +273,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 +313,28 @@ 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 (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)
constexpr bool skipSecondFFT = true;
@@ -512,35 +527,67 @@ void FFTcode(void * parameter)
fftCalc[14] = fftAddAvg(147,194); // 2940 - 3900
fftCalc[15] = fftAddAvg(194,250); // 3880 - 5000 // avoid the last 5 bins, which are usually inaccurate
#else
/* new mapping, optimized for 22050 Hz by softhack007 */
//WLEDMM: different distributions
if (freqDist == 0) {
/* 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) {
// skip frequencies below 100hz
fftCalc[ 0] = 0.8f * fftAddAvg(1,1);
fftCalc[ 1] = 0.9f * fftAddAvg(2,2);
fftCalc[ 2] = fftAddAvg(3,3);
fftCalc[ 3] = fftAddAvg(4,4);
// 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,1); // 1 43 - 86 sub-bass
fftCalc[ 1] = fftAddAvg(2,2); // 1 86 - 129 bass
fftCalc[ 2] = fftAddAvg(3,3); // 2 129 - 216 bass
fftCalc[ 3] = fftAddAvg(4,4); // 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(5,6); // 3 301 - 430 midrange
fftCalc[ 5] = fftAddAvg(7,8); // 3 430 - 560 midrange
fftCalc[ 6] = fftAddAvg(9,10); // 5 560 - 818 midrange
fftCalc[ 7] = fftAddAvg(11,13); // 7 818 - 1120 midrange -- 1Khz should always be the center !
fftCalc[ 8] = fftAddAvg(14,18); // 7 1120 - 1421 midrange
fftCalc[ 9] = fftAddAvg(19,25); // 9 1421 - 1895 midrange
fftCalc[10] = fftAddAvg(26,36); // 12 1895 - 2412 midrange + high mid
fftCalc[11] = fftAddAvg(37,45); // 14 2412 - 3015 high mid
fftCalc[12] = fftAddAvg(46,66); // 16 3015 - 3704 high mid
fftCalc[13] = fftAddAvg(67,97); // 18 3704 - 4479 high mid
fftCalc[14] = fftAddAvg(98,164) * 0.88f; // 61 4479 - 7106 high mid + high -- with slight damping
}
#endif
} else { // noise gate closed - just decay old values
isFirstRun = false;
@@ -861,7 +908,9 @@ class AudioReactive : public Usermod {
static const char _name[];
static const char _enabled[];
static const char _inputLvl[];
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
static const char _analogmic[];
#endif
static const char _digitalmic[];
static const char UDP_SYNC_HEADER[];
static const char UDP_SYNC_HEADER_v1[];
@@ -1057,6 +1106,10 @@ 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
static unsigned long startuptime = 0; // "fast freeze" mode: do not interfere during first 12 seconds (filter startup time)
#ifdef WLED_DISABLE_SOUND
micIn = inoise8(millis(), millis()); // Simulated analog read
@@ -1079,8 +1132,15 @@ 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 (startuptime == 0) startuptime = millis(); // fast freeze mode - remember filter startup time
if ((micLevelMethod < 1) || !isFrozen) { // following the input level, UNLESS mic Level was frozen
micLev += (micDataReal-micLev) / 12288.0f;
}
if(micDataReal < (micLev-0.24)) { // MicLev above input signal:
micLev = ((micLev * 31.0f) + micDataReal) / 32.0f; // always align MicLev to lowest input signal
if (!haveSilence) isFrozen = true; // freeze mode: freeze micLevel so it cannot rise again
}
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.
@@ -1093,10 +1153,26 @@ class AudioReactive : public Usermod {
expAdjF = fabsf(expAdjF); // Now (!) take the absolute value
if ((micLevelMethod == 2) && !haveSilence && (expAdjF >= (1.5f * float(soundSquelch))))
isFrozen = true; // fast freeze mode: freeze micLevel once the volume rises 50% above squelch
//expAdjF = (micInNoDC <= soundSquelch) ? 0: expAdjF; // simple noise gate - experimental
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 micLev
if (micLevelMethod == 0) isFrozen = false;
if ((micLevelMethod == 1) && isFrozen && haveSilence && ((millis() - lastSoundTime) > 4000)) isFrozen = false; // normal freeze: 4 seconds silence needed
if ((micLevelMethod == 2) && isFrozen && haveSilence && ((millis() - lastSoundTime) > 6000)) isFrozen = false; // fast freeze: 6 seconds silence needed
if ((micLevelMethod == 2) && (millis() - startuptime < 12000)) isFrozen = false; // fast freeze: no freeze in first 12 seconds (filter startup phase)
tmpSample = expAdjF;
micIn = abs(micIn); // And get the absolute value of each sample
@@ -1360,6 +1436,7 @@ class AudioReactive : public Usermod {
case 0: //ADC analog
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
case 5: //PDM Microphone
case 51: //legacy PDM Microphone
#endif
#endif
case 1:
@@ -1397,6 +1474,13 @@ class AudioReactive : public Usermod {
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;
delay(100);
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
break;
#endif
case 6:
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
@@ -1537,7 +1621,7 @@ class AudioReactive : public Usermod {
#if defined(WLED_DEBUG) || defined(SR_DEBUG) || defined(SR_STATS)
// complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second.
if ((userloopDelay > /*23*/ 30) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
if ((userloopDelay > /*23*/ 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
USER_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay);
}
#endif
@@ -1673,14 +1757,15 @@ class AudioReactive : public Usermod {
connected(); // resume UDP
} else
// xTaskCreatePinnedToCore(
xTaskCreate( // no need to "pin" this task to core #0
// xTaskCreate( // no need to "pin" this task to core #0
xTaskCreateUniversal(
FFTcode, // Function to implement the task
"FFT", // Name of the task
5000, // Stack size in words
NULL, // Task input parameter
1, // Priority of the task
&FFT_Task // Task handle
// , 0 // Core where the task should run
, 0 // Core where the task should run
);
}
micDataReal = 0.0f; // just to be sure
@@ -1780,7 +1865,10 @@ class AudioReactive : public Usermod {
if (audioSource->getType() == AudioSource::Type_I2SAdc) {
infoArr.add(F("ADC analog"));
} else {
infoArr.add(F("I2S digital"));
if (dmType != 51)
infoArr.add(F("I2S digital"));
else
infoArr.add(F("legacy I2S PDM"));
}
// input level or "silence"
if (maxSample5sec > 1.0) {
@@ -1793,7 +1881,7 @@ class AudioReactive : public Usermod {
} else {
// error during audio source setup
infoArr.add(F("not initialized"));
infoArr.add(F(" - check GPIO config"));
infoArr.add(F(" - check pin settings"));
}
}
@@ -1957,6 +2045,12 @@ class AudioReactive : public Usermod {
cfg[F("gain")] = sampleGain;
cfg[F("AGC")] = soundAgc;
//WLEDMM: experimental settings
JsonObject poweruser = top.createNestedObject("experiments");
poweruser[F("micLev")] = micLevelMethod;
poweruser[F("freqDist")] = freqDist;
poweruser[F("freqRMS")] = averageByRMS;
JsonObject dynLim = top.createNestedObject("dynamics");
dynLim[F("limiter")] = limiterOn;
dynLim[F("rise")] = attackTime;
@@ -2005,7 +2099,11 @@ class AudioReactive : public Usermod {
if (dmType == 0) dmType = SR_DMTYPE; // MCU does not support analog
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
if (dmType == 5) dmType = SR_DMTYPE; // MCU does not support PDM
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
#endif
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][0], i2ssdPin);
@@ -2019,6 +2117,11 @@ class AudioReactive : public Usermod {
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
configComplete &= getJsonValue(top["config"][F("AGC")], soundAgc);
//WLEDMM: experimental settings
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);
configComplete &= getJsonValue(top["dynamics"][F("fall")], decayTime);
@@ -2038,10 +2141,12 @@ class AudioReactive : public Usermod {
oappend(SET_F("addInfo('AudioReactive:help',0,'<button onclick=\"location.href=&quot;https://mm.kno.wled.ge/soundreactive/Sound-Settings&quot;\" type=\"button\">?</button>');"));
//WLEDMM: add defaults
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) // -S3/-S2/-C3 don't support analog audio
#ifdef AUDIOPIN
oappend(SET_F("xOpt('AudioReactive:analogmic:pin',1,' ⎌',")); oappendi(AUDIOPIN); oappend(");");
#endif
oappend(SET_F("aOpt('AudioReactive:analogmic:pin',1);")); //only analog options
#endif
oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
@@ -2071,12 +2176,17 @@ class AudioReactive : public Usermod {
#else
oappend(SET_F("addOption(dd,'Generic I2S with Mclk',4);"));
#endif
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if SR_DMTYPE==5
oappend(SET_F("addOption(dd,'Generic I2S PDM (⎌)',5);"));
#else
oappend(SET_F("addOption(dd,'Generic I2S PDM',5);"));
#endif
#if SR_DMTYPE==51
oappend(SET_F("addOption(dd,'.Legacy I2S PDM ☾ (⎌)',51);"));
#else
oappend(SET_F("addOption(dd,'.Legacy I2S PDM ☾',51);"));
#endif
#endif
oappend(SET_F("addOption(dd,'ES8388',6);"));
@@ -2093,6 +2203,23 @@ class AudioReactive : public Usermod {
oappend(SET_F("addOption(dd,'Vivid',2);"));
oappend(SET_F("addOption(dd,'Lazy',3);"));
//WLEDMM: experimental settings
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("addOption(dd,'Fast Freeze',2);"));
oappend(SET_F("addInfo('AudioReactive:experiments:micLev',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("addInfo('AudioReactive:experiments:freqDist',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("addInfo('AudioReactive:experiments:freqRMS',1,'☾');"));
oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'On',1);"));
@@ -2163,6 +2290,7 @@ class AudioReactive : public Usermod {
#else
oappend(SET_F("addOption(dd,'userdefined #2',9);"));
#endif
oappend(SET_F("addInfo('AudioReactive:frequency:profile',1,'☾');"));
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
oappend(SET_F("addOption(dd,'Off',0);"));
@@ -2237,7 +2365,9 @@ class AudioReactive : public Usermod {
const char AudioReactive::_name[] PROGMEM = "AudioReactive";
const char AudioReactive::_enabled[] PROGMEM = "enabled";
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
#endif
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00002"; // new sync header version, as format no longer compatible with previous structure
const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = "00001"; // old sync header version - need to add backwards-compatibility feature