Skip to content

Commit

Permalink
Merge branch 'mdev' into mudroom
Browse files Browse the repository at this point in the history
  • Loading branch information
softhack007 committed Dec 4, 2023
2 parents cc8d4e3 + 09ea911 commit 9cbb731
Show file tree
Hide file tree
Showing 9 changed files with 2,538 additions and 2,403 deletions.
72 changes: 61 additions & 11 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,16 @@ board_build.partitions = ${esp32.default_partitions}

; shared build flags and lib deps for minimum and maximum environment
[common_mm]

build_disable_sync_interfaces =
-D WLED_DISABLE_LOXONE
-D WLED_DISABLE_ALEXA
-D WLED_DISABLE_HUESYNC
-D WLED_DISABLE_MQTT
-D WLED_DISABLE_INFRARED
-D WLED_DISABLE_ADALIGHT ;; WLEDMM this board does not have a serial-to-USB chip. Better to disable serial protocols, to avoid crashes (see upstream #3128)
-D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only

build_flags_S =
-Wall -Wformat -Woverflow -Wuninitialized -Winit-self -Warray-bounds ; enables more warnings
-Wno-attributes -Wno-unused-variable -Wno-unused-function -Wno-deprecated-declarations ;disables some stupid warnings
Expand All @@ -932,14 +942,9 @@ build_flags_S =
-D USERMOD_AUDIOREACTIVE
-D UM_AUDIOREACTIVE_USE_NEW_FFT ; use latest (upstream) FFTLib, instead of older library modified by blazoncek. Slightly faster, more accurate, needs 2KB RAM extra
; -D USERMOD_ARTIFX ;; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2
; -D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions.
-D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions.
; -D WLED_DEBUG_HEAP ;; WLEDMM enable heap debugging
; -D WLED_DISABLE_LOXONE
; -D WLED_DISABLE_ALEXA
; -D WLED_DISABLE_HUESYNC
; -D WLED_DISABLE_MQTT
; -D WLED_DISABLE_INFRARED
; -D WLED_ENABLE_DMX
${common_mm.build_disable_sync_interfaces}

lib_deps_S =
;; https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash
Expand Down Expand Up @@ -1033,12 +1038,14 @@ monitor_filters = esp32_exception_decoder
[esp32_4MB_M_base]
extends = esp32_4MB_S_base
build_flags = ${esp32_4MB_S_base.build_flags} ${common_mm.build_flags_M}
build_unflags = ${esp32_4MB_S_base.build_unflags} ${common_mm.build_disable_sync_interfaces}
lib_deps = ${esp32_4MB_S_base.lib_deps} ${common_mm.lib_deps_M}
; board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv

[esp32_4MB_XL_base]
extends = esp32_4MB_M_base
build_flags = ${esp32_4MB_M_base.build_flags} ${common_mm.build_flags_XL}
build_unflags = ${esp32_4MB_M_base.build_unflags} ${common_mm.build_disable_sync_interfaces}
lib_deps = ${esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL}
; board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv

Expand Down Expand Up @@ -1167,7 +1174,7 @@ build_flags = ${esp32_4MB_M_base.build_flags}
extends = esp32_4MB_XL_base
build_flags = ${esp32_4MB_XL_base.build_flags}
-D WLED_RELEASE_NAME=esp32_4MB_XL
build_unflags =
build_unflags = ${esp32_4MB_XL_base.build_unflags}
-D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit
; RAM: [== ] 24.4% (used 80060 bytes from 327680 bytes)
; Flash: [==========] 95.3% (used 1499037 bytes from 1572864 bytes)
Expand Down Expand Up @@ -1972,9 +1979,11 @@ monitor_filters = esp32_exception_decoder
# custom board environments
# ------------------------------------------------------------------------------

[wemos_shield_esp32_4MB_M_base]
extends = esp32_4MB_M_base
build_flags = ${esp32_4MB_M_base.build_flags}
;https://www.tindie.com/products/serg74/wled-shield-board-for-addressable-leds/
;https://www.tindie.com/products/moonmodules/shield-board-for-esp32-for-wled-addressable-leds/
[wemos_shield_esp32_4MB_S_base]
extends = esp32_4MB_S_base
build_flags = ${esp32_4MB_S_base.build_flags}
-D ABL_MILLIAMPS_DEFAULT=9500 ; Wemos max 10A
-D LEDPIN=16
-D RLYPIN=19
Expand All @@ -1990,11 +1999,21 @@ build_flags = ${esp32_4MB_M_base.build_flags}
-D PWM_PIN=-1
; -D WLED_USE_MY_CONFIG

[wemos_shield_esp32_4MB_M_base]
extends = wemos_shield_esp32_4MB_S_base
build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags} ${common_mm.build_flags_M}
lib_deps = ${wemos_shield_esp32_4MB_S_base.lib_deps} ${common_mm.lib_deps_M}

