diff --git a/audio_reactive.h b/audio_reactive.h index 1ebd753c..4cab5697 100644 --- a/audio_reactive.h +++ b/audio_reactive.h @@ -159,6 +159,7 @@ static bool udpSyncConnected = false; // UDP connection status -> true i static volatile bool isOOM = false; // FFTask: not enough memory for buffers (audio processing failed to start) #define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! +#define MAX_PALETTES 3 // number of audioreactive palettes provided by this usermod // audioreactive variables #ifdef ARDUINO_ARCH_ESP32 @@ -1257,6 +1258,9 @@ class AudioReactive : public Usermod { bool enabled = false; #endif bool initDone = false; + bool addPalettes = false; + int8_t palettes = 0; + bool processingPalettes = false; // poor man's interlock - to prevent that palettes get removed while they are processes // variables for UDP sound sync WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!) @@ -1306,8 +1310,16 @@ class AudioReactive : public Usermod { static const char _digitalmic[]; static const char UDP_SYNC_HEADER[]; static const char UDP_SYNC_HEADER_v1[]; + static const char _addPalettes[]; + static const char _palName0[]; + static const char _palName1[]; + static const char _palName2[]; // private methods + void removeAudioPalettes(void); + void createAudioPalettes(void); + CRGB getCRGBForBand(int x, int pal); + void fillAudioPalettes(void); //////////////////// // Debug support // @@ -2211,6 +2223,7 @@ class AudioReactive : public Usermod { receivedFormat = 0; delay(100); if (enabled) connectUDPSoundSync(); + if (enabled && addPalettes) createAudioPalettes(); initDone = true; DEBUGSR_PRINT(F("AR: init done, enabled = ")); DEBUGSR_PRINTLN(enabled ? F("true.") : F("false.")); @@ -2516,6 +2529,8 @@ class AudioReactive : public Usermod { lastTime = millis(); } #endif + + fillAudioPalettes(); } #if defined(_MoonModules_WLED_) && defined(WLEDMM_FASTPATH) @@ -2864,6 +2879,11 @@ class AudioReactive : public Usermod { if (usermod[FPSTR(_enabled)].is()) { enabled = usermod[FPSTR(_enabled)].as(); if (prevEnabled != enabled) onUpdateBegin(!enabled); + if (addPalettes) { + // add/remove custom/audioreactive palettes + if (prevEnabled && !enabled) removeAudioPalettes(); + if (!prevEnabled && enabled) createAudioPalettes(); + } } #ifdef ARDUINO_ARCH_ESP32 if (usermod[FPSTR(_inputLvl)].is()) { @@ -2873,6 +2893,13 @@ class AudioReactive : public Usermod { } } + void onStateChange(uint8_t callMode) { + if (initDone && enabled && addPalettes && palettes==0) { + // if palettes were removed during JSON call re-add them + createAudioPalettes(); + } + } + /* * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. @@ -2912,6 +2939,7 @@ class AudioReactive : public Usermod { void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; + top[FPSTR(_addPalettes)] = addPalettes; #ifdef ARDUINO_ARCH_ESP32 #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) JsonObject amic = top.createNestedObject(FPSTR(_analogmic)); @@ -2984,6 +3012,7 @@ class AudioReactive : public Usermod { bool readFromConfig(JsonObject& root) override { JsonObject top = root[FPSTR(_name)]; bool configComplete = !top.isNull(); + bool oldAddPalettes = addPalettes; #ifdef ARDUINO_ARCH_ESP32 // remember previous values @@ -2996,6 +3025,7 @@ class AudioReactive : public Usermod { #endif configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled); + configComplete &= getJsonValue(top[FPSTR(_addPalettes)], addPalettes); #ifdef ARDUINO_ARCH_ESP32 #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) configComplete &= getJsonValue(top[FPSTR(_analogmic)]["pin"], audioPin); @@ -3049,6 +3079,14 @@ class AudioReactive : public Usermod { configComplete &= getJsonValue(top["sync"][F("check_sequence")], audioSyncSequence); configComplete &= getJsonValue(top["sync"][F("broadcast")], audioSyncBroadcast); +#ifdef ARDUINO_ARCH_ESP32 + if (initDone) { + // add/remove custom/audioreactive palettes + if ((oldAddPalettes && !addPalettes) || (oldAddPalettes && !enabled)) removeAudioPalettes(); + if ((addPalettes && !oldAddPalettes && enabled) || (addPalettes && !oldEnabled && enabled)) createAudioPalettes(); + } +#endif + // WLEDMM notify user when a reboot is necessary #ifdef ARDUINO_ARCH_ESP32 if (initDone) { @@ -3353,6 +3391,105 @@ class AudioReactive : public Usermod { } }; +void AudioReactive::removeAudioPalettes(void) { +#ifndef _MoonModules_WLED_ + // WLEDMM does not support usermod palettes + if (processingPalettes) { + USER_PRINTLN(F("Audio palettes are processed - cannot remove.")); + return; + } + DEBUG_PRINTLN(F("Removing audio palettes.")); + palettes -= (int8_t)removeUsermodPalettes(_name); + if (palettes < 0) palettes = 0; // safeguard +#endif +} + +void AudioReactive::createAudioPalettes(void) { +#ifndef _MoonModules_WLED_ + if (palettes || processingPalettes) return; + DEBUG_PRINTLN(F("Adding audio palettes.")); + static const char *const palNames[MAX_PALETTES] PROGMEM = {_palName0, _palName1, _palName2}; + for (int i=0; i