From 993b123c8e412b513c63b61fc1b82a774598b6c1 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 5 Mar 2024 19:41:19 +0000 Subject: [PATCH 01/59] Basic usermod for detecting silence --- platformio.ini | 1 + .../usermod_v2_auto_playlist.h | 152 ++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 8 + 4 files changed, 162 insertions(+) create mode 100644 usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h diff --git a/platformio.ini b/platformio.ini index 14235a4a0f..b1aeeb6b68 100644 --- a/platformio.ini +++ b/platformio.ini @@ -958,6 +958,7 @@ build_flags_S = ; -D WLED_DISABLE_2D ;; un-comment to build a firmware without 2D matrix support ; -D WLED_USE_CIE_BRIGHTNESS_TABLE ;; experimental: use different color / brightness lookup table -D USERMOD_AUDIOREACTIVE + -D USERMOD_AUTO_PLAYLIST -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. diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h new file mode 100644 index 0000000000..c8cb88a235 --- /dev/null +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -0,0 +1,152 @@ +#pragma once + +#include "wled.h" + + +class AutoPlaylistUsermod : public Usermod { + + private: + bool silenceDetected = true; + uint32_t lastSoundTime; + + public: + + // gets called once at boot. Do all initialization that doesn't depend on + // network here + void setup() { + USER_PRINTLN("AutoPlaylistUsermod"); + } + + // gets called every time WiFi is (re-)connected. Initialize own network + // interfaces here + void connected() {} + + /* + * Da loop. + */ + void loop() { + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // No Audio Reactive + silenceDetected = true; + return; + } + + float volumeSmth = *(float*)um_data->u_data[0]; + + if(volumeSmth > 0.1) { + lastSoundTime = millis(); + } + + if(millis() - lastSoundTime > 60000) { + if(!silenceDetected) { + silenceDetected = true; + USER_PRINTLN("Silence"); + } + } + else { + if(silenceDetected) { + silenceDetected = false; + USER_PRINTLN("End of silence"); + } + } + } + + /* + * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. + * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. + * Below it is shown how this could be used for e.g. a light sensor + */ + void addToJsonInfo(JsonObject& root) { + JsonObject user = root["u"]; + if (user.isNull()) { + user = root.createNestedObject("u"); + } + + JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name + + } + + /* + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + //void addToJsonState(JsonObject& root) { + //} + + /* + * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void readFromJsonState(JsonObject& root) { + if (!initDone) return; // prevent crash on boot applyPreset() + bool en = enabled; + JsonObject um = root[FPSTR(_name)]; + if (!um.isNull()) { + if (en != enabled) enabled = en; + } + } + + void appendConfigData() { + oappend(SET_F("addHB('AutoPlaylist');")); + } + + /* + * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. + * It will be called by WLED when settings are actually saved (for example, LED settings are saved) + * If you want to force saving the current state, use serializeConfig() in your loop(). + * + * CAUTION: serializeConfig() will initiate a filesystem write operation. + * It might cause the LEDs to stutter and will cause flash wear if called too often. + * Use it sparingly and always in the loop, never in network callbacks! + * + * addToConfig() will also not yet add your setting to one of the settings pages automatically. + * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually. + * + * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! + */ + void addToConfig(JsonObject& root) { + // we add JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}} + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + // top[FPSTR(_autoSaveEnabled)] = enabled; + // top[FPSTR(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam + // top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam + // top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot; + DEBUG_PRINTLN(F("AutoPlaylist config saved.")); + } + + /* + * readFromConfig() can be used to read back the custom settings you added with addToConfig(). + * This is called by WLED when settings are loaded (currently this only happens once immediately after boot) + * + * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes), + * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. + * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. + */ + bool readFromConfig(JsonObject& root) { + // we look for JSON object: {"Autosave": {"enabled": true, "autoSaveAfterSec": 10, "autoSavePreset": 250, ...}} + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } + + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(" config (re)loaded.")); + + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; + } + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() { + return USERMOD_ID_AUTOPLAYLIST; + } +}; + diff --git a/wled00/const.h b/wled00/const.h index ae97beef8b..89bd300733 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -142,6 +142,7 @@ #define USERMOD_ID_WEATHER 91 //Usermod "usermod_v2_weather.h" #define USERMOD_ID_GAMES 92 //Usermod "usermod_v2_games.h" #define USERMOD_ID_ANIMARTRIX 93 //Usermod "usermod_v2_animartrix.h" +#define USERMOD_ID_AUTOPLAYLIST 94 // Usermod usermod_v2_auto_playlist.h //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 777ca9d38a..b6ecfcc7af 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -203,6 +203,9 @@ #ifdef USERMOD_ANIMARTRIX #include "../usermods/usermod_v2_animartrix/usermod_v2_animartrix.h" #endif +#ifdef USERMOD_AUTO_PLAYLIST +#include "../usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h" +#endif void registerUsermods() { @@ -402,4 +405,9 @@ void registerUsermods() usermods.add(new AnimartrixUsermod("Animartrix", false)); #endif +#ifdef USERMOD_AUTO_PLAYLIST + usermods.add(new AutoPlaylistUsermod()); +#endif + + } From b1611796366de41a24379396bd72bb8e7f9df3f2 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 5 Mar 2024 21:05:05 +0000 Subject: [PATCH 02/59] add preferences --- .../usermod_v2_auto_playlist.h | 48 ++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index c8cb88a235..b8a25797dd 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -7,10 +7,19 @@ class AutoPlaylistUsermod : public Usermod { private: bool silenceDetected = true; - uint32_t lastSoundTime; + uint32_t lastSoundTime = 0; + byte ambientPlaylist = 1; + byte musicPlaylist = 2; + int timeout = 10; + + static const char _enabled[]; + static const char _ambientPlaylist[]; + static const char _musicPlaylist[]; public: + AutoPlaylistUsermod(const char *name, bool enabled):Usermod(name, enabled) {} + // gets called once at boot. Do all initialization that doesn't depend on // network here void setup() { @@ -25,6 +34,9 @@ class AutoPlaylistUsermod : public Usermod { * Da loop. */ void loop() { + + if(!enabled) return; + um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // No Audio Reactive @@ -38,16 +50,22 @@ class AutoPlaylistUsermod : public Usermod { lastSoundTime = millis(); } - if(millis() - lastSoundTime > 60000) { + if(millis() - lastSoundTime > (timeout * 1000)) { if(!silenceDetected) { silenceDetected = true; - USER_PRINTLN("Silence"); + String name = ""; + getPresetName(ambientPlaylist, name); + USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); + applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); } } else { if(silenceDetected) { silenceDetected = false; - USER_PRINTLN("End of silence"); + String name = ""; + getPresetName(musicPlaylist, name); + USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); + applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); } } } @@ -64,7 +82,12 @@ class AutoPlaylistUsermod : public Usermod { } JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name - + if(!enabled) { + infoArr.add("disabled"); + } + else { + infoArr.add(lastSoundTime); + } } /* @@ -106,12 +129,10 @@ class AutoPlaylistUsermod : public Usermod { * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ void addToConfig(JsonObject& root) { - // we add JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}} JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - // top[FPSTR(_autoSaveEnabled)] = enabled; - // top[FPSTR(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam - // top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam - // top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot; + // top[FPSTR(_enabled)] = enabled; + top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam + top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam DEBUG_PRINTLN(F("AutoPlaylist config saved.")); } @@ -126,7 +147,6 @@ class AutoPlaylistUsermod : public Usermod { * The function should return true if configuration was successfully loaded or false if there was no configuration. */ bool readFromConfig(JsonObject& root) { - // we look for JSON object: {"Autosave": {"enabled": true, "autoSaveAfterSec": 10, "autoSavePreset": 250, ...}} JsonObject top = root[FPSTR(_name)]; if (top.isNull()) { DEBUG_PRINT(FPSTR(_name)); @@ -135,6 +155,9 @@ class AutoPlaylistUsermod : public Usermod { } DEBUG_PRINT(FPSTR(_name)); + getJsonValue(top["ambientPlaylist"], ambientPlaylist); + getJsonValue(top["musicPlaylist"], musicPlaylist); + DEBUG_PRINTLN(F(" config (re)loaded.")); // use "return !top["newestParameter"].isNull();" when updating Usermod with new features @@ -150,3 +173,6 @@ class AutoPlaylistUsermod : public Usermod { } }; +const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; +const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; +const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; From 4f9675bf9ffb5b231c490f5aa3a1b646b3b03a1c Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 5 Mar 2024 21:14:45 +0000 Subject: [PATCH 03/59] add preferences --- .../usermod_v2_auto_playlist.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index b8a25797dd..fd1d286309 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -10,11 +10,12 @@ class AutoPlaylistUsermod : public Usermod { uint32_t lastSoundTime = 0; byte ambientPlaylist = 1; byte musicPlaylist = 2; - int timeout = 10; + int timeout = 60; static const char _enabled[]; static const char _ambientPlaylist[]; static const char _musicPlaylist[]; + static const char _timeout[]; public: @@ -130,7 +131,7 @@ class AutoPlaylistUsermod : public Usermod { */ void addToConfig(JsonObject& root) { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - // top[FPSTR(_enabled)] = enabled; + top[FPSTR(_enabled)] = enabled; top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam DEBUG_PRINTLN(F("AutoPlaylist config saved.")); @@ -155,8 +156,10 @@ class AutoPlaylistUsermod : public Usermod { } DEBUG_PRINT(FPSTR(_name)); - getJsonValue(top["ambientPlaylist"], ambientPlaylist); - getJsonValue(top["musicPlaylist"], musicPlaylist); + getJsonValue(top[_enabled], enabled); + getJsonValue(top[_timeout], timeout); + getJsonValue(top[_ambientPlaylist], ambientPlaylist); + getJsonValue(top[_musicPlaylist], musicPlaylist); DEBUG_PRINTLN(F(" config (re)loaded.")); @@ -173,6 +176,7 @@ class AutoPlaylistUsermod : public Usermod { } }; -const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; -const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; -const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; +const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; +const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; +const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; +const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; From 43e5a12b1d0db485da017e16f73bffe9b8d6995d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 5 Mar 2024 21:23:19 +0000 Subject: [PATCH 04/59] name --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 1 + wled00/usermods_list.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index fd1d286309..e797862b12 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -132,6 +132,7 @@ class AutoPlaylistUsermod : public Usermod { void addToConfig(JsonObject& root) { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname top[FPSTR(_enabled)] = enabled; + top[FPSTR(_timeout)] = timeout; top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam DEBUG_PRINTLN(F("AutoPlaylist config saved.")); diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index b6ecfcc7af..334d3e59c5 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -406,7 +406,7 @@ void registerUsermods() #endif #ifdef USERMOD_AUTO_PLAYLIST - usermods.add(new AutoPlaylistUsermod()); + usermods.add(new AutoPlaylistUsermod("Auto Playlist", true)); #endif From 730714b0d633fc985978db7e981f900fc5f2fb4a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 6 Mar 2024 10:10:16 +0000 Subject: [PATCH 05/59] Add TroyHacks auto change --- .../usermod_v2_auto_playlist.h | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e797862b12..26a3f63c99 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -11,11 +11,36 @@ class AutoPlaylistUsermod : public Usermod { byte ambientPlaylist = 1; byte musicPlaylist = 2; int timeout = 60; + bool autoChange = false; + + + int avg_long_energy = 10000; + int avg_long_lfc = 1000; + int avg_long_zcr = 100; + + int avg_short_energy = 10000; + int avg_short_lfc = 1000; + int avg_short_zcr = 100; + + int vector_energy = 0; + int vector_lfc = 0; + int vector_zcr = 0; + + int squared_distance = 0; + int lastchange = millis(); + + int last_beat_interval = millis(); + int change_threshold = 10; + + int change_lockout = 100; // never change below this numnber of millis. I think of this more like a debounce, but opinions may vary. + int ideal_change_max = 5000; // ideally change patterns no more than this number of millis + int ideal_change_min = 2000; // ideally change patterns no less than this number of millis static const char _enabled[]; static const char _ambientPlaylist[]; static const char _musicPlaylist[]; static const char _timeout[]; + static const char _autoChange[]; public: @@ -31,6 +56,53 @@ class AutoPlaylistUsermod : public Usermod { // interfaces here void connected() {} + void change(um_data_t *um_data) { + + int *extra = (int*) um_data->u_data[11]; + + int zcr = extra[0]; + int energy = extra[1]; + int lfc = extra[2]; + + // WLED-MM/TroyHacks: Calculate the long- and short-running averages + // and the squared_distance for the vector. + + avg_long_energy = avg_long_energy * 0.99 + energy * 0.01; + avg_long_lfc = avg_long_lfc * 0.99 + lfc * 0.01; + avg_long_zcr = avg_long_zcr * 0.99 + zcr * 0.01; + + avg_short_energy = avg_short_energy * 0.9 + energy * 0.1; + avg_short_lfc = avg_short_lfc * 0.9 + lfc * 0.1; + avg_short_zcr = avg_short_zcr * 0.9 + zcr * 0.1; + + // allegedly this is faster than pow(whatever,2) + vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); + vector_energy = (avg_short_energy-avg_long_energy)*(avg_short_energy-avg_long_energy); + vector_zcr = (avg_short_zcr-avg_long_zcr)*(avg_short_zcr-avg_long_zcr); + + squared_distance = vector_lfc + vector_energy + vector_zcr; + squared_distance = squared_distance * squared_distance / 10000000; // shorten just because it's a big number + + // WLED-MM/TroyHacks - Change pattern testing + // + int change_interval = millis()-lastchange; + if (squared_distance <= change_threshold && change_interval > change_lockout) { + if (change_interval > ideal_change_max) { + change_threshold += 1; + } else if (change_interval < ideal_change_min) { + change_threshold -= 1; + } + if (change_threshold < 0) change_threshold = 0; + + int newpreset = random(2,30); + while (currentPreset == newpreset || newpreset == 8 || newpreset == 16 || newpreset == 27) { // 8 is a playlist for me so skip it and the other two just suck :D + newpreset = random(2,30); // make sure we get a different preset + } + applyPreset(newpreset); + USER_PRINTF("*** CHANGE! Squared distance = %d - change interval was %d ms - next change min is %d\n",squared_distance, change_interval, change_threshold); + lastchange = millis(); + } + } /* * Da loop. */ @@ -59,6 +131,7 @@ class AutoPlaylistUsermod : public Usermod { USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); } + if(autoChange) change(um_data); } else { if(silenceDetected) { @@ -135,6 +208,7 @@ class AutoPlaylistUsermod : public Usermod { top[FPSTR(_timeout)] = timeout; top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam + top[FPSTR(_autoChange)] = autoChange; DEBUG_PRINTLN(F("AutoPlaylist config saved.")); } @@ -161,6 +235,7 @@ class AutoPlaylistUsermod : public Usermod { getJsonValue(top[_timeout], timeout); getJsonValue(top[_ambientPlaylist], ambientPlaylist); getJsonValue(top[_musicPlaylist], musicPlaylist); + getJsonValue(top[_autoChange], autoChange); DEBUG_PRINTLN(F(" config (re)loaded.")); @@ -181,3 +256,4 @@ const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; +const char AutoPlaylistUsermod::_autoChange[] PROGMEM = "autoChange"; From a8661b512555e643f7d0dbd38f4724e783626c22 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 6 Mar 2024 10:43:16 +0000 Subject: [PATCH 06/59] Set autochange in correct state --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 26a3f63c99..06a4b85ea2 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -131,7 +131,6 @@ class AutoPlaylistUsermod : public Usermod { USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); } - if(autoChange) change(um_data); } else { if(silenceDetected) { @@ -141,6 +140,7 @@ class AutoPlaylistUsermod : public Usermod { USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); } + if(autoChange) change(um_data); } } From 265339cc3fb1927d253d58dfadea9b7f0e7f235a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 6 Mar 2024 18:38:27 +0000 Subject: [PATCH 07/59] Trying to add enable button to info panel --- .../usermod_v2_auto_playlist.h | 19 ++++++++++++++++--- wled00/usermods_list.cpp | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 06a4b85ea2..02d4bff8fb 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -44,7 +44,7 @@ class AutoPlaylistUsermod : public Usermod { public: - AutoPlaylistUsermod(const char *name, bool enabled):Usermod(name, enabled) {} + AutoPlaylistUsermod(bool enabled):Usermod("AutoPlaylist", enabled) {} // gets called once at boot. Do all initialization that doesn't depend on // network here @@ -156,6 +156,18 @@ class AutoPlaylistUsermod : public Usermod { } JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name + String uiDomString = F(""); + infoArr.add(uiDomString); + + infoArr = user.createNestedArray(F("")); if(!enabled) { infoArr.add("disabled"); } @@ -177,10 +189,11 @@ class AutoPlaylistUsermod : public Usermod { */ void readFromJsonState(JsonObject& root) { if (!initDone) return; // prevent crash on boot applyPreset() - bool en = enabled; JsonObject um = root[FPSTR(_name)]; if (!um.isNull()) { - if (en != enabled) enabled = en; + if (um[FPSTR(_enabled)].is()) { + enabled = um[FPSTR(_enabled)].as(); + } } } diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 334d3e59c5..3cb5c19cbd 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -406,7 +406,7 @@ void registerUsermods() #endif #ifdef USERMOD_AUTO_PLAYLIST - usermods.add(new AutoPlaylistUsermod("Auto Playlist", true)); + usermods.add(new AutoPlaylistUsermod(true)); #endif From 95e94a99b9b8bfa85a1fb68b86e708d7ddd21b39 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 8 Mar 2024 00:35:22 +0000 Subject: [PATCH 08/59] Try to use existing FTT data --- .../usermod_v2_auto_playlist.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 02d4bff8fb..71df76255c 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -60,9 +60,9 @@ class AutoPlaylistUsermod : public Usermod { int *extra = (int*) um_data->u_data[11]; - int zcr = extra[0]; + unsigned int zcr = extra[0]; int energy = extra[1]; - int lfc = extra[2]; + int lfc = getFFTFromRange(um_data, 0 , 3); // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the squared_distance for the vector. @@ -103,6 +103,15 @@ class AutoPlaylistUsermod : public Usermod { lastchange = millis(); } } + uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { + uint8_t *fftResult = (uint8_t*) data->u_data[2]; + uint8_t result = 0; + for (int i = from; i <= to; i++) { + result += fftResult[i] * fftResult[i]; + } + return sqrt(result / (to - from + 1)); + } + /* * Da loop. */ From 5c4c72d068dc0ea559bc01390e09138c298799de Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 12 Mar 2024 20:27:40 +0000 Subject: [PATCH 09/59] Do not auto-select preset if the lamp is off --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 71df76255c..e57ab5baa9 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -138,7 +138,7 @@ class AutoPlaylistUsermod : public Usermod { String name = ""; getPresetName(ambientPlaylist, name); USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); - applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); + if(bri > 0) applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); } } else { @@ -147,7 +147,7 @@ class AutoPlaylistUsermod : public Usermod { String name = ""; getPresetName(musicPlaylist, name); USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); - applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); + if(bri > 0) applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); } if(autoChange) change(um_data); } From c0f2f747556d34eeb1ded4ea9f43449d9fadf509 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 14 Mar 2024 20:14:40 +0000 Subject: [PATCH 10/59] Load presets from playlist --- .../usermod_v2_auto_playlist.h | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e57ab5baa9..60c1ea68dc 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -36,6 +36,8 @@ class AutoPlaylistUsermod : public Usermod { int ideal_change_max = 5000; // ideally change patterns no more than this number of millis int ideal_change_min = 2000; // ideally change patterns no less than this number of millis + std::vector autoChangeIds; + static const char _enabled[]; static const char _ambientPlaylist[]; static const char _musicPlaylist[]; @@ -94,10 +96,23 @@ class AutoPlaylistUsermod : public Usermod { } if (change_threshold < 0) change_threshold = 0; - int newpreset = random(2,30); - while (currentPreset == newpreset || newpreset == 8 || newpreset == 16 || newpreset == 27) { // 8 is a playlist for me so skip it and the other two just suck :D - newpreset = random(2,30); // make sure we get a different preset + if(autoChangeIds.size() == 0) { + USER_PRINTF("Loading presets from playlist:%u\n", currentPlaylist); + JsonObject playtlistOjb = doc.to(); + serializePlaylist(playtlistOjb); + JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; + for(JsonVariant v : playlistArray) { + USER_PRINTF("Adding %u to autoChangeIds\n", v.as()); + autoChangeIds.push_back(v.as()); + } } + + uint8_t newpreset = 0; + do { + newpreset = autoChangeIds.at(random(0, (autoChangeIds.size() - 1))); + } + while (currentPreset == newpreset); + applyPreset(newpreset); USER_PRINTF("*** CHANGE! Squared distance = %d - change interval was %d ms - next change min is %d\n",squared_distance, change_interval, change_threshold); lastchange = millis(); @@ -105,7 +120,7 @@ class AutoPlaylistUsermod : public Usermod { } uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { uint8_t *fftResult = (uint8_t*) data->u_data[2]; - uint8_t result = 0; + uint16_t result = 0; for (int i = from; i <= to; i++) { result += fftResult[i] * fftResult[i]; } From 3ed5b89efcf3db54642ea324592ef18281f7917a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 14 Mar 2024 20:16:23 +0000 Subject: [PATCH 11/59] Skip if turned off --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 60c1ea68dc..7a90d70625 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -134,6 +134,8 @@ class AutoPlaylistUsermod : public Usermod { if(!enabled) return; + if(bri == 0) return; + um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // No Audio Reactive @@ -153,7 +155,7 @@ class AutoPlaylistUsermod : public Usermod { String name = ""; getPresetName(ambientPlaylist, name); USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); - if(bri > 0) applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); + applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); } } else { @@ -162,7 +164,7 @@ class AutoPlaylistUsermod : public Usermod { String name = ""; getPresetName(musicPlaylist, name); USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); - if(bri > 0) applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); + applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); } if(autoChange) change(um_data); } From c4cb5af78c4c8e4902833f0c62148ef73ac5f33e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 18 Mar 2024 14:57:41 +0000 Subject: [PATCH 12/59] Disable auto-playlist if manual selection is made --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 7a90d70625..419e241cf3 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -12,6 +12,7 @@ class AutoPlaylistUsermod : public Usermod { byte musicPlaylist = 2; int timeout = 60; bool autoChange = false; + byte lastAutoPreset = 0; int avg_long_energy = 10000; @@ -136,6 +137,8 @@ class AutoPlaylistUsermod : public Usermod { if(bri == 0) return; + if(lastAutoPreset > 0 && lastAutoPreset != currentPreset) enabled = false; + um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // No Audio Reactive @@ -156,6 +159,7 @@ class AutoPlaylistUsermod : public Usermod { getPresetName(ambientPlaylist, name); USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); + lastAutoPreset = ambientPlaylist; } } else { @@ -165,6 +169,7 @@ class AutoPlaylistUsermod : public Usermod { getPresetName(musicPlaylist, name); USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); + lastAutoPreset = ambientPlaylist; } if(autoChange) change(um_data); } From 2fdd438d34327358b00f26cde2677532a96021c1 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 21 Mar 2024 20:06:29 +0000 Subject: [PATCH 13/59] Disable AutoPlaylist if user makes manual change --- .../usermod_v2_auto_playlist.h | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 419e241cf3..e1c017d968 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -12,7 +12,7 @@ class AutoPlaylistUsermod : public Usermod { byte musicPlaylist = 2; int timeout = 60; bool autoChange = false; - byte lastAutoPreset = 0; + byte lastAutoPlaylist = 0; int avg_long_energy = 10000; @@ -135,9 +135,14 @@ class AutoPlaylistUsermod : public Usermod { if(!enabled) return; + if(millis() < 10000) return; // Wait for device to settle + if(bri == 0) return; - if(lastAutoPreset > 0 && lastAutoPreset != currentPreset) enabled = false; + if(lastAutoPlaylist > 0 && lastAutoPlaylist != currentPlaylist) { + USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); + enabled = false; + } um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -155,21 +160,15 @@ class AutoPlaylistUsermod : public Usermod { if(millis() - lastSoundTime > (timeout * 1000)) { if(!silenceDetected) { silenceDetected = true; - String name = ""; - getPresetName(ambientPlaylist, name); - USER_PRINTF("AutoPlaylist: Silence - apply %s\n", name.c_str()); - applyPreset(ambientPlaylist, CALL_MODE_NOTIFICATION); - lastAutoPreset = ambientPlaylist; + USER_PRINTF("AutoPlaylist: Silence "); + changePlaylist(ambientPlaylist); } } else { if(silenceDetected) { silenceDetected = false; - String name = ""; - getPresetName(musicPlaylist, name); - USER_PRINTF("AutoPlaylist: End of silence - apply %s\n", name.c_str()); - applyPreset(musicPlaylist, CALL_MODE_NOTIFICATION); - lastAutoPreset = ambientPlaylist; + USER_PRINTF("AutoPlaylist: End of silence "); + changePlaylist(musicPlaylist); } if(autoChange) change(um_data); } @@ -253,6 +252,7 @@ class AutoPlaylistUsermod : public Usermod { top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam top[FPSTR(_autoChange)] = autoChange; + lastAutoPlaylist = 0; DEBUG_PRINTLN(F("AutoPlaylist config saved.")); } @@ -294,6 +294,18 @@ class AutoPlaylistUsermod : public Usermod { uint16_t getId() { return USERMOD_ID_AUTOPLAYLIST; } + + private: + + void changePlaylist(byte id) { + String name = ""; + getPresetName(id, name); + USER_PRINTF("apply %s\n", name.c_str()); + applyPreset(id, CALL_MODE_NOTIFICATION); + lastAutoPlaylist = id; + } + + }; const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; From cfafa0d358815696f2201e862c35d24998b18b80 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 21 Mar 2024 23:32:44 +0000 Subject: [PATCH 14/59] Auto disengage --- .../usermod_v2_auto_playlist.h | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e1c017d968..4d5ba8c930 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -133,16 +133,26 @@ class AutoPlaylistUsermod : public Usermod { */ void loop() { - if(!enabled) return; - if(millis() < 10000) return; // Wait for device to settle - if(bri == 0) return; - - if(lastAutoPlaylist > 0 && lastAutoPlaylist != currentPlaylist) { - USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); - enabled = false; + if(lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { + if(currentPlaylist == musicPlaylist) { + USER_PRINTF("AutoPlaylist: enabled due to manual change of playlist back to %u\n", currentPlaylist); + enabled = true; + lastAutoPlaylist = currentPlaylist; + } + else if(enabled) { + USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); + enabled = false; + } + } + if(!enabled && currentPlaylist == musicPlaylist) { + USER_PRINTF("AutoPlaylist: enabled due selecting musicPlaylist(%u)", musicPlaylist); + enabled = true; } + if(!enabled) return; + + if(bri == 0) return; um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -153,7 +163,7 @@ class AutoPlaylistUsermod : public Usermod { float volumeSmth = *(float*)um_data->u_data[0]; - if(volumeSmth > 0.1) { + if(volumeSmth > 0.5) { lastSoundTime = millis(); } From fd714e3e0f5e394e7a786a2590f580d9ee39c10b Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 22 Mar 2024 00:07:36 +0000 Subject: [PATCH 15/59] Remove buttton --- .../usermod_v2_auto_playlist.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 4d5ba8c930..e39f4c2bc8 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -196,16 +196,6 @@ class AutoPlaylistUsermod : public Usermod { } JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name - String uiDomString = F(""); - infoArr.add(uiDomString); infoArr = user.createNestedArray(F("")); if(!enabled) { From 734ba393998bd0bc350af156d31a61f5982ebd86 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Mar 2024 09:29:32 -0400 Subject: [PATCH 16/59] Fixes. Auto is too animated. --- usermods/audioreactive/audio_reactive.h | 3 ++- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index da6005dbca..b234b43ca9 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -36,7 +36,7 @@ #endif #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) -// this applies "pink noise scaling" to FFT results before computing the major peak for effects. +// this applies "pink noise scaling" to FFT results before computing the major peak for effects.0 // currently only for ESP32-S3 and classic ESP32, due to increased runtime #define FFT_MAJORPEAK_HUMAN_EAR #endif @@ -549,6 +549,7 @@ void FFTcode(void * parameter) // find highest sample in the batch float maxSample = 0.0f; // max sample from FFT batch + zeroCrossingCount = 0; for (int i=0; i < samplesFFT; i++) { // set imaginary parts to 0 vImag[i] = 0; diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e39f4c2bc8..8be728b15f 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -34,8 +34,8 @@ class AutoPlaylistUsermod : public Usermod { int change_threshold = 10; int change_lockout = 100; // never change below this numnber of millis. I think of this more like a debounce, but opinions may vary. - int ideal_change_max = 5000; // ideally change patterns no more than this number of millis int ideal_change_min = 2000; // ideally change patterns no less than this number of millis + int ideal_change_max = 5000; // ideally change patterns no more than this number of millis std::vector autoChangeIds; @@ -65,7 +65,7 @@ class AutoPlaylistUsermod : public Usermod { unsigned int zcr = extra[0]; int energy = extra[1]; - int lfc = getFFTFromRange(um_data, 0 , 3); + int lfc = extra[2]; // getFFTFromRange(um_data, 1 , 3); // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the squared_distance for the vector. From 8d687b3a868cdba5faf953beeb0914994dc70943 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Mar 2024 10:10:09 -0400 Subject: [PATCH 17/59] Debugging --- usermods/audioreactive/audio_reactive.h | 2 +- .../usermod_v2_auto_playlist.h | 24 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index b234b43ca9..b19b453213 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -662,7 +662,7 @@ void FFTcode(void * parameter) vReal[i] = t / 16.0f; // Reduce magnitude. Want end result to be scaled linear and ~4096 max. } // for() - lowFreqencyContent = fftAddAvg(1,9); // WLED-MM/TroyHacks: Calculate Low-Frequency Content + lowFreqencyContent = fftAddAvg(1,4); // WLED-MM/TroyHacks: Calculate Low-Frequency Content // mapping of FFT result bins to frequency channels //if (fabsf(sampleAvg) > 0.25f) { // noise gate open diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 8be728b15f..2b21691fc4 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -14,7 +14,6 @@ class AutoPlaylistUsermod : public Usermod { bool autoChange = false; byte lastAutoPlaylist = 0; - int avg_long_energy = 10000; int avg_long_lfc = 1000; int avg_long_zcr = 100; @@ -65,7 +64,9 @@ class AutoPlaylistUsermod : public Usermod { unsigned int zcr = extra[0]; int energy = extra[1]; - int lfc = extra[2]; // getFFTFromRange(um_data, 1 , 3); + int lfc = extra[2]; // getFFTFromRange(um_data, 2 , 4); + + USER_PRINTF("zcr = %d, energy = %d, lfc = %d\n",zcr,energy,lfc); // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the squared_distance for the vector. @@ -78,12 +79,18 @@ class AutoPlaylistUsermod : public Usermod { avg_short_lfc = avg_short_lfc * 0.9 + lfc * 0.1; avg_short_zcr = avg_short_zcr * 0.9 + zcr * 0.1; + energy = 0; + lfc = 0; + zcr = 0; + // allegedly this is faster than pow(whatever,2) vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); vector_energy = (avg_short_energy-avg_long_energy)*(avg_short_energy-avg_long_energy); vector_zcr = (avg_short_zcr-avg_long_zcr)*(avg_short_zcr-avg_long_zcr); squared_distance = vector_lfc + vector_energy + vector_zcr; + // USER_PRINTF("squared_distance = %d\n", squared_distance * squared_distance / 10000000); + squared_distance = squared_distance * squared_distance / 10000000; // shorten just because it's a big number // WLED-MM/TroyHacks - Change pattern testing @@ -119,13 +126,22 @@ class AutoPlaylistUsermod : public Usermod { lastchange = millis(); } } + + // // 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); + // } + uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { uint8_t *fftResult = (uint8_t*) data->u_data[2]; uint16_t result = 0; for (int i = from; i <= to; i++) { - result += fftResult[i] * fftResult[i]; + result += fftResult[i]; // * fftResult[i]; } - return sqrt(result / (to - from + 1)); + return result / float(to - from + 1); // sqrt(result / (to - from + 1)); } /* From 2fe86bde5db87bb43f6033f2df0dd2ae7789dbfb Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Mar 2024 17:41:34 -0400 Subject: [PATCH 18/59] Feature complete... and better! --- usermods/audioreactive/audio_reactive.h | 57 +++++--- .../usermod_v2_auto_playlist.h | 138 +++++++++++------- 2 files changed, 120 insertions(+), 75 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index b19b453213..db6f50654a 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -141,9 +141,9 @@ static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. chann 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) -unsigned int zeroCrossingCount = 0; -unsigned int energy = 0; -unsigned int lowFreqencyContent = 0; +uint_fast32_t zeroCrossingCount = 0; +uint_fast32_t energy = 0; +uint_fast32_t lowFreqencyContent = 0; // 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 @@ -498,6 +498,21 @@ void FFTcode(void * parameter) // get a fresh batch of samples from I2S if (audioSource) audioSource->getSamples(vReal, samplesFFT); + + // WLED-MM/TroyHacks: Calculate zero crossings + // + zeroCrossingCount = 0; + energy = 0; + + for (int i=0; i < samplesFFT; i++) { + if (i < (samplesFFT)-2) { + if((vReal[i] >= 0 && vReal[i+1] < 0) || (vReal[i+1] < 0 && vReal[i+1] >= 0)) { + zeroCrossingCount++; + } + } + // WLED-MM/TroyHacks: Calculate energy + energy += (vReal[i] * vReal[i])/10000000; + } #if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS) // debug info in case that stack usage changes @@ -549,24 +564,13 @@ void FFTcode(void * parameter) // find highest sample in the batch float maxSample = 0.0f; // max sample from FFT batch - zeroCrossingCount = 0; for (int i=0; i < samplesFFT; i++) { // set imaginary parts to 0 vImag[i] = 0; // pick our our current mic sample - we take the max value from all samples that go into FFT if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts if (fabsf((float)vReal[i]) > maxSample) maxSample = fabsf((float)vReal[i]); - - // WLED-MM/TroyHacks: Calculate zero crossings - if (i < samplesFFT-2) { - if (vReal[i] * vReal[i+1] < 0) { - zeroCrossingCount++; - } - } - // WLED-MM/TroyHacks: Calculate energy - energy += vReal[i] * vReal[i]; } - energy /= 100000; // WLED-MM/TroyHacks: scale this down becasue we're gonna make it bigger later // release highest sample to volume reactive effects early - not strictly necessary here - could also be done at the end of the function // early release allows the filters (getSample() and agcAvg()) to work with fresh values - we will have matching gain and noise gate values when we want to process the FFT results. @@ -641,6 +645,17 @@ void FFTcode(void * parameter) #endif FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects FFT_MajPeakSmth = FFT_MajPeakSmth + 0.42 * (FFT_MajorPeak - FFT_MajPeakSmth); // I like this "swooping peak" look + + // WLED-MM/TroyHacks: Calculate Low-Frequency Content + // + lowFreqencyContent = fftAddAvg(2,4)/1000; + + // USER_PRINT("ZCR = "); + // USER_PRINT(zeroCrossingCount); + // USER_PRINT(" Energy = "); + // USER_PRINT(" LFC = "); + // USER_PRINT(lowFreqencyContent); + // USER_PRINTLN(); } else { // skip second run --> clear fft results, keep peaks memset(vReal, 0, sizeof(vReal)); @@ -662,8 +677,6 @@ void FFTcode(void * parameter) vReal[i] = t / 16.0f; // Reduce magnitude. Want end result to be scaled linear and ~4096 max. } // for() - lowFreqencyContent = fftAddAvg(1,4); // WLED-MM/TroyHacks: Calculate Low-Frequency Content - // mapping of FFT result bins to frequency channels //if (fabsf(sampleAvg) > 0.25f) { // noise gate open if (fabsf(volumeSmth) > 0.25f) { // noise gate open @@ -1738,7 +1751,7 @@ class AudioReactive : public Usermod { // usermod exchangeable data // we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers um_data = new um_data_t; - um_data->u_size = 11; + um_data->u_size = 13; um_data->u_type = new um_types_t[um_data->u_size]; um_data->u_data = new void*[um_data->u_size]; um_data->u_data[0] = &volumeSmth; //*used (New) @@ -1764,10 +1777,12 @@ class AudioReactive : public Usermod { um_data->u_type[9] = UMT_FLOAT; um_data->u_data[10] = &agcSensitivity; // used (New) um_data->u_type[10] = UMT_FLOAT; - unsigned int* extra[3] = {&zeroCrossingCount, &energy, &lowFreqencyContent}; - um_data->u_data[11] = extra; // - um_data->u_type[11] = UMT_INT16_ARR; - + um_data->u_data[11] = &zeroCrossingCount; + um_data->u_type[11] = UMT_UINT32; + um_data->u_data[12] = &energy; + um_data->u_type[12] = UMT_UINT32; + um_data->u_data[13] = &lowFreqencyContent; + um_data->u_type[13] = UMT_UINT32; #else // ESP8266 // See https://github.com/MoonModules/WLED/pull/60#issuecomment-1666972133 for explanation of these alternative sources of data diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 2b21691fc4..e8061331ae 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -13,28 +13,32 @@ class AutoPlaylistUsermod : public Usermod { int timeout = 60; bool autoChange = false; byte lastAutoPlaylist = 0; + int change_timer = millis(); - int avg_long_energy = 10000; - int avg_long_lfc = 1000; - int avg_long_zcr = 100; + uint_fast32_t avg_long_energy = 250; + uint_fast32_t avg_long_lfc = 1000; + uint_fast32_t avg_long_zcr = 500; - int avg_short_energy = 10000; - int avg_short_lfc = 1000; - int avg_short_zcr = 100; + uint_fast32_t avg_short_energy = 250; + uint_fast32_t avg_short_lfc = 1000; + uint_fast32_t avg_short_zcr = 500; - int vector_energy = 0; - int vector_lfc = 0; - int vector_zcr = 0; + uint_fast32_t vector_energy = 0; + uint_fast32_t vector_lfc = 0; + uint_fast32_t vector_zcr = 0; + + uint_fast32_t distance = 0; + + // uint_fast64_t squared_distance = 0; - int squared_distance = 0; int lastchange = millis(); int last_beat_interval = millis(); - int change_threshold = 10; + int change_threshold = 50; - int change_lockout = 100; // never change below this numnber of millis. I think of this more like a debounce, but opinions may vary. - int ideal_change_min = 2000; // ideally change patterns no less than this number of millis - int ideal_change_max = 5000; // ideally change patterns no more than this number of millis + int change_lockout = 1000; // never change below this numnber of millis. I think of this more like a debounce, but opinions may vary. + int ideal_change_min = 10000; // ideally change patterns no less than this number of millis + int ideal_change_max = 20000; // ideally change patterns no more than this number of millis std::vector autoChangeIds; @@ -43,10 +47,15 @@ class AutoPlaylistUsermod : public Usermod { static const char _musicPlaylist[]; static const char _timeout[]; static const char _autoChange[]; + static const char _change_lockout[]; + static const char _ideal_change_min[]; + static const char _ideal_change_max[]; public: - AutoPlaylistUsermod(bool enabled):Usermod("AutoPlaylist", enabled) {} + AutoPlaylistUsermod(bool enabled):Usermod("AutoPlaylist", enabled) { + // noop + } // gets called once at boot. Do all initialization that doesn't depend on // network here @@ -56,47 +65,62 @@ class AutoPlaylistUsermod : public Usermod { // gets called every time WiFi is (re-)connected. Initialize own network // interfaces here - void connected() {} + void connected() { + // noop + } void change(um_data_t *um_data) { - int *extra = (int*) um_data->u_data[11]; - - unsigned int zcr = extra[0]; - int energy = extra[1]; - int lfc = extra[2]; // getFFTFromRange(um_data, 2 , 4); - - USER_PRINTF("zcr = %d, energy = %d, lfc = %d\n",zcr,energy,lfc); + uint_fast32_t zcr = *(uint_fast32_t*)um_data->u_data[11]; + uint_fast32_t energy = *(uint_fast32_t*)um_data->u_data[12]; + uint_fast32_t lfc = *(uint_fast32_t*)um_data->u_data[13]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the squared_distance for the vector. - avg_long_energy = avg_long_energy * 0.99 + energy * 0.01; - avg_long_lfc = avg_long_lfc * 0.99 + lfc * 0.01; - avg_long_zcr = avg_long_zcr * 0.99 + zcr * 0.01; + if (volumeSmth > 0.1) { - avg_short_energy = avg_short_energy * 0.9 + energy * 0.1; - avg_short_lfc = avg_short_lfc * 0.9 + lfc * 0.1; - avg_short_zcr = avg_short_zcr * 0.9 + zcr * 0.1; + avg_long_energy = avg_long_energy * 0.99 + energy * 0.01; + avg_long_lfc = avg_long_lfc * 0.99 + lfc * 0.01; + avg_long_zcr = avg_long_zcr * 0.99 + zcr * 0.01; - energy = 0; - lfc = 0; - zcr = 0; + avg_short_energy = avg_short_energy * 0.9 + energy * 0.1; + avg_short_lfc = avg_short_lfc * 0.9 + lfc * 0.1; + avg_short_zcr = avg_short_zcr * 0.9 + zcr * 0.1; - // allegedly this is faster than pow(whatever,2) - vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); - vector_energy = (avg_short_energy-avg_long_energy)*(avg_short_energy-avg_long_energy); - vector_zcr = (avg_short_zcr-avg_long_zcr)*(avg_short_zcr-avg_long_zcr); + // allegedly this is faster than pow(whatever,2) + vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); + vector_energy = (avg_short_energy-avg_long_energy)*(avg_short_energy-avg_long_energy); + vector_zcr = (avg_short_zcr-avg_long_zcr)*(avg_short_zcr-avg_long_zcr); - squared_distance = vector_lfc + vector_energy + vector_zcr; + } + + distance = vector_lfc + vector_energy + vector_zcr; // USER_PRINTF("squared_distance = %d\n", squared_distance * squared_distance / 10000000); - squared_distance = squared_distance * squared_distance / 10000000; // shorten just because it's a big number + // squared_distance = distance * distance; + + int change_interval = millis()-lastchange; + + // if (millis() > change_timer + 100) { + // // if (change_interval > ideal_change_max) { + // // USER_PRINTF("Increasing sensitivity to: %d\n",change_threshold++); + // // } + // USER_PRINT("\tDistance: "); + // USER_PRINT(distance); + // USER_PRINT("\tv_lfc: "); + // USER_PRINT(vector_lfc); + // USER_PRINT("\tv_energy: "); + // USER_PRINT(vector_energy); + // USER_PRINT("\tv_zcr: "); + // USER_PRINTLN(vector_zcr); + + // change_timer = millis(); + // } // WLED-MM/TroyHacks - Change pattern testing // - int change_interval = millis()-lastchange; - if (squared_distance <= change_threshold && change_interval > change_lockout) { + if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { if (change_interval > ideal_change_max) { change_threshold += 1; } else if (change_interval < ideal_change_min) { @@ -122,19 +146,16 @@ class AutoPlaylistUsermod : public Usermod { while (currentPreset == newpreset); applyPreset(newpreset); - USER_PRINTF("*** CHANGE! Squared distance = %d - change interval was %d ms - next change min is %d\n",squared_distance, change_interval, change_threshold); + USER_PRINT("*** CHANGE! Vector distance = "); + USER_PRINT(distance); + USER_PRINT(" - change interval was "); + USER_PRINT(change_interval); + USER_PRINT("ms - next change min is "); + USER_PRINTLN(change_threshold); lastchange = millis(); } } - // // 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); - // } - uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { uint8_t *fftResult = (uint8_t*) data->u_data[2]; uint16_t result = 0; @@ -268,6 +289,9 @@ class AutoPlaylistUsermod : public Usermod { top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam top[FPSTR(_autoChange)] = autoChange; + top[FPSTR(_change_lockout)] = change_lockout; + top[FPSTR(_ideal_change_min)] = ideal_change_min; + top[FPSTR(_ideal_change_max)] = ideal_change_max; lastAutoPlaylist = 0; DEBUG_PRINTLN(F("AutoPlaylist config saved.")); } @@ -296,6 +320,9 @@ class AutoPlaylistUsermod : public Usermod { getJsonValue(top[_ambientPlaylist], ambientPlaylist); getJsonValue(top[_musicPlaylist], musicPlaylist); getJsonValue(top[_autoChange], autoChange); + getJsonValue(top[_change_lockout], change_lockout); + getJsonValue(top[_ideal_change_min], ideal_change_min); + getJsonValue(top[_ideal_change_max], ideal_change_max); DEBUG_PRINTLN(F(" config (re)loaded.")); @@ -324,8 +351,11 @@ class AutoPlaylistUsermod : public Usermod { }; -const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; -const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; -const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; -const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; -const char AutoPlaylistUsermod::_autoChange[] PROGMEM = "autoChange"; +const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; +const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; +const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; +const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; +const char AutoPlaylistUsermod::_autoChange[] PROGMEM = "autoChange"; +const char AutoPlaylistUsermod::_change_lockout[] PROGMEM = "change_lockout"; +const char AutoPlaylistUsermod::_ideal_change_min[] PROGMEM = "ideal_change_min"; +const char AutoPlaylistUsermod::_ideal_change_max[] PROGMEM = "ideal_change_max"; From 9e9b0149594d790a450d5ff104b623a0bb1736b9 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Mar 2024 18:22:44 -0400 Subject: [PATCH 19/59] change_threshold pushback when window missing. --- .../usermod_v2_auto_playlist.h | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e8061331ae..44407616ce 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -96,27 +96,30 @@ class AutoPlaylistUsermod : public Usermod { } distance = vector_lfc + vector_energy + vector_zcr; - // USER_PRINTF("squared_distance = %d\n", squared_distance * squared_distance / 10000000); - // squared_distance = distance * distance; int change_interval = millis()-lastchange; - // if (millis() > change_timer + 100) { - // // if (change_interval > ideal_change_max) { - // // USER_PRINTF("Increasing sensitivity to: %d\n",change_threshold++); - // // } - // USER_PRINT("\tDistance: "); - // USER_PRINT(distance); - // USER_PRINT("\tv_lfc: "); - // USER_PRINT(vector_lfc); - // USER_PRINT("\tv_energy: "); - // USER_PRINT(vector_energy); - // USER_PRINT("\tv_zcr: "); - // USER_PRINTLN(vector_zcr); - - // change_timer = millis(); - // } + // USER_PRINT("\tDistance: "); + // USER_PRINT(distance); + // USER_PRINT("\tv_lfc: "); + // USER_PRINT(vector_lfc); + // USER_PRINT("\tv_energy: "); + // USER_PRINT(vector_energy); + // USER_PRINT("\tv_zcr: "); + // USER_PRINTLN(vector_zcr); + + if (millis() > change_timer + ideal_change_min) { + // Make the analysis less sensitive if we miss the window, slowly. + // Sometimes the analysis lowers the change_threshold too much for + // the current music, especially after track changes or during + // sparce intros and breakdowns. + if (change_interval > ideal_change_min) { + change_threshold++; + USER_PRINTF("Increasing change_threshold to: %d\n",change_threshold); + } + change_timer = millis(); + } // WLED-MM/TroyHacks - Change pattern testing // @@ -146,14 +149,17 @@ class AutoPlaylistUsermod : public Usermod { while (currentPreset == newpreset); applyPreset(newpreset); + USER_PRINT("*** CHANGE! Vector distance = "); USER_PRINT(distance); - USER_PRINT(" - change interval was "); + USER_PRINT(" - change_interval was "); USER_PRINT(change_interval); - USER_PRINT("ms - next change min is "); + USER_PRINT("ms - next change_threshold is "); USER_PRINTLN(change_threshold); lastchange = millis(); + } + } uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { @@ -283,7 +289,9 @@ class AutoPlaylistUsermod : public Usermod { * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ void addToConfig(JsonObject& root) { + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + top[FPSTR(_enabled)] = enabled; top[FPSTR(_timeout)] = timeout; top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam @@ -292,8 +300,11 @@ class AutoPlaylistUsermod : public Usermod { top[FPSTR(_change_lockout)] = change_lockout; top[FPSTR(_ideal_change_min)] = ideal_change_min; top[FPSTR(_ideal_change_max)] = ideal_change_max; + lastAutoPlaylist = 0; + DEBUG_PRINTLN(F("AutoPlaylist config saved.")); + } /* @@ -307,7 +318,9 @@ class AutoPlaylistUsermod : public Usermod { * The function should return true if configuration was successfully loaded or false if there was no configuration. */ bool readFromConfig(JsonObject& root) { + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); @@ -328,6 +341,7 @@ class AutoPlaylistUsermod : public Usermod { // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; + } /* @@ -348,7 +362,6 @@ class AutoPlaylistUsermod : public Usermod { lastAutoPlaylist = id; } - }; const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; From 901e4fa83ea8d9d6e971cff2b6373b1221933688 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Mar 2024 22:19:10 -0400 Subject: [PATCH 20/59] Better automatic change_intervals --- .../usermod_v2_auto_playlist.h | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 44407616ce..39b14049dc 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -28,7 +28,7 @@ class AutoPlaylistUsermod : public Usermod { uint_fast32_t vector_zcr = 0; uint_fast32_t distance = 0; - + uint_fast32_t distance_tracker = UINT_FAST32_MAX; // uint_fast64_t squared_distance = 0; int lastchange = millis(); @@ -78,7 +78,7 @@ class AutoPlaylistUsermod : public Usermod { // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the squared_distance for the vector. - if (volumeSmth > 0.1) { + if (volumeSmth > 1) { avg_long_energy = avg_long_energy * 0.99 + energy * 0.01; avg_long_lfc = avg_long_lfc * 0.99 + lfc * 0.01; @@ -95,11 +95,17 @@ class AutoPlaylistUsermod : public Usermod { } + // distance is linear, squared_distance is magnitude. + // linear is easier to fine-tune, IMHO. distance = vector_lfc + vector_energy + vector_zcr; // squared_distance = distance * distance; int change_interval = millis()-lastchange; + if (distance < distance_tracker && change_interval > change_lockout) { + distance_tracker = distance; + } + // USER_PRINT("\tDistance: "); // USER_PRINT(distance); // USER_PRINT("\tv_lfc: "); @@ -114,9 +120,13 @@ class AutoPlaylistUsermod : public Usermod { // Sometimes the analysis lowers the change_threshold too much for // the current music, especially after track changes or during // sparce intros and breakdowns. - if (change_interval > ideal_change_min) { - change_threshold++; + if (change_interval > ideal_change_min && distance_tracker < 1000) { + // change_threshold++; + change_threshold += distance_tracker/10; USER_PRINTF("Increasing change_threshold to: %d\n",change_threshold); + USER_PRINT (" lowest recorded distance was: "); + USER_PRINTLN(distance_tracker); + distance_tracker = UINT_FAST32_MAX; } change_timer = millis(); } @@ -124,11 +134,17 @@ class AutoPlaylistUsermod : public Usermod { // WLED-MM/TroyHacks - Change pattern testing // if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { + if (change_interval > ideal_change_max) { - change_threshold += 1; + // change_threshold += 1; + change_threshold += distance/10; } else if (change_interval < ideal_change_min) { - change_threshold -= 1; + // change_threshold -= 1; + change_threshold -= distance/10; } + + distance_tracker = UINT_FAST32_MAX; + if (change_threshold < 0) change_threshold = 0; if(autoChangeIds.size() == 0) { @@ -144,7 +160,7 @@ class AutoPlaylistUsermod : public Usermod { uint8_t newpreset = 0; do { - newpreset = autoChangeIds.at(random(0, (autoChangeIds.size() - 1))); + newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. } while (currentPreset == newpreset); From 5ff44755d81a7f1431eb7c1aff2dfa47fb0487a5 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:19:05 -0400 Subject: [PATCH 21/59] calculations based on normalized FFT results --- usermods/audioreactive/audio_reactive.h | 34 +++++++++---------- .../usermod_v2_auto_playlist.h | 19 ++++++----- wled00/FX_2Dfcn.cpp | 2 +- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index db6f50654a..0d302db443 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -498,20 +498,16 @@ void FFTcode(void * parameter) // get a fresh batch of samples from I2S if (audioSource) audioSource->getSamples(vReal, samplesFFT); - + // WLED-MM/TroyHacks: Calculate zero crossings // zeroCrossingCount = 0; - energy = 0; - for (int i=0; i < samplesFFT; i++) { if (i < (samplesFFT)-2) { if((vReal[i] >= 0 && vReal[i+1] < 0) || (vReal[i+1] < 0 && vReal[i+1] >= 0)) { zeroCrossingCount++; } } - // WLED-MM/TroyHacks: Calculate energy - energy += (vReal[i] * vReal[i])/10000000; } #if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS) @@ -645,17 +641,6 @@ void FFTcode(void * parameter) #endif FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects FFT_MajPeakSmth = FFT_MajPeakSmth + 0.42 * (FFT_MajorPeak - FFT_MajPeakSmth); // I like this "swooping peak" look - - // WLED-MM/TroyHacks: Calculate Low-Frequency Content - // - lowFreqencyContent = fftAddAvg(2,4)/1000; - - // USER_PRINT("ZCR = "); - // USER_PRINT(zeroCrossingCount); - // USER_PRINT(" Energy = "); - // USER_PRINT(" LFC = "); - // USER_PRINT(lowFreqencyContent); - // USER_PRINTLN(); } else { // skip second run --> clear fft results, keep peaks memset(vReal, 0, sizeof(vReal)); @@ -801,7 +786,22 @@ void FFTcode(void * parameter) // run peak detection autoResetPeak(); detectSamplePeak(); - + + // WLED-MM/TroyHacks: Calculate Energy & Low-Frequency Content + // + energy = 0; + for (int i=0; i < NUM_GEQ_CHANNELS; i++) { + energy += fftResult[i]; + } + energy *= energy; + energy /= 10000; + lowFreqencyContent = fftResult[0]; + + // WLED-MM/TroyHacks: Ideally these numbers are roughly in the same rations + // ...but more importantly hitting a zero point at a regular interval + // + // USER_PRINTF("ZCR: %3lu Energy: %5lu LFC: %4lu\n",(unsigned long)zeroCrossingCount,(unsigned long)energy,(unsigned long)lowFreqencyContent) + // we have new results - notify UDP sound send haveNewFFTResult = true; diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 39b14049dc..dc23135cbf 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -121,12 +121,15 @@ class AutoPlaylistUsermod : public Usermod { // the current music, especially after track changes or during // sparce intros and breakdowns. if (change_interval > ideal_change_min && distance_tracker < 1000) { - // change_threshold++; - change_threshold += distance_tracker/10; - USER_PRINTF("Increasing change_threshold to: %d\n",change_threshold); - USER_PRINT (" lowest recorded distance was: "); + + change_threshold += distance_tracker>10?distance_tracker/10:1; + + USER_PRINT ("The lowest recorded distance was: "); USER_PRINTLN(distance_tracker); + USER_PRINTF("Increasing change_threshold to: %d\n",change_threshold); + distance_tracker = UINT_FAST32_MAX; + } change_timer = millis(); } @@ -136,11 +139,9 @@ class AutoPlaylistUsermod : public Usermod { if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { if (change_interval > ideal_change_max) { - // change_threshold += 1; - change_threshold += distance/10; + change_threshold += distance_tracker>10?distance_tracker/10:1; } else if (change_interval < ideal_change_min) { - // change_threshold -= 1; - change_threshold -= distance/10; + change_threshold -= distance_tracker>10?distance_tracker/10:1; } distance_tracker = UINT_FAST32_MAX; @@ -162,7 +163,7 @@ class AutoPlaylistUsermod : public Usermod { do { newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. } - while (currentPreset == newpreset); + while (currentPreset == newpreset); // make sure we get a different random preset. applyPreset(newpreset); diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 999684b1b2..166536e10f 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -64,7 +64,7 @@ void WS2812FX::setUpMatrix() { return; } - USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight); + // TroyHacks temp commented out, FIXME and put back: USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight); //WLEDMM recreate customMappingTable if more space needed if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) { From b52773c1d31484d362cd2af99c33c909b66be5f1 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:27:12 -0400 Subject: [PATCH 22/59] comments and some temp removal of other debug --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 4 ++-- wled00/FX_fcn.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index dc23135cbf..36cece7242 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -34,9 +34,9 @@ class AutoPlaylistUsermod : public Usermod { int lastchange = millis(); int last_beat_interval = millis(); - int change_threshold = 50; + int change_threshold = 50; // arbitrary starting point. - int change_lockout = 1000; // never change below this numnber of millis. I think of this more like a debounce, but opinions may vary. + int change_lockout = 1000; // never change below this number of millis. I think of this more like a debounce, but opinions may vary. int ideal_change_min = 10000; // ideally change patterns no less than this number of millis int ideal_change_max = 20000; // ideally change patterns no more than this number of millis diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index fa46432083..d70096adad 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -124,7 +124,7 @@ void Segment::allocLeds() { } // softhack007 clean up buffer } if ((size > 0) && (!ledsrgb || size > ledsrgbSize)) { //softhack dont allocate zero bytes - USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0); + // TroyHacks: FIXME reneable this later: USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0); if (ledsrgb) free(ledsrgb); // we need a bigger buffer, so free the old one first ledsrgb = (CRGB*)calloc(size, 1); ledsrgbSize = ledsrgb?size:0; From 977002f30c0ee5218960b5dfae012e398e5bce3b Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:58:34 -0400 Subject: [PATCH 23/59] better debug messages --- .../usermod_v2_auto_playlist.h | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 36cece7242..2a4bfe6a57 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -124,9 +124,7 @@ class AutoPlaylistUsermod : public Usermod { change_threshold += distance_tracker>10?distance_tracker/10:1; - USER_PRINT ("The lowest recorded distance was: "); - USER_PRINTLN(distance_tracker); - USER_PRINTF("Increasing change_threshold to: %d\n",change_threshold); + USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,(distance_tracker>10?distance_tracker/10:1),change_threshold); distance_tracker = UINT_FAST32_MAX; @@ -149,12 +147,12 @@ class AutoPlaylistUsermod : public Usermod { if (change_threshold < 0) change_threshold = 0; if(autoChangeIds.size() == 0) { - USER_PRINTF("Loading presets from playlist:%u\n", currentPlaylist); + USER_PRINTF("Loading presets from playlist: %3u\n", currentPlaylist); JsonObject playtlistOjb = doc.to(); serializePlaylist(playtlistOjb); JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; for(JsonVariant v : playlistArray) { - USER_PRINTF("Adding %u to autoChangeIds\n", v.as()); + USER_PRINTF("Adding %3u to autoChangeIds\n", v.as()); autoChangeIds.push_back(v.as()); } } @@ -167,12 +165,8 @@ class AutoPlaylistUsermod : public Usermod { applyPreset(newpreset); - USER_PRINT("*** CHANGE! Vector distance = "); - USER_PRINT(distance); - USER_PRINT(" - change_interval was "); - USER_PRINT(change_interval); - USER_PRINT("ms - next change_threshold is "); - USER_PRINTLN(change_threshold); + USER_PRINTF("*** CHANGE! Vector distance =%4lu - change_interval was %5dms - next change_threshold is %3d\n",(unsigned long)distance,change_interval,change_threshold); + lastchange = millis(); } From cc01e38cadd336486d4788ab510a91e7497fab02 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:15:31 -0400 Subject: [PATCH 24/59] Comments added. --- usermods/audioreactive/audio_reactive.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 0d302db443..959ab54ca6 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -794,11 +794,11 @@ void FFTcode(void * parameter) energy += fftResult[i]; } energy *= energy; - energy /= 10000; + energy /= 10000; // scale down so we get 0 sometimes lowFreqencyContent = fftResult[0]; - // WLED-MM/TroyHacks: Ideally these numbers are roughly in the same rations - // ...but more importantly hitting a zero point at a regular interval + // WLED-MM/TroyHacks: Ideally these numbers are roughly in the same ratios + // ...but most importantly all values need to be hitting zero at a regular interval // // USER_PRINTF("ZCR: %3lu Energy: %5lu LFC: %4lu\n",(unsigned long)zeroCrossingCount,(unsigned long)energy,(unsigned long)lowFreqencyContent) From 22be977df8a2a373cec99db8c554142aab87fb24 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:19:13 -0400 Subject: [PATCH 25/59] IfDefs to quiet some other debug lines during debugging. --- wled00/FX_2Dfcn.cpp | 4 +++- wled00/FX_fcn.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 166536e10f..b013457e68 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -64,7 +64,9 @@ void WS2812FX::setUpMatrix() { return; } - // TroyHacks temp commented out, FIXME and put back: USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight); + #ifndef USERMOD_AUTO_PLAYLIST // TroyHacks - FIXME: just tidy output temporarily while debugging + USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight); + #endif //WLEDMM recreate customMappingTable if more space needed if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) { diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d70096adad..68c0d7dc55 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -124,7 +124,9 @@ void Segment::allocLeds() { } // softhack007 clean up buffer } if ((size > 0) && (!ledsrgb || size > ledsrgbSize)) { //softhack dont allocate zero bytes - // TroyHacks: FIXME reneable this later: USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0); + #ifndef USERMOD_AUTO_PLAYLIST // TroyHacks - FIXME: just tidy output temporarily while debugging + USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0); + #endif if (ledsrgb) free(ledsrgb); // we need a bigger buffer, so free the old one first ledsrgb = (CRGB*)calloc(size, 1); ledsrgbSize = ledsrgb?size:0; From 793b1089ac55dd92634d2564c924b15bff22658b Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:42:12 -0400 Subject: [PATCH 26/59] Better debug --- .../usermod_v2_auto_playlist.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 2a4bfe6a57..c8060764fe 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -102,18 +102,11 @@ class AutoPlaylistUsermod : public Usermod { int change_interval = millis()-lastchange; - if (distance < distance_tracker && change_interval > change_lockout) { + if (distance < distance_tracker && change_interval > change_lockout && volumeSmth > 1) { distance_tracker = distance; } - // USER_PRINT("\tDistance: "); - // USER_PRINT(distance); - // USER_PRINT("\tv_lfc: "); - // USER_PRINT(vector_lfc); - // USER_PRINT("\tv_energy: "); - // USER_PRINT(vector_energy); - // USER_PRINT("\tv_zcr: "); - // USER_PRINTLN(vector_zcr); + // USER_PRINTF("Distance: %3lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); if (millis() > change_timer + ideal_change_min) { // Make the analysis less sensitive if we miss the window, slowly. From 3279134a4bdb7ffda12fa64c7dfd7ae283772e54 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:52:33 -0400 Subject: [PATCH 27/59] Tidy --- .../usermod_v2_auto_playlist.h | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index c8060764fe..e4cc521633 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -2,10 +2,10 @@ #include "wled.h" - class AutoPlaylistUsermod : public Usermod { private: + bool silenceDetected = true; uint32_t lastSoundTime = 0; byte ambientPlaylist = 1; @@ -36,7 +36,7 @@ class AutoPlaylistUsermod : public Usermod { int last_beat_interval = millis(); int change_threshold = 50; // arbitrary starting point. - int change_lockout = 1000; // never change below this number of millis. I think of this more like a debounce, but opinions may vary. + int change_lockout = 1000; // never change below this number of millis. I think of this more like a debounce, but opinions may vary. int ideal_change_min = 10000; // ideally change patterns no less than this number of millis int ideal_change_max = 20000; // ideally change patterns no more than this number of millis @@ -109,10 +109,12 @@ class AutoPlaylistUsermod : public Usermod { // USER_PRINTF("Distance: %3lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); if (millis() > change_timer + ideal_change_min) { + // Make the analysis less sensitive if we miss the window, slowly. // Sometimes the analysis lowers the change_threshold too much for // the current music, especially after track changes or during // sparce intros and breakdowns. + if (change_interval > ideal_change_min && distance_tracker < 1000) { change_threshold += distance_tracker>10?distance_tracker/10:1; @@ -122,11 +124,11 @@ class AutoPlaylistUsermod : public Usermod { distance_tracker = UINT_FAST32_MAX; } + change_timer = millis(); + } - // WLED-MM/TroyHacks - Change pattern testing - // if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { if (change_interval > ideal_change_max) { @@ -139,18 +141,23 @@ class AutoPlaylistUsermod : public Usermod { if (change_threshold < 0) change_threshold = 0; - if(autoChangeIds.size() == 0) { + if (autoChangeIds.size() == 0) { + USER_PRINTF("Loading presets from playlist: %3u\n", currentPlaylist); + JsonObject playtlistOjb = doc.to(); serializePlaylist(playtlistOjb); JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; + for(JsonVariant v : playlistArray) { USER_PRINTF("Adding %3u to autoChangeIds\n", v.as()); autoChangeIds.push_back(v.as()); } + } uint8_t newpreset = 0; + do { newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. } @@ -166,68 +173,60 @@ class AutoPlaylistUsermod : public Usermod { } - uint8_t getFFTFromRange(um_data_t *data, uint8_t from, uint8_t to) { - uint8_t *fftResult = (uint8_t*) data->u_data[2]; - uint16_t result = 0; - for (int i = from; i <= to; i++) { - result += fftResult[i]; // * fftResult[i]; - } - return result / float(to - from + 1); // sqrt(result / (to - from + 1)); - } - /* * Da loop. */ void loop() { - if(millis() < 10000) return; // Wait for device to settle + if (millis() < 10000) return; // Wait for device to settle - if(lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { - if(currentPlaylist == musicPlaylist) { + if (lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { + if (currentPlaylist == musicPlaylist) { USER_PRINTF("AutoPlaylist: enabled due to manual change of playlist back to %u\n", currentPlaylist); enabled = true; lastAutoPlaylist = currentPlaylist; - } - else if(enabled) { + } else if (enabled) { USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); enabled = false; } } - if(!enabled && currentPlaylist == musicPlaylist) { + + if (!enabled && currentPlaylist == musicPlaylist) { USER_PRINTF("AutoPlaylist: enabled due selecting musicPlaylist(%u)", musicPlaylist); enabled = true; } - if(!enabled) return; - if(bri == 0) return; + if (!enabled) return; + + if (bri == 0) return; um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // No Audio Reactive silenceDetected = true; return; } - float volumeSmth = *(float*)um_data->u_data[0]; + float volumeSmth = *(float*)um_data->u_data[0]; - if(volumeSmth > 0.5) { + if (volumeSmth > 0.5) { lastSoundTime = millis(); } - if(millis() - lastSoundTime > (timeout * 1000)) { - if(!silenceDetected) { + if (millis() - lastSoundTime > (timeout * 1000)) { + if (!silenceDetected) { silenceDetected = true; USER_PRINTF("AutoPlaylist: Silence "); changePlaylist(ambientPlaylist); } - } - else { - if(silenceDetected) { + } else { + if (silenceDetected) { silenceDetected = false; USER_PRINTF("AutoPlaylist: End of silence "); changePlaylist(musicPlaylist); } - if(autoChange) change(um_data); + if (autoChange) change(um_data); } } @@ -237,7 +236,9 @@ class AutoPlaylistUsermod : public Usermod { * Below it is shown how this could be used for e.g. a light sensor */ void addToJsonInfo(JsonObject& root) { + JsonObject user = root["u"]; + if (user.isNull()) { user = root.createNestedObject("u"); } @@ -245,12 +246,13 @@ class AutoPlaylistUsermod : public Usermod { JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name infoArr = user.createNestedArray(F("")); - if(!enabled) { + + if (!enabled) { infoArr.add("disabled"); - } - else { + } else { infoArr.add(lastSoundTime); } + } /* @@ -358,12 +360,12 @@ class AutoPlaylistUsermod : public Usermod { private: - void changePlaylist(byte id) { - String name = ""; - getPresetName(id, name); - USER_PRINTF("apply %s\n", name.c_str()); - applyPreset(id, CALL_MODE_NOTIFICATION); - lastAutoPlaylist = id; + void changePlaylist(byte id) { + String name = ""; + getPresetName(id, name); + USER_PRINTF("apply %s\n", name.c_str()); + applyPreset(id, CALL_MODE_NOTIFICATION); + lastAutoPlaylist = id; } }; From 13bfe6018dd6904be656aa628183c902eec56848 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Tue, 26 Mar 2024 08:13:56 -0400 Subject: [PATCH 28/59] Faster change_threshold catch-up --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index e4cc521633..0208ec7c7e 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -76,7 +76,7 @@ class AutoPlaylistUsermod : public Usermod { uint_fast32_t lfc = *(uint_fast32_t*)um_data->u_data[13]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages - // and the squared_distance for the vector. + // and the individual vector distances. if (volumeSmth > 1) { @@ -117,9 +117,11 @@ class AutoPlaylistUsermod : public Usermod { if (change_interval > ideal_change_min && distance_tracker < 1000) { - change_threshold += distance_tracker>10?distance_tracker/10:1; + // change_threshold += distance_tracker>10?distance_tracker/10:1; + change_threshold += ((distance_tracker-change_threshold)/2)>1?(distance_tracker-change_threshold)/2:1; - USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,(distance_tracker>10?distance_tracker/10:1),change_threshold); + // USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,(distance_tracker>10?distance_tracker/10:1),change_threshold); + USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,((distance_tracker-change_threshold)/2)>1?(distance_tracker-change_threshold)/2:1,change_threshold); distance_tracker = UINT_FAST32_MAX; From d922374e92794a69a0e7e4443dbcbdf727ae2fc4 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:48:55 -0400 Subject: [PATCH 29/59] Better change window tracking. --- .../usermod_v2_auto_playlist.h | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 0208ec7c7e..eddddb3cd9 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -33,10 +33,10 @@ class AutoPlaylistUsermod : public Usermod { int lastchange = millis(); - int last_beat_interval = millis(); - int change_threshold = 50; // arbitrary starting point. + int_fast16_t change_threshold = 50; // arbitrary starting point. + uint_fast16_t change_threshold_change = 0; - int change_lockout = 1000; // never change below this number of millis. I think of this more like a debounce, but opinions may vary. + int change_lockout = 1000; // never change below this number of millis. Ideally 60000/your_average_bpm*beats_to_skip = change_lockout (1000 = skip 2 beats at 120bpm) int ideal_change_min = 10000; // ideally change patterns no less than this number of millis int ideal_change_max = 20000; // ideally change patterns no more than this number of millis @@ -117,11 +117,10 @@ class AutoPlaylistUsermod : public Usermod { if (change_interval > ideal_change_min && distance_tracker < 1000) { - // change_threshold += distance_tracker>10?distance_tracker/10:1; - change_threshold += ((distance_tracker-change_threshold)/2)>1?(distance_tracker-change_threshold)/2:1; + change_threshold_change = (distance_tracker)-change_threshold; + change_threshold = distance_tracker; - // USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,(distance_tracker>10?distance_tracker/10:1),change_threshold); - USER_PRINTF("The lowest recorded distance was: %3lu - change_threshold increased by %2u to %3u\n", (unsigned long)distance_tracker,((distance_tracker-change_threshold)/2)>1?(distance_tracker-change_threshold)/2:1,change_threshold); + USER_PRINTF("--- lowest distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); distance_tracker = UINT_FAST32_MAX; @@ -133,15 +132,21 @@ class AutoPlaylistUsermod : public Usermod { if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { + change_threshold_change = change_threshold-(distance*0.9); + + if (change_threshold_change < 1) change_threshold_change = 1; + if (change_interval > ideal_change_max) { - change_threshold += distance_tracker>10?distance_tracker/10:1; + change_threshold += change_threshold_change; } else if (change_interval < ideal_change_min) { - change_threshold -= distance_tracker>10?distance_tracker/10:1; + change_threshold -= change_threshold_change; + } else { + change_threshold_change = 0; } - distance_tracker = UINT_FAST32_MAX; + if (change_threshold < 1) change_threshold = 0; // we need change_threshold to be signed becasue otherwise this wraps to UINT_FAST16_MAX - if (change_threshold < 0) change_threshold = 0; + distance_tracker = UINT_FAST32_MAX; if (autoChangeIds.size() == 0) { @@ -167,7 +172,7 @@ class AutoPlaylistUsermod : public Usermod { applyPreset(newpreset); - USER_PRINTF("*** CHANGE! Vector distance =%4lu - change_interval was %5dms - next change_threshold is %3d\n",(unsigned long)distance,change_interval,change_threshold); + USER_PRINTF("*** CHANGE distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); lastchange = millis(); From 022b3100f119c61473c01aa9c093a680ef466805 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:15:03 -0400 Subject: [PATCH 30/59] Comments and debug faff. --- .../usermod_v2_auto_playlist.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index eddddb3cd9..5a1ec6d923 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -110,7 +110,7 @@ class AutoPlaylistUsermod : public Usermod { if (millis() > change_timer + ideal_change_min) { - // Make the analysis less sensitive if we miss the window, slowly. + // Make the analysis less sensitive if we miss the window. // Sometimes the analysis lowers the change_threshold too much for // the current music, especially after track changes or during // sparce intros and breakdowns. @@ -120,7 +120,7 @@ class AutoPlaylistUsermod : public Usermod { change_threshold_change = (distance_tracker)-change_threshold; change_threshold = distance_tracker; - USER_PRINTF("--- lowest distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("--- lowest distance =%4lu - no changes done in %6ums - next change_threshold is %3u (%3u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); distance_tracker = UINT_FAST32_MAX; @@ -129,22 +129,22 @@ class AutoPlaylistUsermod : public Usermod { change_timer = millis(); } - - if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 0.1) { + + if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1) { change_threshold_change = change_threshold-(distance*0.9); if (change_threshold_change < 1) change_threshold_change = 1; if (change_interval > ideal_change_max) { - change_threshold += change_threshold_change; + change_threshold += change_threshold_change; // make changes more sensitive } else if (change_interval < ideal_change_min) { - change_threshold -= change_threshold_change; + change_threshold -= change_threshold_change; // make changes less sensitive } else { - change_threshold_change = 0; + change_threshold_change = 0; // change was within our window, no sensitivity change } - if (change_threshold < 1) change_threshold = 0; // we need change_threshold to be signed becasue otherwise this wraps to UINT_FAST16_MAX + if (change_threshold < 1) change_threshold = 0; // we need change_threshold to be signed becasue otherwise this wraps to UINT_FAST16_MAX distance_tracker = UINT_FAST32_MAX; From 58184a5a74ab3ec3e5ff1d25a9f28e4c0743d39e Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:45:32 -0400 Subject: [PATCH 31/59] Moved calcs into usermod except zero crossings --- usermods/audioreactive/audio_reactive.h | 26 ++----------------- .../usermod_v2_auto_playlist.h | 16 +++++++++--- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 959ab54ca6..8a5610be6f 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -141,9 +141,7 @@ static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. chann 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) -uint_fast32_t zeroCrossingCount = 0; -uint_fast32_t energy = 0; -uint_fast32_t lowFreqencyContent = 0; +uint_fast16_t zeroCrossingCount = 0; // 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 @@ -787,22 +785,6 @@ void FFTcode(void * parameter) autoResetPeak(); detectSamplePeak(); - // WLED-MM/TroyHacks: Calculate Energy & Low-Frequency Content - // - energy = 0; - for (int i=0; i < NUM_GEQ_CHANNELS; i++) { - energy += fftResult[i]; - } - energy *= energy; - energy /= 10000; // scale down so we get 0 sometimes - lowFreqencyContent = fftResult[0]; - - // WLED-MM/TroyHacks: Ideally these numbers are roughly in the same ratios - // ...but most importantly all values need to be hitting zero at a regular interval - // - // USER_PRINTF("ZCR: %3lu Energy: %5lu LFC: %4lu\n",(unsigned long)zeroCrossingCount,(unsigned long)energy,(unsigned long)lowFreqencyContent) - - // we have new results - notify UDP sound send haveNewFFTResult = true; #if !defined(I2S_GRAB_ADC1_COMPLETELY) @@ -1778,11 +1760,7 @@ class AudioReactive : public Usermod { um_data->u_data[10] = &agcSensitivity; // used (New) um_data->u_type[10] = UMT_FLOAT; um_data->u_data[11] = &zeroCrossingCount; - um_data->u_type[11] = UMT_UINT32; - um_data->u_data[12] = &energy; - um_data->u_type[12] = UMT_UINT32; - um_data->u_data[13] = &lowFreqencyContent; - um_data->u_type[13] = UMT_UINT32; + um_data->u_type[11] = UMT_UINT16; #else // ESP8266 // See https://github.com/MoonModules/WLED/pull/60#issuecomment-1666972133 for explanation of these alternative sources of data diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 5a1ec6d923..b07d11787c 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -15,6 +15,8 @@ class AutoPlaylistUsermod : public Usermod { byte lastAutoPlaylist = 0; int change_timer = millis(); + uint_fast32_t energy = 0; + uint_fast32_t avg_long_energy = 250; uint_fast32_t avg_long_lfc = 1000; uint_fast32_t avg_long_zcr = 500; @@ -71,9 +73,17 @@ class AutoPlaylistUsermod : public Usermod { void change(um_data_t *um_data) { - uint_fast32_t zcr = *(uint_fast32_t*)um_data->u_data[11]; - uint_fast32_t energy = *(uint_fast32_t*)um_data->u_data[12]; - uint_fast32_t lfc = *(uint_fast32_t*)um_data->u_data[13]; + uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; + + for (int i=0; i < NUM_GEQ_CHANNELS; i++) { + energy += fftResult[i]; + } + + energy *= energy; + energy /= 10000; // scale down so we get 0 sometimes + + uint8_t lfc = fftResult[0]; + uint_fast16_t zcr = *(uint_fast16_t*)um_data->u_data[11]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the individual vector distances. From 9b8f0ba873c3019a133a2a9c46390c079a2cdc44 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:12:38 -0400 Subject: [PATCH 32/59] Bug fix with um_data length --- usermods/audioreactive/audio_reactive.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 8a5610be6f..c938c465ee 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1733,7 +1733,7 @@ class AudioReactive : public Usermod { // usermod exchangeable data // we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers um_data = new um_data_t; - um_data->u_size = 13; + um_data->u_size = 11; um_data->u_type = new um_types_t[um_data->u_size]; um_data->u_data = new void*[um_data->u_size]; um_data->u_data[0] = &volumeSmth; //*used (New) From cd8884dbf7dc11cff9dc61628c9668c8c8f2a7a2 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Thu, 28 Mar 2024 08:55:18 -0400 Subject: [PATCH 33/59] Skip change logic for distance freefall --- .../usermod_v2_auto_playlist.h | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index b07d11787c..9eb438d8f4 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -180,11 +180,26 @@ class AutoPlaylistUsermod : public Usermod { } while (currentPreset == newpreset); // make sure we get a different random preset. - applyPreset(newpreset); + if (change_interval > change_lockout+3) { - USER_PRINTF("*** CHANGE distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + // Make sure we have a statistically significant change and we aren't + // just bouncing off change_lockout. That's valid for changing the + // thresholds, but might be a bit crazy for lighting changes. + // When the music changes quite a bit, the distance calculation can + // go into freefall - this logic stops that from triggering right + // after change_lockout. Better for smaller change_lockout values. - lastchange = millis(); + applyPreset(newpreset); + + USER_PRINTF("*** CHANGE distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + + } else { + + USER_PRINTF("*** SKIP!! distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + + } + + lastchange = millis(); } From 494646a21e3b4e85be6d9a4b0f254fb60bd7fa0a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 26 Mar 2024 20:08:22 +0000 Subject: [PATCH 34/59] Tweak status --- .../usermod_v2_auto_playlist.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 9eb438d8f4..debb7e5769 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -278,11 +278,11 @@ class AutoPlaylistUsermod : public Usermod { JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name infoArr = user.createNestedArray(F("")); - - if (!enabled) { - infoArr.add("disabled"); - } else { - infoArr.add(lastSoundTime); + if(!enabled) { + infoArr.add(""); + } + else { + infoArr.add("Active"); } } From cce7d4c79e964497ff5410acf7201e643a771f93 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 28 Mar 2024 19:57:42 +0000 Subject: [PATCH 35/59] Cleanup --- usermods/audioreactive/audio_reactive.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index c938c465ee..191e60d03e 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -36,7 +36,7 @@ #endif #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) -// this applies "pink noise scaling" to FFT results before computing the major peak for effects.0 +// this applies "pink noise scaling" to FFT results before computing the major peak for effects. // currently only for ESP32-S3 and classic ESP32, due to increased runtime #define FFT_MAJORPEAK_HUMAN_EAR #endif From 1e934d342604417039dee50c88491bafa906b9a9 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 29 Mar 2024 12:47:51 +0000 Subject: [PATCH 36/59] Prevent crash trying to load playlist -1 --- usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index debb7e5769..deead6d692 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -159,8 +159,9 @@ class AutoPlaylistUsermod : public Usermod { distance_tracker = UINT_FAST32_MAX; if (autoChangeIds.size() == 0) { + if(currentPlaylist < 1) return; - USER_PRINTF("Loading presets from playlist: %3u\n", currentPlaylist); + USER_PRINTF("Loading presets from playlist: %3d\n", currentPlaylist); JsonObject playtlistOjb = doc.to(); serializePlaylist(playtlistOjb); From 04a8681f717c802b909309ea9f28c8f044b80fd2 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 30 Mar 2024 11:09:14 -0400 Subject: [PATCH 37/59] WM8978 fix for IDF below 4.2.0 --- usermods/audioreactive/audio_source.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index bd02696823..0e0a2153ac 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -649,7 +649,13 @@ class WM8978Source : public I2SSource { _wm8978I2cWrite( 1,0b000111110); // Power Management 1 - power off most things, but enable mic bias and I/O tie-off to help mitigate mic leakage. _wm8978I2cWrite( 2,0b110111111); // Power Management 2 - enable output and amp stages (amps may lift signal but it works better on the ADCs) _wm8978I2cWrite( 3,0b000001100); // Power Management 3 - enable L&R output mixers + + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) _wm8978I2cWrite( 4,0b001010000); // Audio Interface - standard I2S, 24-bit + #else + _wm8978I2cWrite( 4,0b001001000); // Audio Interface - left-justified I2S, 24-bit + #endif + _wm8978I2cWrite( 6,0b000000000); // Clock generation control - use external mclk _wm8978I2cWrite( 7,0b000000100); // Sets sample rate to ~24kHz (only used for internal calculations, not I2S) _wm8978I2cWrite(14,0b010001000); // 128x ADC oversampling - high pass filter disabled as it kills the bass response From c36adbdad07ec4e365e0414f484a1292da70a4d9 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 30 Mar 2024 12:30:32 -0400 Subject: [PATCH 38/59] Button added to Info panel. Logic needs work. --- .../usermod_v2_auto_playlist.h | 108 +++++++++--------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index deead6d692..c933980940 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -5,7 +5,8 @@ class AutoPlaylistUsermod : public Usermod { private: - + + bool initDone = false; bool silenceDetected = true; uint32_t lastSoundTime = 0; byte ambientPlaylist = 1; @@ -44,7 +45,8 @@ class AutoPlaylistUsermod : public Usermod { std::vector autoChangeIds; - static const char _enabled[]; + static const char _name[]; + static const char _autoPlaylistEnabled[]; static const char _ambientPlaylist[]; static const char _musicPlaylist[]; static const char _timeout[]; @@ -63,6 +65,7 @@ class AutoPlaylistUsermod : public Usermod { // network here void setup() { USER_PRINTLN("AutoPlaylistUsermod"); + initDone = true; } // gets called every time WiFi is (re-)connected. Initialize own network @@ -264,48 +267,46 @@ class AutoPlaylistUsermod : public Usermod { } /* - * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. - * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. - * Below it is shown how this could be used for e.g. a light sensor + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients */ void addToJsonInfo(JsonObject& root) { - JsonObject user = root["u"]; - if (user.isNull()) { user = root.createNestedObject("u"); } JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name - infoArr = user.createNestedArray(F("")); - if(!enabled) { - infoArr.add(""); - } - else { - infoArr.add("Active"); - } - + String uiDomString = F(""); + infoArr.add(uiDomString); } - /* - * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - //void addToJsonState(JsonObject& root) { - //} - /* * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). * Values in the state object may be modified by connected clients */ void readFromJsonState(JsonObject& root) { if (!initDone) return; // prevent crash on boot applyPreset() + bool en = enabled; JsonObject um = root[FPSTR(_name)]; if (!um.isNull()) { - if (um[FPSTR(_enabled)].is()) { - enabled = um[FPSTR(_enabled)].as(); + if (um[FPSTR(_autoPlaylistEnabled)].is()) { + en = um[FPSTR(_autoPlaylistEnabled)].as(); + } else { + String str = um[FPSTR(_autoPlaylistEnabled)]; // checkbox -> off or on + en = (bool)(str!="off"); // off is guaranteed to be present } + if (en != enabled) enabled = en; + USER_PRINT("AutoPlaylist enabled = "); + USER_PRINTLN(en); } } @@ -331,18 +332,18 @@ class AutoPlaylistUsermod : public Usermod { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - top[FPSTR(_enabled)] = enabled; - top[FPSTR(_timeout)] = timeout; - top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam - top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam - top[FPSTR(_autoChange)] = autoChange; - top[FPSTR(_change_lockout)] = change_lockout; - top[FPSTR(_ideal_change_min)] = ideal_change_min; - top[FPSTR(_ideal_change_max)] = ideal_change_max; + top[FPSTR(_autoPlaylistEnabled)] = enabled; + top[FPSTR(_timeout)] = timeout; + top[FPSTR(_ambientPlaylist)] = ambientPlaylist; // usermodparam + top[FPSTR(_musicPlaylist)] = musicPlaylist; // usermodparam + top[FPSTR(_autoChange)] = autoChange; + top[FPSTR(_change_lockout)] = change_lockout; + top[FPSTR(_ideal_change_min)] = ideal_change_min; + top[FPSTR(_ideal_change_max)] = ideal_change_max; lastAutoPlaylist = 0; - DEBUG_PRINTLN(F("AutoPlaylist config saved.")); + USER_PRINTLN(F("AutoPlaylist config saved.")); } @@ -361,22 +362,22 @@ class AutoPlaylistUsermod : public Usermod { JsonObject top = root[FPSTR(_name)]; if (top.isNull()) { - DEBUG_PRINT(FPSTR(_name)); - DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + USER_PRINT(FPSTR(_name)); + USER_PRINTLN(F(": No config found. (Using defaults.)")); return false; } - DEBUG_PRINT(FPSTR(_name)); - getJsonValue(top[_enabled], enabled); - getJsonValue(top[_timeout], timeout); - getJsonValue(top[_ambientPlaylist], ambientPlaylist); - getJsonValue(top[_musicPlaylist], musicPlaylist); - getJsonValue(top[_autoChange], autoChange); - getJsonValue(top[_change_lockout], change_lockout); - getJsonValue(top[_ideal_change_min], ideal_change_min); - getJsonValue(top[_ideal_change_max], ideal_change_max); + enabled = top[FPSTR(_autoPlaylistEnabled)] | enabled; + timeout = top[FPSTR(_timeout)] | timeout; + ambientPlaylist = top[FPSTR(_ambientPlaylist)] | ambientPlaylist; + musicPlaylist = top[FPSTR(_musicPlaylist)] | musicPlaylist; + autoChange = top[FPSTR(_autoChange)] | autoChange; + change_lockout = top[FPSTR(_change_lockout)] | change_lockout; + ideal_change_min = top[FPSTR(_ideal_change_min)] | ideal_change_min; + ideal_change_max = top[FPSTR(_ideal_change_max)] | ideal_change_max; - DEBUG_PRINTLN(F(" config (re)loaded.")); + USER_PRINT(FPSTR(_name)); + USER_PRINTLN(F(" config (re)loaded.")); // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; @@ -403,11 +404,12 @@ class AutoPlaylistUsermod : public Usermod { }; -const char AutoPlaylistUsermod::_enabled[] PROGMEM = "enabled"; -const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; -const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; -const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; -const char AutoPlaylistUsermod::_autoChange[] PROGMEM = "autoChange"; -const char AutoPlaylistUsermod::_change_lockout[] PROGMEM = "change_lockout"; -const char AutoPlaylistUsermod::_ideal_change_min[] PROGMEM = "ideal_change_min"; -const char AutoPlaylistUsermod::_ideal_change_max[] PROGMEM = "ideal_change_max"; +const char AutoPlaylistUsermod::_name[] PROGMEM = "AutoPlaylist"; +const char AutoPlaylistUsermod::_autoPlaylistEnabled[] PROGMEM = "enabled"; +const char AutoPlaylistUsermod::_ambientPlaylist[] PROGMEM = "ambientPlaylist"; +const char AutoPlaylistUsermod::_musicPlaylist[] PROGMEM = "musicPlaylist"; +const char AutoPlaylistUsermod::_timeout[] PROGMEM = "timeout"; +const char AutoPlaylistUsermod::_autoChange[] PROGMEM = "autoChange"; +const char AutoPlaylistUsermod::_change_lockout[] PROGMEM = "change_lockout"; +const char AutoPlaylistUsermod::_ideal_change_min[] PROGMEM = "ideal_change_min"; +const char AutoPlaylistUsermod::_ideal_change_max[] PROGMEM = "ideal_change_max"; From 1f659aa1bfc87c09ec395f75e7999b3b9f81db75 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 30 Mar 2024 12:54:28 -0400 Subject: [PATCH 39/59] "Enabled" mostly working --- .../usermod_v2_auto_playlist.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index c933980940..4237aabcd2 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -214,6 +214,8 @@ class AutoPlaylistUsermod : public Usermod { */ void loop() { + if (!enabled) return; + if (millis() < 10000) return; // Wait for device to settle if (lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { @@ -232,7 +234,7 @@ class AutoPlaylistUsermod : public Usermod { enabled = true; } - if (!enabled) return; + if (bri == 0) return; @@ -305,8 +307,8 @@ class AutoPlaylistUsermod : public Usermod { en = (bool)(str!="off"); // off is guaranteed to be present } if (en != enabled) enabled = en; - USER_PRINT("AutoPlaylist enabled = "); - USER_PRINTLN(en); + DEBUG_PRINT("AutoPlaylist enabled = "); + DEBUG_PRINTLN(en); } } @@ -343,7 +345,7 @@ class AutoPlaylistUsermod : public Usermod { lastAutoPlaylist = 0; - USER_PRINTLN(F("AutoPlaylist config saved.")); + DEBUG_PRINTLN(F("AutoPlaylist config saved.")); } @@ -376,8 +378,8 @@ class AutoPlaylistUsermod : public Usermod { ideal_change_min = top[FPSTR(_ideal_change_min)] | ideal_change_min; ideal_change_max = top[FPSTR(_ideal_change_max)] | ideal_change_max; - USER_PRINT(FPSTR(_name)); - USER_PRINTLN(F(" config (re)loaded.")); + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(" config (re)loaded.")); // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; From c3bf851613d1b6406f163638f8fc11cb78090be0 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 30 Mar 2024 15:09:59 -0400 Subject: [PATCH 40/59] Higher possible change threshold --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 4237aabcd2..d9211c438c 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -128,12 +128,12 @@ class AutoPlaylistUsermod : public Usermod { // the current music, especially after track changes or during // sparce intros and breakdowns. - if (change_interval > ideal_change_min && distance_tracker < 1000) { + if (change_interval > ideal_change_min && distance_tracker <= 9999) { change_threshold_change = (distance_tracker)-change_threshold; change_threshold = distance_tracker; - USER_PRINTF("--- lowest distance =%4lu - no changes done in %6ums - next change_threshold is %3u (%3u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ums - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); distance_tracker = UINT_FAST32_MAX; @@ -195,15 +195,16 @@ class AutoPlaylistUsermod : public Usermod { applyPreset(newpreset); - USER_PRINTF("*** CHANGE distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ums - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); } else { - USER_PRINTF("*** SKIP!! distance =%4lu - change_interval was %5ums - next change_threshold is %3u (%3u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ums - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); } lastchange = millis(); + change_timer = millis(); } From b72e402a2dea3feac69c05a558654d193a6d0f2c Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 5 Apr 2024 00:31:14 +0200 Subject: [PATCH 41/59] bugfixing * make filters work (requires float instead of integer) * avoid "expression propagation to double" by using float constants * use unsigned long for all variables that depend on millis() --- .../usermod_v2_auto_playlist.h | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index d9211c438c..94885e475f 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -8,23 +8,23 @@ class AutoPlaylistUsermod : public Usermod { bool initDone = false; bool silenceDetected = true; - uint32_t lastSoundTime = 0; + unsigned long lastSoundTime = 0; byte ambientPlaylist = 1; byte musicPlaylist = 2; int timeout = 60; bool autoChange = false; byte lastAutoPlaylist = 0; - int change_timer = millis(); + unsigned long change_timer = millis(); uint_fast32_t energy = 0; - uint_fast32_t avg_long_energy = 250; - uint_fast32_t avg_long_lfc = 1000; - uint_fast32_t avg_long_zcr = 500; + float avg_long_energy = 250; + float avg_long_lfc = 1000; + float avg_long_zcr = 500; - uint_fast32_t avg_short_energy = 250; - uint_fast32_t avg_short_lfc = 1000; - uint_fast32_t avg_short_zcr = 500; + float avg_short_energy = 250; + float avg_short_lfc = 1000; + float avg_short_zcr = 500; uint_fast32_t vector_energy = 0; uint_fast32_t vector_lfc = 0; @@ -34,7 +34,7 @@ class AutoPlaylistUsermod : public Usermod { uint_fast32_t distance_tracker = UINT_FAST32_MAX; // uint_fast64_t squared_distance = 0; - int lastchange = millis(); + unsigned long lastchange = millis(); int_fast16_t change_threshold = 50; // arbitrary starting point. uint_fast16_t change_threshold_change = 0; @@ -86,20 +86,21 @@ class AutoPlaylistUsermod : public Usermod { energy /= 10000; // scale down so we get 0 sometimes uint8_t lfc = fftResult[0]; - uint_fast16_t zcr = *(uint_fast16_t*)um_data->u_data[11]; + uint16_t zcr = *(uint16_t*)um_data->u_data[11]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages // and the individual vector distances. - if (volumeSmth > 1) { + if (volumeSmth > 1.0f) { - avg_long_energy = avg_long_energy * 0.99 + energy * 0.01; - avg_long_lfc = avg_long_lfc * 0.99 + lfc * 0.01; - avg_long_zcr = avg_long_zcr * 0.99 + zcr * 0.01; + // softhack007: original code used 0.998f as decay factor + avg_long_energy = avg_long_energy * 0.99f + energy * 0.01f; + avg_long_lfc = avg_long_lfc * 0.99f + lfc * 0.01f; + avg_long_zcr = avg_long_zcr * 0.99f + zcr * 0.01f; - avg_short_energy = avg_short_energy * 0.9 + energy * 0.1; - avg_short_lfc = avg_short_lfc * 0.9 + lfc * 0.1; - avg_short_zcr = avg_short_zcr * 0.9 + zcr * 0.1; + avg_short_energy = avg_short_energy * 0.9f + energy * 0.1f; + avg_short_lfc = avg_short_lfc * 0.9f + lfc * 0.1f; + avg_short_zcr = avg_short_zcr * 0.9f + zcr * 0.1f; // allegedly this is faster than pow(whatever,2) vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); @@ -113,15 +114,15 @@ class AutoPlaylistUsermod : public Usermod { distance = vector_lfc + vector_energy + vector_zcr; // squared_distance = distance * distance; - int change_interval = millis()-lastchange; + long change_interval = millis()-lastchange; - if (distance < distance_tracker && change_interval > change_lockout && volumeSmth > 1) { + if (distance < distance_tracker && change_interval > change_lockout && volumeSmth > 1.0f) { distance_tracker = distance; } // USER_PRINTF("Distance: %3lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); - if (millis() > change_timer + ideal_change_min) { + if ((millis() - change_timer) > ideal_change_min) { // softhack007 same result as "millis() > change_timer + ideal_change_min", but more robust against unsigned overflow // Make the analysis less sensitive if we miss the window. // Sometimes the analysis lowers the change_threshold too much for @@ -133,7 +134,7 @@ class AutoPlaylistUsermod : public Usermod { change_threshold_change = (distance_tracker)-change_threshold; change_threshold = distance_tracker; - USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ums - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); distance_tracker = UINT_FAST32_MAX; @@ -143,9 +144,9 @@ class AutoPlaylistUsermod : public Usermod { } - if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1) { + if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { - change_threshold_change = change_threshold-(distance*0.9); + change_threshold_change = change_threshold-(distance*0.9f); if (change_threshold_change < 1) change_threshold_change = 1; @@ -157,7 +158,7 @@ class AutoPlaylistUsermod : public Usermod { change_threshold_change = 0; // change was within our window, no sensitivity change } - if (change_threshold < 1) change_threshold = 0; // we need change_threshold to be signed becasue otherwise this wraps to UINT_FAST16_MAX + if (change_threshold < 1) change_threshold = 0; // we need change_threshold to be signed because otherwise this wraps to UINT_FAST16_MAX distance_tracker = UINT_FAST32_MAX; @@ -195,11 +196,11 @@ class AutoPlaylistUsermod : public Usermod { applyPreset(newpreset); - USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ums - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); } else { - USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ums - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); } @@ -226,7 +227,7 @@ class AutoPlaylistUsermod : public Usermod { lastAutoPlaylist = currentPlaylist; } else if (enabled) { USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); - enabled = false; + enabled = false; // softhack007: warning this state is _not_ intermediate, due to line 219 "if (!enabled) return;" } } @@ -249,11 +250,11 @@ class AutoPlaylistUsermod : public Usermod { float volumeSmth = *(float*)um_data->u_data[0]; - if (volumeSmth > 0.5) { + if (volumeSmth > 0.5f) { lastSoundTime = millis(); } - if (millis() - lastSoundTime > (timeout * 1000)) { + if (millis() - lastSoundTime > (long(timeout) * 1000)) { if (!silenceDetected) { silenceDetected = true; USER_PRINTF("AutoPlaylist: Silence "); From 39f7a2e1872c2ee120dd80b6c3791599d9b291c1 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:32:26 -0400 Subject: [PATCH 42/59] Removed button, bettr Info pane, debug flag. --- .../usermod_v2_auto_playlist.h | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 94885e475f..c62c7c5fff 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -1,5 +1,11 @@ #pragma once +#ifdef WLED_DEBUG + #ifndef USERMOD_AUTO_PLAYLIST_DEBUG + #define USERMOD_AUTO_PLAYLIST_DEBUG + #endif +#endif + #include "wled.h" class AutoPlaylistUsermod : public Usermod { @@ -134,7 +140,9 @@ class AutoPlaylistUsermod : public Usermod { change_threshold_change = (distance_tracker)-change_threshold; change_threshold = distance_tracker; + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + #endif distance_tracker = UINT_FAST32_MAX; @@ -165,14 +173,18 @@ class AutoPlaylistUsermod : public Usermod { if (autoChangeIds.size() == 0) { if(currentPlaylist < 1) return; + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("Loading presets from playlist: %3d\n", currentPlaylist); + #endif JsonObject playtlistOjb = doc.to(); serializePlaylist(playtlistOjb); JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; for(JsonVariant v : playlistArray) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("Adding %3u to autoChangeIds\n", v.as()); + #endif autoChangeIds.push_back(v.as()); } @@ -195,12 +207,16 @@ class AutoPlaylistUsermod : public Usermod { // after change_lockout. Better for smaller change_lockout values. applyPreset(newpreset); - + + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + #endif } else { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + #endif } @@ -216,27 +232,31 @@ class AutoPlaylistUsermod : public Usermod { */ void loop() { - if (!enabled) return; - if (millis() < 10000) return; // Wait for device to settle if (lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { if (currentPlaylist == musicPlaylist) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("AutoPlaylist: enabled due to manual change of playlist back to %u\n", currentPlaylist); + #endif enabled = true; lastAutoPlaylist = currentPlaylist; } else if (enabled) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); + #endif enabled = false; // softhack007: warning this state is _not_ intermediate, due to line 219 "if (!enabled) return;" } } if (!enabled && currentPlaylist == musicPlaylist) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("AutoPlaylist: enabled due selecting musicPlaylist(%u)", musicPlaylist); + #endif enabled = true; } - + if (!enabled) return; if (bri == 0) return; @@ -282,15 +302,30 @@ class AutoPlaylistUsermod : public Usermod { JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name - String uiDomString = F(""); + String uiDomString = enabled ? F("AutoPlaylist is Enabled") : F("AutoPlaylist is Disabled"); + + uiDomString += F("
"); + + if (autoChange && currentPlaylist == musicPlaylist) { + uiDomString += F("AutoChange is Active"); + } else if (autoChange && currentPlaylist != musicPlaylist) { + uiDomString += F("AutoChange on Stand-by"); + } else if (!autoChange) { + uiDomString += F("AutoChange is Disabled"); + } + + uiDomString += F("
"); + + if (currentPlaylist == musicPlaylist && currentPlaylist > 0) { + uiDomString += F("Music Playlist"); + } else if (currentPlaylist == ambientPlaylist && currentPlaylist > 0) { + uiDomString += F("Ambient Playlist"); + } else { + uiDomString += F("Playlist Overridden"); + } + infoArr.add(uiDomString); + } /* @@ -298,20 +333,7 @@ class AutoPlaylistUsermod : public Usermod { * Values in the state object may be modified by connected clients */ void readFromJsonState(JsonObject& root) { - if (!initDone) return; // prevent crash on boot applyPreset() - bool en = enabled; - JsonObject um = root[FPSTR(_name)]; - if (!um.isNull()) { - if (um[FPSTR(_autoPlaylistEnabled)].is()) { - en = um[FPSTR(_autoPlaylistEnabled)].as(); - } else { - String str = um[FPSTR(_autoPlaylistEnabled)]; // checkbox -> off or on - en = (bool)(str!="off"); // off is guaranteed to be present - } - if (en != enabled) enabled = en; - DEBUG_PRINT("AutoPlaylist enabled = "); - DEBUG_PRINTLN(en); - } + return; } void appendConfigData() { @@ -347,7 +369,9 @@ class AutoPlaylistUsermod : public Usermod { lastAutoPlaylist = 0; - DEBUG_PRINTLN(F("AutoPlaylist config saved.")); + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTLN(F("AutoPlaylist config saved.")); + #endif } @@ -380,8 +404,10 @@ class AutoPlaylistUsermod : public Usermod { ideal_change_min = top[FPSTR(_ideal_change_min)] | ideal_change_min; ideal_change_max = top[FPSTR(_ideal_change_max)] | ideal_change_max; - DEBUG_PRINT(FPSTR(_name)); - DEBUG_PRINTLN(F(" config (re)loaded.")); + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINT(FPSTR(_name)); + USER_PRINTLN(F(" config (re)loaded.")); + #endif // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; @@ -401,7 +427,9 @@ class AutoPlaylistUsermod : public Usermod { void changePlaylist(byte id) { String name = ""; getPresetName(id, name); + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("apply %s\n", name.c_str()); + #endif applyPreset(id, CALL_MODE_NOTIFICATION); lastAutoPlaylist = id; } From a90c9f0f2a6ebd0fad5e2574a33308b368284876 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:39:58 -0400 Subject: [PATCH 43/59] Update FX_fcn.cpp Removed temp debug suppression --- wled00/FX_fcn.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 68c0d7dc55..561f2380da 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -115,7 +115,7 @@ Segment::Segment(const Segment &orig) { //WLEDMM: recreate ledsrgb if more space needed (will not free ledsrgb!) void Segment::allocLeds() { - size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); //TroyHack + size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); //Hack if ((size < sizeof(CRGB)) || (size > 164000)) { //softhack too small (<3) or too large (>160Kb) DEBUG_PRINTF("allocLeds warning: size == %u !!\n", size); if (ledsrgb && (ledsrgbSize == 0)) { @@ -124,9 +124,7 @@ void Segment::allocLeds() { } // softhack007 clean up buffer } if ((size > 0) && (!ledsrgb || size > ledsrgbSize)) { //softhack dont allocate zero bytes - #ifndef USERMOD_AUTO_PLAYLIST // TroyHacks - FIXME: just tidy output temporarily while debugging USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0); - #endif if (ledsrgb) free(ledsrgb); // we need a bigger buffer, so free the old one first ledsrgb = (CRGB*)calloc(size, 1); ledsrgbSize = ledsrgb?size:0; @@ -1538,7 +1536,7 @@ void WS2812FX::enumerateLedmaps() { USER_PRINTF("enumerateLedmaps %s \"%s\"", fileName, name); if (isMatrix) { - //WLEDMM calc ledmapMaxSize (TroyHack) + //WLEDMM calc ledmapMaxSize (Hack) char dim[34] = { '\0' }; f.find("\"width\":"); f.readBytesUntil('\n', dim, sizeof(dim)-1); //hack: use fileName as we have this allocated already @@ -2389,7 +2387,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { //WLEDMM recreate customMappingTable if more space needed if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) { - size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//TroyHack + size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//Hack USER_PRINTF("deserializemap customMappingTable alloc %u from %u\n", size, customMappingTableSize); //if (customMappingTable != nullptr) delete[] customMappingTable; //customMappingTable = new uint16_t[size]; From 1f9e800957035e43e7a11c4f613c891a223d034c Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:45:46 -0400 Subject: [PATCH 44/59] Update FX_fcn.cpp Accidental find/replace --- wled00/FX_fcn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 561f2380da..b9c37e8b16 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -115,7 +115,7 @@ Segment::Segment(const Segment &orig) { //WLEDMM: recreate ledsrgb if more space needed (will not free ledsrgb!) void Segment::allocLeds() { - size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); //Hack + size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); // TroyHacks if ((size < sizeof(CRGB)) || (size > 164000)) { //softhack too small (<3) or too large (>160Kb) DEBUG_PRINTF("allocLeds warning: size == %u !!\n", size); if (ledsrgb && (ledsrgbSize == 0)) { @@ -1536,7 +1536,7 @@ void WS2812FX::enumerateLedmaps() { USER_PRINTF("enumerateLedmaps %s \"%s\"", fileName, name); if (isMatrix) { - //WLEDMM calc ledmapMaxSize (Hack) + //WLEDMM calc ledmapMaxSize (TroyHacks) char dim[34] = { '\0' }; f.find("\"width\":"); f.readBytesUntil('\n', dim, sizeof(dim)-1); //hack: use fileName as we have this allocated already @@ -2387,7 +2387,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { //WLEDMM recreate customMappingTable if more space needed if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) { - size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//Hack + size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight)); // TroyHacks USER_PRINTF("deserializemap customMappingTable alloc %u from %u\n", size, customMappingTableSize); //if (customMappingTable != nullptr) delete[] customMappingTable; //customMappingTable = new uint16_t[size]; From 6e23b09a93beac8e641e1ff612528c6c85ad40a7 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:46:35 -0400 Subject: [PATCH 45/59] Update FX_2Dfcn.cpp removed temp debugging --- wled00/FX_2Dfcn.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index b013457e68..c4e0ac8e5c 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -64,13 +64,11 @@ void WS2812FX::setUpMatrix() { return; } - #ifndef USERMOD_AUTO_PLAYLIST // TroyHacks - FIXME: just tidy output temporarily while debugging USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight); - #endif - + //WLEDMM recreate customMappingTable if more space needed if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) { - size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//TroyHack + size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight)); // TroyHacks USER_PRINTF("setupmatrix customMappingTable alloc %d from %d\n", size, customMappingTableSize); //if (customMappingTable != nullptr) delete[] customMappingTable; //customMappingTable = new uint16_t[size]; From abc811484d9394113f873872f2f588009f2958b5 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:31:08 -0400 Subject: [PATCH 46/59] Added new internal functionality enabled tracking --- .../usermod_v2_auto_playlist.h | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index c62c7c5fff..3859c8ed75 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -13,6 +13,7 @@ class AutoPlaylistUsermod : public Usermod { private: bool initDone = false; + bool functionality_enabled = false; bool silenceDetected = true; unsigned long lastSoundTime = 0; byte ambientPlaylist = 1; @@ -100,13 +101,13 @@ class AutoPlaylistUsermod : public Usermod { if (volumeSmth > 1.0f) { // softhack007: original code used 0.998f as decay factor - avg_long_energy = avg_long_energy * 0.99f + energy * 0.01f; - avg_long_lfc = avg_long_lfc * 0.99f + lfc * 0.01f; - avg_long_zcr = avg_long_zcr * 0.99f + zcr * 0.01f; + avg_long_energy = avg_long_energy * 0.99f + energy * 0.01f; + avg_long_lfc = avg_long_lfc * 0.99f + lfc * 0.01f; + avg_long_zcr = avg_long_zcr * 0.99f + zcr * 0.01f; - avg_short_energy = avg_short_energy * 0.9f + energy * 0.1f; - avg_short_lfc = avg_short_lfc * 0.9f + lfc * 0.1f; - avg_short_zcr = avg_short_zcr * 0.9f + zcr * 0.1f; + avg_short_energy = avg_short_energy * 0.90f + energy * 0.10f; + avg_short_lfc = avg_short_lfc * 0.90f + lfc * 0.10f; + avg_short_zcr = avg_short_zcr * 0.90f + zcr * 0.10f; // allegedly this is faster than pow(whatever,2) vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); @@ -135,14 +136,18 @@ class AutoPlaylistUsermod : public Usermod { // the current music, especially after track changes or during // sparce intros and breakdowns. - if (change_interval > ideal_change_min && distance_tracker <= 9999) { - - change_threshold_change = (distance_tracker)-change_threshold; + if (change_interval > ideal_change_min && distance_tracker <= 1000) { + + change_threshold_change = distance_tracker-change_threshold; change_threshold = distance_tracker; - #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); - #endif + if (change_threshold_change > 9999999) change_threshold_change = 0; + + if (functionality_enabled) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + #endif + } distance_tracker = UINT_FAST32_MAX; @@ -151,8 +156,8 @@ class AutoPlaylistUsermod : public Usermod { change_timer = millis(); } - - if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { + + if (functionality_enabled && distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { change_threshold_change = change_threshold-(distance*0.9f); @@ -194,8 +199,7 @@ class AutoPlaylistUsermod : public Usermod { do { newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. - } - while (currentPreset == newpreset); // make sure we get a different random preset. + } while (currentPreset == newpreset); // make sure we get a different random preset. if (change_interval > change_lockout+3) { @@ -232,31 +236,33 @@ class AutoPlaylistUsermod : public Usermod { */ void loop() { + if (!enabled) return; + if (millis() < 10000) return; // Wait for device to settle if (lastAutoPlaylist > 0 && currentPlaylist != lastAutoPlaylist && currentPreset != 0) { - if (currentPlaylist == musicPlaylist) { + if (functionality_enabled) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("AutoPlaylist: enabled due to manual change of playlist back to %u\n", currentPlaylist); + USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); #endif - enabled = true; - lastAutoPlaylist = currentPlaylist; - } else if (enabled) { + functionality_enabled = false; + } else if (currentPlaylist == musicPlaylist) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("AutoPlaylist: disable due to manual change of playlist from %u to %d, preset:%u\n", lastAutoPlaylist, currentPlaylist, currentPreset); + USER_PRINTF("AutoPlaylist: enabled due to manual change of playlist back to %u\n", currentPlaylist); #endif - enabled = false; // softhack007: warning this state is _not_ intermediate, due to line 219 "if (!enabled) return;" + functionality_enabled = true; + lastAutoPlaylist = currentPlaylist; } } - if (!enabled && currentPlaylist == musicPlaylist) { + if (!functionality_enabled && currentPlaylist == musicPlaylist) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("AutoPlaylist: enabled due selecting musicPlaylist(%u)", musicPlaylist); + USER_PRINTF("AutoPlaylist: enabled due selecting musicPlaylist(%u)\n", musicPlaylist); #endif - enabled = true; + functionality_enabled = true; } - if (!enabled) return; + // if (!functionality_enabled) return; if (bri == 0) return; @@ -277,13 +283,13 @@ class AutoPlaylistUsermod : public Usermod { if (millis() - lastSoundTime > (long(timeout) * 1000)) { if (!silenceDetected) { silenceDetected = true; - USER_PRINTF("AutoPlaylist: Silence "); + USER_PRINTLN("AutoPlaylist: Silence"); changePlaylist(ambientPlaylist); } } else { if (silenceDetected) { silenceDetected = false; - USER_PRINTF("AutoPlaylist: End of silence "); + USER_PRINTLN("AutoPlaylist: End of silence"); changePlaylist(musicPlaylist); } if (autoChange) change(um_data); @@ -302,13 +308,21 @@ class AutoPlaylistUsermod : public Usermod { JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name - String uiDomString = enabled ? F("AutoPlaylist is Enabled") : F("AutoPlaylist is Disabled"); + String uiDomString = F(""); + + if (enabled && functionality_enabled) { + uiDomString += F("AutoPlaylist is Running"); + } else if (!enabled) { + uiDomString += F("AutoPlaylist is Disabled"); + } else { + uiDomString += F("AutoPlaylist is Suspended"); + } uiDomString += F("
"); - if (autoChange && currentPlaylist == musicPlaylist) { + if (autoChange && currentPlaylist == musicPlaylist && functionality_enabled) { uiDomString += F("AutoChange is Active"); - } else if (autoChange && currentPlaylist != musicPlaylist) { + } else if (autoChange && (currentPlaylist != musicPlaylist || !functionality_enabled || !enabled)) { uiDomString += F("AutoChange on Stand-by"); } else if (!autoChange) { uiDomString += F("AutoChange is Disabled"); @@ -317,12 +331,18 @@ class AutoPlaylistUsermod : public Usermod { uiDomString += F("
"); if (currentPlaylist == musicPlaylist && currentPlaylist > 0) { - uiDomString += F("Music Playlist"); + uiDomString += F("Playlist: Music Playlist"); } else if (currentPlaylist == ambientPlaylist && currentPlaylist > 0) { - uiDomString += F("Ambient Playlist"); + uiDomString += F("Playlist: Ambient Playlist"); } else { - uiDomString += F("Playlist Overridden"); + uiDomString += F("Playlist: Overridden"); } + + // #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + // uiDomString += F("
"); + // uiDomString += F("Change Threshold: "); + // uiDomString += String(change_threshold); + // #endif infoArr.add(uiDomString); From f9eb6d23006dfe6e488d5da06d41a63519048cf6 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:04:39 -0400 Subject: [PATCH 47/59] functionality_enabled logic --- .../usermod_v2_auto_playlist.h | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 3859c8ed75..1d23770be1 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -22,6 +22,7 @@ class AutoPlaylistUsermod : public Usermod { bool autoChange = false; byte lastAutoPlaylist = 0; unsigned long change_timer = millis(); + unsigned long autochange_timer = millis(); uint_fast32_t energy = 0; @@ -85,6 +86,8 @@ class AutoPlaylistUsermod : public Usermod { uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; + energy = 0; + for (int i=0; i < NUM_GEQ_CHANNELS; i++) { energy += fftResult[i]; } @@ -136,12 +139,12 @@ class AutoPlaylistUsermod : public Usermod { // the current music, especially after track changes or during // sparce intros and breakdowns. - if (change_interval > ideal_change_min && distance_tracker <= 1000) { + if (change_interval > ideal_change_min && distance_tracker <= 100) { change_threshold_change = distance_tracker-change_threshold; change_threshold = distance_tracker; - if (change_threshold_change > 9999999) change_threshold_change = 0; + if (change_threshold_change > 9999) change_threshold_change = 0; // cosmetic for debug if (functionality_enabled) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG @@ -157,7 +160,7 @@ class AutoPlaylistUsermod : public Usermod { } - if (functionality_enabled && distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { + if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { change_threshold_change = change_threshold-(distance*0.9f); @@ -175,52 +178,56 @@ class AutoPlaylistUsermod : public Usermod { distance_tracker = UINT_FAST32_MAX; - if (autoChangeIds.size() == 0) { - if(currentPlaylist < 1) return; - - #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("Loading presets from playlist: %3d\n", currentPlaylist); - #endif - - JsonObject playtlistOjb = doc.to(); - serializePlaylist(playtlistOjb); - JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; + if (functionality_enabled) { + + if (autoChangeIds.size() == 0) { + if(currentPlaylist < 1) return; - for(JsonVariant v : playlistArray) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("Adding %3u to autoChangeIds\n", v.as()); + USER_PRINTF("Loading presets from playlist: %3d\n", currentPlaylist); #endif - autoChangeIds.push_back(v.as()); + + JsonObject playtlistOjb = doc.to(); + serializePlaylist(playtlistOjb); + JsonArray playlistArray = playtlistOjb["playlist"]["ps"]; + + for(JsonVariant v : playlistArray) { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTF("Adding %3u to autoChangeIds\n", v.as()); + #endif + autoChangeIds.push_back(v.as()); + } + } - } + uint8_t newpreset = 0; - uint8_t newpreset = 0; + do { + newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. + } while (currentPreset == newpreset); // make sure we get a different random preset. - do { - newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. - } while (currentPreset == newpreset); // make sure we get a different random preset. + if (change_interval > change_lockout+3) { - if (change_interval > change_lockout+3) { + // Make sure we have a statistically significant change and we aren't + // just bouncing off change_lockout. That's valid for changing the + // thresholds, but might be a bit crazy for lighting changes. + // When the music changes quite a bit, the distance calculation can + // go into freefall - this logic stops that from triggering right + // after change_lockout. Better for smaller change_lockout values. - // Make sure we have a statistically significant change and we aren't - // just bouncing off change_lockout. That's valid for changing the - // thresholds, but might be a bit crazy for lighting changes. - // When the music changes quite a bit, the distance calculation can - // go into freefall - this logic stops that from triggering right - // after change_lockout. Better for smaller change_lockout values. + applyPreset(newpreset); + + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + #endif - applyPreset(newpreset); - - #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("*** CHANGE distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); - #endif + } else { - } else { + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); + #endif - #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("^^^ SKIP!! distance = %4lu - change_interval was %5ldms - next change_threshold is %4u (%4u diff aprox)\n",(unsigned long)distance,change_interval,change_threshold,change_threshold_change); - #endif + } } @@ -292,7 +299,10 @@ class AutoPlaylistUsermod : public Usermod { USER_PRINTLN("AutoPlaylist: End of silence"); changePlaylist(musicPlaylist); } - if (autoChange) change(um_data); + if (autoChange && millis() >= autochange_timer+22) { + change(um_data); + autochange_timer = millis(); + } } } From c5a71af679d618a1b5664211e42a4fadd6a6b39a Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:10:38 -0400 Subject: [PATCH 48/59] Update usermods_list.cpp Disabled by default --- wled00/usermods_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 3cb5c19cbd..a6e7ba7a85 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -406,7 +406,7 @@ void registerUsermods() #endif #ifdef USERMOD_AUTO_PLAYLIST - usermods.add(new AutoPlaylistUsermod(true)); + usermods.add(new AutoPlaylistUsermod(false)); #endif From 02b464f2836d7a674128a5de1468945da7c7718b Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:45:21 -0400 Subject: [PATCH 49/59] Smoothing sound detection --- .../usermod_v2_auto_playlist.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 1d23770be1..74c6472d4f 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -15,14 +15,15 @@ class AutoPlaylistUsermod : public Usermod { bool initDone = false; bool functionality_enabled = false; bool silenceDetected = true; - unsigned long lastSoundTime = 0; byte ambientPlaylist = 1; byte musicPlaylist = 2; int timeout = 60; bool autoChange = false; byte lastAutoPlaylist = 0; + unsigned long lastSoundTime = millis()-(timeout*1000)-100; unsigned long change_timer = millis(); unsigned long autochange_timer = millis(); + float avg_volumeSmth = 0; uint_fast32_t energy = 0; @@ -283,20 +284,22 @@ class AutoPlaylistUsermod : public Usermod { float volumeSmth = *(float*)um_data->u_data[0]; - if (volumeSmth > 0.5f) { + avg_volumeSmth = avg_volumeSmth * 0.99f + volumeSmth * 0.01f; + + if (avg_volumeSmth >= 1.0f) { lastSoundTime = millis(); } if (millis() - lastSoundTime > (long(timeout) * 1000)) { if (!silenceDetected) { silenceDetected = true; - USER_PRINTLN("AutoPlaylist: Silence"); + USER_PRINTLN("AutoPlaylist: Silence detected"); changePlaylist(ambientPlaylist); } } else { if (silenceDetected) { silenceDetected = false; - USER_PRINTLN("AutoPlaylist: End of silence"); + USER_PRINTLN("AutoPlaylist: Sound detected"); changePlaylist(musicPlaylist); } if (autoChange && millis() >= autochange_timer+22) { @@ -330,7 +333,7 @@ class AutoPlaylistUsermod : public Usermod { uiDomString += F("
"); - if (autoChange && currentPlaylist == musicPlaylist && functionality_enabled) { + if (enabled && autoChange && currentPlaylist == musicPlaylist && functionality_enabled) { uiDomString += F("AutoChange is Active"); } else if (autoChange && (currentPlaylist != musicPlaylist || !functionality_enabled || !enabled)) { uiDomString += F("AutoChange on Stand-by"); @@ -458,7 +461,7 @@ class AutoPlaylistUsermod : public Usermod { String name = ""; getPresetName(id, name); #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("apply %s\n", name.c_str()); + USER_PRINTF("AutoPlaylist: Applying \"%s\"\n", name.c_str()); #endif applyPreset(id, CALL_MODE_NOTIFICATION); lastAutoPlaylist = id; From 5186c0fdb67ff60600d81917b589826c0547255a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:23:01 +0200 Subject: [PATCH 50/59] autoplaylist bugfix for playlists with only one preset * prevent infinite loop in case that there is only one preset in a playlist * fixing two typos --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 74c6472d4f..0e420eaed4 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -138,7 +138,7 @@ class AutoPlaylistUsermod : public Usermod { // Make the analysis less sensitive if we miss the window. // Sometimes the analysis lowers the change_threshold too much for // the current music, especially after track changes or during - // sparce intros and breakdowns. + // sparse intros and breakdowns. if (change_interval > ideal_change_min && distance_tracker <= 100) { @@ -149,7 +149,7 @@ class AutoPlaylistUsermod : public Usermod { if (functionality_enabled) { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff aprox)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); + USER_PRINTF("--- lowest distance = %4lu - no changes done in %6ldms - next change_threshold is %4u (%4u diff approx)\n", (unsigned long)distance_tracker,change_interval,change_threshold,change_threshold_change); #endif } @@ -205,7 +205,7 @@ class AutoPlaylistUsermod : public Usermod { do { newpreset = autoChangeIds.at(random(0, autoChangeIds.size())); // random() is *exclusive* of the last value, so it's OK to use the full size. - } while (currentPreset == newpreset); // make sure we get a different random preset. + } while ((currentPreset == newpreset) && (autoChangeIds.size() > 1)); // make sure we get a different random preset. Unless there is only one. if (change_interval > change_lockout+3) { From 2a4810f43716f0502ec98f288e637d29f348d5a4 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:31:53 +0200 Subject: [PATCH 51/59] autoplaylist filter improvements * initialize slow and fast filters with current values (first call only) - reduces time for filter stabilization * use slightly optimized variant of "rolling average" filter (result is exactly the same) --> replaced `xX = xX * (1-a) + newX * a;` by `xX = xX + a * (newX - Xx);` * use constants for filter parameters (for tinkering and improved readability) --- .../usermod_v2_auto_playlist.h | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 0e420eaed4..06bbc2ff27 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -12,6 +12,25 @@ class AutoPlaylistUsermod : public Usermod { private: + #if 0 + // experimental parameters by softhack007 - more balanced but need testing + const uint_fast32_t ENERGY_SCALE = 24000; + const float FILTER_SLOW1 = 0.0075f; // for "slow" energy + const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr + const float FILTER_FAST1 = 0.2f; // for "fast" energy + const float FILTER_FAST2 = 0.25f; // for "fast" lfc / zcr + const float FILTER_VOLUME = 0.03f; // for volumeSmth averaging - takes 8-10sec until "silence" + #else + // parameters used by TroyHacks / netmindz - behaviour is mainly driven by "energy" + const uint_fast32_t ENERGY_SCALE = 10000; + // softhack007: original code used FILTER_SLOW = 0.002f + const float FILTER_SLOW1 = 0.01f; // for "slow" energy + const float FILTER_SLOW2 = 0.01f; // for "slow" lfc / zcr + const float FILTER_FAST1 = 0.1f; // for "fast" energy + const float FILTER_FAST2 = 0.1f; // for "fast" lfc / zcr + const float FILTER_VOLUME = 0.01f; // for volumeSmth averaging - takes 12-15sec until "silence" + #endif + bool initDone = false; bool functionality_enabled = false; bool silenceDetected = true; @@ -35,6 +54,7 @@ class AutoPlaylistUsermod : public Usermod { float avg_short_lfc = 1000; float avg_short_zcr = 500; + bool resetFilters = true; // to (re)initialize filters on first run uint_fast32_t vector_energy = 0; uint_fast32_t vector_lfc = 0; uint_fast32_t vector_zcr = 0; @@ -94,7 +114,7 @@ class AutoPlaylistUsermod : public Usermod { } energy *= energy; - energy /= 10000; // scale down so we get 0 sometimes + energy /= ENERGY_SCALE; // scale down so we get 0 sometimes uint8_t lfc = fftResult[0]; uint16_t zcr = *(uint16_t*)um_data->u_data[11]; @@ -103,15 +123,24 @@ class AutoPlaylistUsermod : public Usermod { // and the individual vector distances. if (volumeSmth > 1.0f) { + // initialize filters on first run + if (resetFilters) { + avg_short_energy = avg_long_energy = energy; + avg_short_lfc = avg_long_lfc = lfc; + avg_short_zcr = avg_long_zcr = zcr; + resetFilters = false; + #ifdef USERMOD_AUTO_PLAYLIST_DEBUG + USER_PRINTLN("autoplaylist: filters reset."); + #endif + } - // softhack007: original code used 0.998f as decay factor - avg_long_energy = avg_long_energy * 0.99f + energy * 0.01f; - avg_long_lfc = avg_long_lfc * 0.99f + lfc * 0.01f; - avg_long_zcr = avg_long_zcr * 0.99f + zcr * 0.01f; + avg_long_energy = avg_long_energy + FILTER_SLOW1 * (float(energy) - avg_long_energy); + avg_long_lfc = avg_long_lfc + FILTER_SLOW2 * (float(lfc) - avg_long_lfc); + avg_long_zcr = avg_long_zcr + FILTER_SLOW2 * (float(zcr) - avg_long_zcr); - avg_short_energy = avg_short_energy * 0.90f + energy * 0.10f; - avg_short_lfc = avg_short_lfc * 0.90f + lfc * 0.10f; - avg_short_zcr = avg_short_zcr * 0.90f + zcr * 0.10f; + avg_short_energy = avg_short_energy + FILTER_FAST1 * (float(energy) - avg_short_energy); + avg_short_lfc = avg_short_lfc + FILTER_FAST2 * (float(lfc) - avg_short_lfc); + avg_short_zcr = avg_short_zcr + FILTER_FAST2 * (float(zcr) - avg_short_zcr); // allegedly this is faster than pow(whatever,2) vector_lfc = (avg_short_lfc-avg_long_lfc)*(avg_short_lfc-avg_long_lfc); @@ -284,7 +313,7 @@ class AutoPlaylistUsermod : public Usermod { float volumeSmth = *(float*)um_data->u_data[0]; - avg_volumeSmth = avg_volumeSmth * 0.99f + volumeSmth * 0.01f; + avg_volumeSmth = avg_volumeSmth + FILTER_VOLUME * (volumeSmth - avg_volumeSmth); if (avg_volumeSmth >= 1.0f) { lastSoundTime = millis(); From 03cbc52c65ef6f7d4e99a8f227a15dd88ab69488 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:23:28 +0200 Subject: [PATCH 52/59] ar_energy small improvements * use named constant instead of "100" * make change_threshold_change more robust against negatives * unloadPlaylist() before activating a new playlist --- .../usermod_v2_auto_playlist.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 06bbc2ff27..83407e5fcb 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -14,6 +14,7 @@ class AutoPlaylistUsermod : public Usermod { #if 0 // experimental parameters by softhack007 - more balanced but need testing + const uint_fast32_t MAX_DISTANCE_TRACKER = 184; // maximum accepted distance_tracker const uint_fast32_t ENERGY_SCALE = 24000; const float FILTER_SLOW1 = 0.0075f; // for "slow" energy const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr @@ -22,6 +23,7 @@ class AutoPlaylistUsermod : public Usermod { const float FILTER_VOLUME = 0.03f; // for volumeSmth averaging - takes 8-10sec until "silence" #else // parameters used by TroyHacks / netmindz - behaviour is mainly driven by "energy" + const uint_fast32_t MAX_DISTANCE_TRACKER = 128; // maximum accepted distance_tracker const uint_fast32_t ENERGY_SCALE = 10000; // softhack007: original code used FILTER_SLOW = 0.002f const float FILTER_SLOW1 = 0.01f; // for "slow" energy @@ -169,7 +171,7 @@ class AutoPlaylistUsermod : public Usermod { // the current music, especially after track changes or during // sparse intros and breakdowns. - if (change_interval > ideal_change_min && distance_tracker <= 100) { + if (change_interval > ideal_change_min && distance_tracker <= MAX_DISTANCE_TRACKER) { change_threshold_change = distance_tracker-change_threshold; change_threshold = distance_tracker; @@ -192,9 +194,7 @@ class AutoPlaylistUsermod : public Usermod { if (distance <= change_threshold && change_interval > change_lockout && volumeSmth > 1.0f) { - change_threshold_change = change_threshold-(distance*0.9f); - - if (change_threshold_change < 1) change_threshold_change = 1; + change_threshold_change = max(1.0f, roundf(change_threshold-(distance*0.9f))); // exclude negatives, ensure change_threshold_change is always >= 1 if (change_interval > ideal_change_max) { change_threshold += change_threshold_change; // make changes more sensitive @@ -245,6 +245,8 @@ class AutoPlaylistUsermod : public Usermod { // go into freefall - this logic stops that from triggering right // after change_lockout. Better for smaller change_lockout values. + // SH7: this method is sub-optimal, as its interfering with the "playlist" engine + // we shoud find a better method for triggering playlist changes applyPreset(newpreset); #ifdef USERMOD_AUTO_PLAYLIST_DEBUG @@ -492,7 +494,10 @@ class AutoPlaylistUsermod : public Usermod { #ifdef USERMOD_AUTO_PLAYLIST_DEBUG USER_PRINTF("AutoPlaylist: Applying \"%s\"\n", name.c_str()); #endif - applyPreset(id, CALL_MODE_NOTIFICATION); + // if (currentPlaylist != id) { // un-comment to only change on "real" changes + unloadPlaylist(); // applying a preset requires to unload previous playlist + applyPreset(id, CALL_MODE_NOTIFICATION); + // } lastAutoPlaylist = id; } From 70bfbd5a4334c3e96b6fdd973f732b469e65c1ec Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:42:21 +0200 Subject: [PATCH 53/59] ar_energy: fix a math error fixing mis-optimized math when calculating energy. energy = sum(amplitude^2). this is not the same as sum(amplitude)^2. Example: 1+5+7 = 13; 13 * 13 = 169 1*1 + 5*5 + 7*7 = 75 --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 83407e5fcb..56ed93c28d 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -15,7 +15,7 @@ class AutoPlaylistUsermod : public Usermod { #if 0 // experimental parameters by softhack007 - more balanced but need testing const uint_fast32_t MAX_DISTANCE_TRACKER = 184; // maximum accepted distance_tracker - const uint_fast32_t ENERGY_SCALE = 24000; + const uint_fast32_t ENERGY_SCALE = 14000; const float FILTER_SLOW1 = 0.0075f; // for "slow" energy const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr const float FILTER_FAST1 = 0.2f; // for "fast" energy @@ -112,10 +112,10 @@ class AutoPlaylistUsermod : public Usermod { energy = 0; for (int i=0; i < NUM_GEQ_CHANNELS; i++) { - energy += fftResult[i]; + uint_fast32_t amplitude = fftResult[i]; + energy += amplitude * amplitude; } - energy *= energy; energy /= ENERGY_SCALE; // scale down so we get 0 sometimes uint8_t lfc = fftResult[0]; From 6e24850073da97e6c234b13708024083f37da72e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 10 Apr 2024 18:56:23 +0200 Subject: [PATCH 54/59] ar_energy: improved energy reconstruction fftResult[] is indended to look good on GEQ, and has a very "twisted" representation of FFT results only. This change improves reconstruction of signal energy, by on-doing some of the "GEQ enhancements" in fftResults[]. --- .../usermod_v2_auto_playlist.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 56ed93c28d..acbb3e6d2c 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -15,7 +15,7 @@ class AutoPlaylistUsermod : public Usermod { #if 0 // experimental parameters by softhack007 - more balanced but need testing const uint_fast32_t MAX_DISTANCE_TRACKER = 184; // maximum accepted distance_tracker - const uint_fast32_t ENERGY_SCALE = 14000; + const uint_fast32_t ENERGY_SCALE = 1500; const float FILTER_SLOW1 = 0.0075f; // for "slow" energy const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr const float FILTER_FAST1 = 0.2f; // for "fast" energy @@ -24,7 +24,8 @@ class AutoPlaylistUsermod : public Usermod { #else // parameters used by TroyHacks / netmindz - behaviour is mainly driven by "energy" const uint_fast32_t MAX_DISTANCE_TRACKER = 128; // maximum accepted distance_tracker - const uint_fast32_t ENERGY_SCALE = 10000; + //const uint_fast32_t ENERGY_SCALE = 10000; + const uint_fast32_t ENERGY_SCALE = 2000; // softhack007: original code used FILTER_SLOW = 0.002f const float FILTER_SLOW1 = 0.01f; // for "slow" energy const float FILTER_SLOW2 = 0.01f; // for "slow" lfc / zcr @@ -46,6 +47,9 @@ class AutoPlaylistUsermod : public Usermod { unsigned long autochange_timer = millis(); float avg_volumeSmth = 0; + // fftesult de-scaling factors: 2.8f / fftResultPink[] + const float fftDeScaler[NUM_GEQ_CHANNELS] = {2.8/2.35, 2.8/1.32, 2.8/1.32, 2.8/1.40, 2.8/1.48, 2.8/1.57, 2.8/1.68, 2.8/1.80, 2.8/1.89, 2.8/1.95, 2.8/2.14, 2.8/2.26, 2.8/2.50, 2.8/2.90, 2.8/4.20, 2.8/6.50}; + uint_fast32_t energy = 0; float avg_long_energy = 250; @@ -112,8 +116,15 @@ class AutoPlaylistUsermod : public Usermod { energy = 0; for (int i=0; i < NUM_GEQ_CHANNELS; i++) { +#if 1 + // make an attempt to undo some "trying to look better" FFT manglings in AudioReactive postProcessFFTResults() + float amplitude = float(fftResult[i]) * fftDeScaler[i]; // undo "pink noise" scaling + amplitude /= 0.85f + (float(i)/4.5f); // undo extra up-scaling for high frequencies + energy += roundf(amplitude * amplitude); // calc energy from amplitude +#else uint_fast32_t amplitude = fftResult[i]; energy += amplitude * amplitude; +#endif } energy /= ENERGY_SCALE; // scale down so we get 0 sometimes From af028b58908a609be1f94850dbdb1ed7dc88ebcd Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:39:15 -0400 Subject: [PATCH 55/59] Accepting some Softhack007 suggestions --- .../usermod_v2_auto_playlist.h | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index acbb3e6d2c..6655c749c4 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -12,7 +12,7 @@ class AutoPlaylistUsermod : public Usermod { private: - #if 0 + #if 1 // experimental parameters by softhack007 - more balanced but need testing const uint_fast32_t MAX_DISTANCE_TRACKER = 184; // maximum accepted distance_tracker const uint_fast32_t ENERGY_SCALE = 1500; @@ -27,11 +27,11 @@ class AutoPlaylistUsermod : public Usermod { //const uint_fast32_t ENERGY_SCALE = 10000; const uint_fast32_t ENERGY_SCALE = 2000; // softhack007: original code used FILTER_SLOW = 0.002f - const float FILTER_SLOW1 = 0.01f; // for "slow" energy - const float FILTER_SLOW2 = 0.01f; // for "slow" lfc / zcr - const float FILTER_FAST1 = 0.1f; // for "fast" energy - const float FILTER_FAST2 = 0.1f; // for "fast" lfc / zcr - const float FILTER_VOLUME = 0.01f; // for volumeSmth averaging - takes 12-15sec until "silence" + const float FILTER_SLOW1 = 0.01f; // for "slow" energy + const float FILTER_SLOW2 = 0.01f; // for "slow" lfc / zcr + const float FILTER_FAST1 = 0.1f; // for "fast" energy + const float FILTER_FAST2 = 0.1f; // for "fast" lfc / zcr + const float FILTER_VOLUME = 0.03f; // for volumeSmth averaging - takes 8-10sec until "silence" #endif bool initDone = false; @@ -67,7 +67,6 @@ class AutoPlaylistUsermod : public Usermod { uint_fast32_t distance = 0; uint_fast32_t distance_tracker = UINT_FAST32_MAX; - // uint_fast64_t squared_distance = 0; unsigned long lastchange = millis(); @@ -116,15 +115,13 @@ class AutoPlaylistUsermod : public Usermod { energy = 0; for (int i=0; i < NUM_GEQ_CHANNELS; i++) { -#if 1 + // make an attempt to undo some "trying to look better" FFT manglings in AudioReactive postProcessFFTResults() + float amplitude = float(fftResult[i]) * fftDeScaler[i]; // undo "pink noise" scaling amplitude /= 0.85f + (float(i)/4.5f); // undo extra up-scaling for high frequencies energy += roundf(amplitude * amplitude); // calc energy from amplitude -#else - uint_fast32_t amplitude = fftResult[i]; - energy += amplitude * amplitude; -#endif + } energy /= ENERGY_SCALE; // scale down so we get 0 sometimes @@ -136,6 +133,7 @@ class AutoPlaylistUsermod : public Usermod { // and the individual vector distances. if (volumeSmth > 1.0f) { + // initialize filters on first run if (resetFilters) { avg_short_energy = avg_long_energy = energy; @@ -143,7 +141,7 @@ class AutoPlaylistUsermod : public Usermod { avg_short_zcr = avg_long_zcr = zcr; resetFilters = false; #ifdef USERMOD_AUTO_PLAYLIST_DEBUG - USER_PRINTLN("autoplaylist: filters reset."); + USER_PRINTLN("AutoPlaylist: Filters reset."); #endif } @@ -162,10 +160,7 @@ class AutoPlaylistUsermod : public Usermod { } - // distance is linear, squared_distance is magnitude. - // linear is easier to fine-tune, IMHO. distance = vector_lfc + vector_energy + vector_zcr; - // squared_distance = distance * distance; long change_interval = millis()-lastchange; @@ -173,7 +168,7 @@ class AutoPlaylistUsermod : public Usermod { distance_tracker = distance; } - // USER_PRINTF("Distance: %3lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); + // USER_PRINTF("Distance: %5lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); if ((millis() - change_timer) > ideal_change_min) { // softhack007 same result as "millis() > change_timer + ideal_change_min", but more robust against unsigned overflow @@ -312,8 +307,6 @@ class AutoPlaylistUsermod : public Usermod { functionality_enabled = true; } - // if (!functionality_enabled) return; - if (bri == 0) return; um_data_t *um_data; From dfab0ca402eeceb379ccc0972187af40e2636f03 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sun, 14 Apr 2024 15:21:07 -0400 Subject: [PATCH 56/59] Accepting more Softhack007 suggestings --- .../usermod_v2_auto_playlist.h | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 6655c749c4..ffd057daa2 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -12,27 +12,14 @@ class AutoPlaylistUsermod : public Usermod { private: - #if 1 // experimental parameters by softhack007 - more balanced but need testing const uint_fast32_t MAX_DISTANCE_TRACKER = 184; // maximum accepted distance_tracker const uint_fast32_t ENERGY_SCALE = 1500; - const float FILTER_SLOW1 = 0.0075f; // for "slow" energy - const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr - const float FILTER_FAST1 = 0.2f; // for "fast" energy - const float FILTER_FAST2 = 0.25f; // for "fast" lfc / zcr + const float FILTER_SLOW1 = 0.0075f; // for "slow" energy - was 0.01f + const float FILTER_SLOW2 = 0.005f; // for "slow" lfc / zcr - was 0.01f + const float FILTER_FAST1 = 0.2f; // for "fast" energy - was 0.10f + const float FILTER_FAST2 = 0.25f; // for "fast" lfc / zcr - was 0.10f const float FILTER_VOLUME = 0.03f; // for volumeSmth averaging - takes 8-10sec until "silence" - #else - // parameters used by TroyHacks / netmindz - behaviour is mainly driven by "energy" - const uint_fast32_t MAX_DISTANCE_TRACKER = 128; // maximum accepted distance_tracker - //const uint_fast32_t ENERGY_SCALE = 10000; - const uint_fast32_t ENERGY_SCALE = 2000; - // softhack007: original code used FILTER_SLOW = 0.002f - const float FILTER_SLOW1 = 0.01f; // for "slow" energy - const float FILTER_SLOW2 = 0.01f; // for "slow" lfc / zcr - const float FILTER_FAST1 = 0.1f; // for "fast" energy - const float FILTER_FAST2 = 0.1f; // for "fast" lfc / zcr - const float FILTER_VOLUME = 0.03f; // for volumeSmth averaging - takes 8-10sec until "silence" - #endif bool initDone = false; bool functionality_enabled = false; @@ -126,7 +113,7 @@ class AutoPlaylistUsermod : public Usermod { energy /= ENERGY_SCALE; // scale down so we get 0 sometimes - uint8_t lfc = fftResult[0]; + uint8_t lfc = float(fftResult[0]) * fftDeScaler[0] / 0.85f; // might as well undo pink noise here too. uint16_t zcr = *(uint16_t*)um_data->u_data[11]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages @@ -168,6 +155,7 @@ class AutoPlaylistUsermod : public Usermod { distance_tracker = distance; } + // Debug for adjusting formulas, etc: // USER_PRINTF("Distance: %5lu - v_lfc: %5lu v_energy: %5lu v_zcr: %5lu\n",(unsigned long)distance,(unsigned long)vector_lfc,(unsigned long)vector_energy,(unsigned long)vector_zcr); if ((millis() - change_timer) > ideal_change_min) { // softhack007 same result as "millis() > change_timer + ideal_change_min", but more robust against unsigned overflow From 11315a81b5c11a82c422015469c747357bd82547 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sun, 14 Apr 2024 15:32:13 -0400 Subject: [PATCH 57/59] unsigned wraparound prevention --- .../usermod_v2_auto_playlist/usermod_v2_auto_playlist.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index ffd057daa2..afe5852f14 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -167,7 +167,12 @@ class AutoPlaylistUsermod : public Usermod { if (change_interval > ideal_change_min && distance_tracker <= MAX_DISTANCE_TRACKER) { - change_threshold_change = distance_tracker-change_threshold; + if (distance_tracker >= change_threshold) { + change_threshold_change = distance_tracker-change_threshold; + } else { + change_threshold_change = change_threshold-distance_tracker; + } + change_threshold = distance_tracker; if (change_threshold_change > 9999) change_threshold_change = 0; // cosmetic for debug From acfbe890b316cd0242c76e4a3ce46089eed7cf1b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:25:21 +0200 Subject: [PATCH 58/59] suspend playlist engine while auto-change is active * adding suspendPlaylist() to playlist engine code * autoplaylist usermod calls suspendPlaylist() before switching to another preset * fix a potential overflow on `lfc` (uint8_t -> uint16_t) --- .../usermod_v2_auto_playlist.h | 5 ++--- wled00/fcn_declare.h | 1 + wled00/playlist.cpp | 12 ++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index afe5852f14..4ac05c249c 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -113,7 +113,7 @@ class AutoPlaylistUsermod : public Usermod { energy /= ENERGY_SCALE; // scale down so we get 0 sometimes - uint8_t lfc = float(fftResult[0]) * fftDeScaler[0] / 0.85f; // might as well undo pink noise here too. + uint16_t lfc = float(fftResult[0]) * fftDeScaler[0] / 0.85f; // might as well undo pink noise here too. uint16_t zcr = *(uint16_t*)um_data->u_data[11]; // WLED-MM/TroyHacks: Calculate the long- and short-running averages @@ -244,8 +244,7 @@ class AutoPlaylistUsermod : public Usermod { // go into freefall - this logic stops that from triggering right // after change_lockout. Better for smaller change_lockout values. - // SH7: this method is sub-optimal, as its interfering with the "playlist" engine - // we shoud find a better method for triggering playlist changes + suspendPlaylist(); // suspend the playlist engine before changing to another preset applyPreset(newpreset); #ifdef USERMOD_AUTO_PLAYLIST_DEBUG diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index dcf4019ed3..a818d3fa06 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -208,6 +208,7 @@ void _overlayAnalogCountdown(); void _overlayAnalogClock(); //playlist.cpp +void suspendPlaylist(); // WLEDMM support function for auto playlist usermod void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 8a6227e1df..236cc32432 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -41,6 +41,12 @@ void shufflePlaylist() { DEBUG_PRINTLN(F("Playlist shuffle.")); } +// WLEDMM supporting function for auto_playlist usermod +// prevents the active playlist from progressing (until it gets unloaded) +static bool playlistSuspended = false; +void suspendPlaylist() { + playlistSuspended = true; +} void unloadPlaylist() { if (playlistEntries != nullptr) { @@ -49,6 +55,7 @@ void unloadPlaylist() { } currentPlaylist = playlistIndex = -1; playlistLen = playlistEntryDur = playlistOptions = 0; + playlistSuspended = false; // WLEDMM DEBUG_PRINTLN(F("Playlist unloaded.")); } @@ -125,6 +132,11 @@ void handlePlaylist() { // if fileDoc is not null JSON buffer is in use so just quit if (currentPlaylist < 0 || playlistEntries == nullptr || fileDoc != nullptr) return; + if (playlistSuspended) { // WLEDMM + if (millis() - presetCycledTime > (100*playlistEntryDur)) presetCycledTime = millis(); // keep updating timer + return; // but don't progress to next extry, and don't shuffle + } + if (millis() - presetCycledTime > (100*playlistEntryDur)) { presetCycledTime = millis(); if (bri == 0 || nightlightActive) return; From d42148d9944df471855d4da06d2c64aeea296b22 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:57:31 +0200 Subject: [PATCH 59/59] Info page optimizations * reduce from 3 lines to two lines * don't add to info when usermod is disabled in UM settings * show current playlist id --- .../usermod_v2_auto_playlist.h | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h index 4ac05c249c..c15f116ee8 100644 --- a/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h +++ b/usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h @@ -346,16 +346,26 @@ class AutoPlaylistUsermod : public Usermod { user = root.createNestedObject("u"); } - JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name + if (!enabled) return; // usermod disabled -> don't add to info page - String uiDomString = F(""); - + String uiNameString = FPSTR(_name); if (enabled && functionality_enabled) { - uiDomString += F("AutoPlaylist is Running"); + uiNameString += F(" Running"); } else if (!enabled) { - uiDomString += F("AutoPlaylist is Disabled"); + uiNameString += F(" Disabled"); + } else { + uiNameString += F(" Suspended"); + } + JsonArray infoArr = user.createNestedArray(uiNameString); // name + status + + String uiDomString = (currentPlaylist > 0) ? String("#") + String(currentPlaylist) + String(" ") : String(""); + + if (currentPlaylist == musicPlaylist && currentPlaylist > 0) { + uiDomString += F("Music Playlist"); + } else if (currentPlaylist == ambientPlaylist && currentPlaylist > 0) { + uiDomString += F("Ambient Playlist"); } else { - uiDomString += F("AutoPlaylist is Suspended"); + uiDomString += F("Playlist Overridden"); } uiDomString += F("
"); @@ -367,16 +377,6 @@ class AutoPlaylistUsermod : public Usermod { } else if (!autoChange) { uiDomString += F("AutoChange is Disabled"); } - - uiDomString += F("
"); - - if (currentPlaylist == musicPlaylist && currentPlaylist > 0) { - uiDomString += F("Playlist: Music Playlist"); - } else if (currentPlaylist == ambientPlaylist && currentPlaylist > 0) { - uiDomString += F("Playlist: Ambient Playlist"); - } else { - uiDomString += F("Playlist: Overridden"); - } // #ifdef USERMOD_AUTO_PLAYLIST_DEBUG // uiDomString += F("
");