[wemos_shield_esp32_4MB_XL_base]
extends = wemos_shield_esp32_4MB_M_base
build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} ${common_mm.build_flags_XL}
lib_deps = ${wemos_shield_esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL}

[env:wemos_shield_esp32_4MB_S]
extends = wemos_shield_esp32_4MB_S_base
build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags}
-D WLED_RELEASE_NAME=wemos_shield_esp32_4MB_S

[env:wemos_shield_esp32_4MB_M]
extends = wemos_shield_esp32_4MB_M_base
build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags}
Expand Down Expand Up @@ -2022,6 +2041,13 @@ build_unflags = ${common.build_unflags} ${Shield_LineIn.build_unflags}
build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} ${Shield_LineIn.build_flags}
-D WLED_RELEASE_NAME=wemos_shield_esp32_4MB_LineIn_M

[env:wemos_shield_esp32_16MB_S]
extends = wemos_shield_esp32_4MB_S_base
build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags}
-D WLED_RELEASE_NAME=wemos_shield_esp32_16MB_S
board = esp32_16MB
board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem

[env:wemos_shield_esp32_16MB_M]
extends = wemos_shield_esp32_4MB_M_base
build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags}
Expand Down Expand Up @@ -2081,6 +2107,7 @@ board = esp32_16MB
board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem
;board_build.partitions = tools/WLED_ESP32_16MB_9MB_FS.csv ;; WLED extended for 16MB flash: 3.2MB firmware, 9 MB filesystem

;https://www.athom.tech/blank-1/wled-esp32-music-addressable-led-strip-controller
[env:athom_music_esp32_4MB_M]
extends = esp32_4MB_M_base
build_flags = ${esp32_4MB_M_base.build_flags} ${Athom_PDMmic.build_flags}
Expand All @@ -2100,6 +2127,29 @@ build_flags = ${esp32_4MB_M_base.build_flags} ${Athom_PDMmic.build_flags}
; -D PWM_PIN=-1
; -D WLED_USE_MY_CONFIG

;https://shop.myhome-control.de/Elektronik/
[env:abc_wled_controller_v43_S]
extends = esp32_4MB_S_base
build_unflags = ${esp32_4MB_S_base.build_unflags} ${common_mm.build_disable_sync_interfaces}
build_flags = ${esp32_4MB_S_base.build_flags}
-D WLED_RELEASE_NAME=abc_wled_controller_v43_M

-D LEDPIN=16
-D ABL_MILLIAMPS_DEFAULT=5000 ; 5A default. Max 13A depending on the wires connected

-D WLED_USE_ETHERNET
-D WLED_ETH_DEFAULT=9 ; ABC! WLED V43 & compatible
-D RLYPIN=-1 -D BTNPIN=-1 ;; Prevent clash
-D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only

-D AUDIOPIN=-1
-D FLD_PIN_SCL=-1 -D FLD_PIN_SDA=-1 ; use global!

; -D WLED_USE_MY_CONFIG
-D SR_DMTYPE=4 -D I2S_SDPIN=32 -D I2S_WSPIN=15 -D I2S_CKPIN=14 -D MCLK_PIN=0 ; generic i2s with mclk 0
-D SR_SQUELCH=1 -D SR_GAIN=60 ; increrase squelch if noise, in test 0 is okay, but only slightly
-D SR_FREQ_PROF=1 ; Generic line in

; ESP32 WLED pico board with builtin ICS-43432 microphpone
[env:esp32_pico_4MB_M]
extends = esp32_4MB_M_base
Expand Down
70 changes: 64 additions & 6 deletions usermods/audioreactive/audio_reactive.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@
//#define SR_STATS

#if !defined(FFTTASK_PRIORITY)
#if defined(WLEDMM_FASTPATH) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && defined(ARDUINO_ARCH_ESP32)
// FASTPATH: use higher priority, to avoid that webserver (ws, json, etc) delays sample processing
//#define FFTTASK_PRIORITY 3 // competing with async_tcp
#define FFTTASK_PRIORITY 4 // above async_tcp
#else
#define FFTTASK_PRIORITY 1 // standard: looptask prio
//#define FFTTASK_PRIORITY 2 // above looptask, below async_tcp
//#define FFTTASK_PRIORITY 4 // above async_tcp
#endif
#endif

#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
Expand Down Expand Up @@ -111,7 +116,11 @@ static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of pe
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
volatile bool haveNewFFTResult = false; // flag to directly inform UDP sound sender when new FFT results are availeable (to reduce latency). Flag is reset at next UDP send

static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. channel result table to be used by effects
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. (also used by dynamics limiter)
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)

// TODO: probably best not used by receive nodes
static float agcSensitivity = 128; // AGC sensitivity estimation, based on agc gain (multAgc). calculated by getSensitivity(). range 0..255
Expand Down Expand Up @@ -280,8 +289,6 @@ static float sampleTime = 0; // avg (blocked) time for reading I2S sample

// FFT Task variables (filtering and post-processing)
static float lastFftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // backup of last FFT channels (before postprocessing)
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)

#if !defined(CONFIG_IDF_TARGET_ESP32C3)
// audio source parameters and constant
Expand Down Expand Up @@ -499,6 +506,11 @@ void FFTcode(void * parameter)
}
#endif

#if defined(WLEDMM_FASTPATH) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && defined(ARDUINO_ARCH_ESP32)
// experimental - be nice to LED update task (trying to avoid flickering) - dual core only
if (strip.isServicing()) delay(2);
#endif

// band pass filter - can reduce noise floor by a factor of 50
// downside: frequencies below 100Hz will be ignored
if ((useInputFilter > 0) && (useInputFilter < 99)) {
Expand Down Expand Up @@ -736,6 +748,9 @@ void FFTcode(void * parameter)
autoResetPeak();
detectSamplePeak();

// we have new results - notify UDP sound send
haveNewFFTResult = true;

#if !defined(I2S_GRAB_ADC1_COMPLETELY)
if ((audioSource == nullptr) || (audioSource->getType() != AudioSource::Type_I2SAdc)) // the "delay trick" does not help for analog ADC
#endif
Expand Down Expand Up @@ -998,7 +1013,11 @@ class AudioReactive : public Usermod {
// variables for UDP sound sync
WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!)
unsigned long lastTime = 0; // last time of running UDP Microphone Sync
#if defined(WLEDMM_FASTPATH)
const uint16_t delayMs = 5; // I don't want to sample too often and overload WLED
#else
const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED
#endif
uint16_t audioSyncPort= 11988;// default port for UDP sound sync

bool updateIsRunning = false; // true during OTA.
Expand Down Expand Up @@ -1425,6 +1444,39 @@ class AudioReactive : public Usermod {
last_time = millis();
}

// MM experimental: limiter to smooth GEQ samples (only for UDP sound receiver mode)
// target value (if gotNewSample) : fftCalc
// last filtered value: fftAvg
void limitGEQDynamics(bool gotNewSample) {
constexpr float bigChange = 202; // just a representative number - a large, expected sample value
constexpr float smooth = 0.8f; // a bit of filtering
static unsigned long last_time = 0;

if (limiterOn == false) return;

if (gotNewSample) { // take new FFT samples as target values
for(unsigned i=0; i < NUM_GEQ_CHANNELS; i++) {
fftCalc[i] = fftResult[i];
fftResult[i] = fftAvg[i];
}
}

long delta_time = millis() - last_time;
delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> silly lil hick-up
float maxAttack = (attackTime <= 0) ? 255.0f : (bigChange * float(delta_time) / float(attackTime));
float maxDecay = (decayTime <= 0) ? -255.0f : (-bigChange * float(delta_time) / float(decayTime));

for(unsigned i=0; i < NUM_GEQ_CHANNELS; i++) {
float deltaSample = fftCalc[i] - fftAvg[i];
if (deltaSample > maxAttack) deltaSample = maxAttack;
if (deltaSample < maxDecay) deltaSample = maxDecay;
deltaSample = deltaSample * smooth;
fftAvg[i] = fmaxf(0.0f, fminf(255.0f, fftAvg[i] + deltaSample));
fftResult[i] = fftAvg[i];
}
last_time = millis();
}

//////////////////////
// UDP Sound Sync //
//////////////////////
Expand Down Expand Up @@ -1881,7 +1933,7 @@ class AudioReactive : public Usermod {
return;
}
// We cannot wait indefinitely before processing audio data
if (strip.isUpdating() && (millis() - lastUMRun < 2)) return; // be nice, but not too nice
if (strip.isServicing() && (millis() - lastUMRun < 2)) return; // WLEDMM isServicing() is the critical part (be nice, but not too nice)

// suspend local sound processing when "real time mode" is active (E131, UDP, ADALIGHT, ARTNET)
if ( (realtimeOverride == REALTIME_OVERRIDE_NONE) // please add other overrides here if needed
Expand Down Expand Up @@ -1998,6 +2050,7 @@ class AudioReactive : public Usermod {
if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample
else volumeSmth = syncVolumeSmth; // restore originally received sample for next run of dynamics limiter
limitSampleDynamics(); // run dynamics limiter on received volumeSmth, to hide jumps and hickups
limitGEQDynamics(have_new_sample); // WLEDMM experimental: smooth FFT (GEQ) samples
} else {
receivedFormat = 0;
}
Expand Down Expand Up @@ -2048,7 +2101,12 @@ class AudioReactive : public Usermod {

#ifdef ARDUINO_ARCH_ESP32
//UDP Microphone Sync - transmit mode
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) {
#if defined(WLEDMM_FASTPATH)
if ((audioSyncEnabled & 0x01) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms)
#else
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) { // standard: send data each 20ms
#endif
haveNewFFTResult = false; // reset notification
// Only run the transmit code IF we're in Transmit mode
transmitAudioData();
lastTime = millis();
Expand Down
25 changes: 20 additions & 5 deletions wled00/data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ var ctx = null; // WLEDMM
var ledmapNr = -1; //WLEDMM
var ledmapFileNames = []; //WLEDMM
let nodesData = []; //WLEDMM
let ibtglChecked = true; //WLEDMM
let sbtglChecked = true; //WLEDMM
let sbchkChecked = false; //WLEDMM

function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();}
function sCol(na, col) {d.documentElement.style.setProperty(na, col);}
Expand Down Expand Up @@ -694,6 +697,7 @@ ${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.
${theap>0?inforow("Heap ☾",((i.totalheap-i.freeheap)/1000).toFixed(0)+"/"+theap.toFixed(0)+" kB"," ("+Math.round((i.totalheap-i.freeheap)/(10*theap))+"%)"):""}
${i.minfreeheap?inforow("Max used heap ☾",((i.totalheap-i.minfreeheap)/1000).toFixed(1)+" kB"," ("+Math.round((i.totalheap-i.minfreeheap)/(10*theap))+"%)"):""}
${inforow("Free heap",heap," kB")}
${i.freestack?inforow("Free stack ☾",i.freestack," kB"):""} <!--WLEDMM-->
${inforow("Flash Size ☾",flashsize," kB")} <!--WLEDMM and Athom-->
${i.tpram?inforow("PSRAM ☾",(i.tpram/1024).toFixed(1)," kB"):""}
${i.psram?((i.tpram-i.psram)>16383?inforow("Used PSRAM ☾",((i.tpram-i.psram)/1024).toFixed(1)," kB"):inforow("Used PSRAM ☾",(i.tpram-i.psram)," B")):""}
Expand Down Expand Up @@ -2459,21 +2463,21 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
<span class="lstIname">
Include brightness
</span>
<input type="checkbox" id="p${i}ibtgl" checked>
<input type="checkbox" id="p${i}ibtgl" ${ibtglChecked?"checked":""}> <!--WLEDMM-->
<span class="checkmark"></span>
</label>
<label class="check revchkl">
<span class="lstIname">
Save segment bounds
</span>
<input type="checkbox" id="p${i}sbtgl" checked>
<input type="checkbox" id="p${i}sbtgl" ${sbtglChecked?"checked":""}> <!--WLEDMM-->
<span class="checkmark"></span>
</label>
<label class="check revchkl">
<span class="lstIname">
Checked segments only
</span>
<input type="checkbox" id="p${i}sbchk">
<input type="checkbox" id="p${i}sbchk" ${sbchkChecked?"checked":""}> <!--WLEDMM-->
<span class="checkmark"></span>
</label>`;
if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>0) { //WLEDMM >0 instead of 1 to show also first ledmap. Attention: WLED AC has isM check, in MM Matrices are supported so do not check on isM
Expand Down Expand Up @@ -2514,7 +2518,15 @@ function makePUtil()
p.innerHTML = `<div class="presin expanded">${makeP(0)}</div>`;
let pTx = gId('p0txt');
pTx.focus();
pTx.value = eJson.find((o)=>{return o.id==selectedFx}).name;
//WLEDMM: take the name PLUS the icons as default name
let fxName = eJson.find((o)=>{return o.id==selectedFx}).name;

let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`);
if (sE) {
fxName = sE.querySelector(".lstIname").innerText;
}

pTx.value = fxName;
pTx.select();
p.scrollIntoView({
behavior: 'smooth',
Expand Down Expand Up @@ -2902,8 +2914,11 @@ function saveP(i,pl)
obj.o = true;
} else {
obj.ib = gId(`p${i}ibtgl`).checked;
ibtglChecked = obj.ib; //WLEDMM
obj.sb = gId(`p${i}sbtgl`).checked;
sbtglChecked = obj.sb; //WLEDMM
obj.sc = gId(`p${i}sbchk`).checked;
sbchkChecked = obj.sc; //WLEDMM
if (gId(`p${i}lmp`) && gId(`p${i}lmp`).value!=="") obj.ledmap = parseInt(gId(`p${i}lmp`).value);
}
}
Expand Down Expand Up @@ -3235,7 +3250,7 @@ function genPresets()
addToPlaylist("All", ef.id);
if (m.includes("1")) addToPlaylist("All1", ef.id);
if (m.includes("2")) addToPlaylist("All2", ef.id);
} //fxData is array
} //fxdata is array
} //not RSVD
} //all effects

Expand Down
Loading

0 comments on commit 9cbb731

Please sign in to comment.