diff --git a/.gitignore b/.gitignore index 02e648b88b..dfbdcc71c8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ node_modules .idea .direnv +wled00/wled00.ino.cpp diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile index 29d75d19da..cab85e35b2 100644 --- a/.gitpod.Dockerfile +++ b/.gitpod.Dockerfile @@ -1,5 +1,3 @@ FROM gitpod/workspace-full - -USER gitpod -RUN pip3 install -U platformio +USER gitpod diff --git a/.gitpod.yml b/.gitpod.yml index cc416b1c2d..8452f08be7 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,12 +1,11 @@ tasks: - - command: platformio run + - command: pip3 install -U platformio && platformio run image: file: .gitpod.Dockerfile vscode: extensions: - - ms-vscode.cpptools@0.26.3:u3GsZ5PK12Ddr79vh4TWgQ== - - eamodio.gitlens@10.2.1:e0IYyp0efFqVsrZwsIe8CA== - - Atishay-Jain.All-Autocomplete@0.0.23:fbZNfSpnd8XkAHGfAPS2rA== - - 2gua.rainbow-brackets@0.0.6:Tbu8dTz0i+/bgcKQTQ5b8g== + - Atishay-Jain.All-Autocomplete + - esbenp.prettier-vscode + - shardulm94.trailing-spaces diff --git a/CHANGELOG.md b/CHANGELOG.md index 0636b7717b..7d36934454 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,37 @@ -## WLED changelog +## WLED-SR changelog +- upgrade custom effects to ARTI-FX (from MoonModules fork) +- Audio responsive palettes +- beat-sensitive effect variants (Palette, Popcorn, Fireworks, Starburst) +- various effect bugfixes and minor effect improvements +- 2d Lissajous improvements +- Allow up to 9 (instead of 8) LED pins +- better support for some "M5" devices (needs specific firmware build) +- Preview colors bugfix +- Segment offset bugfix +- upgrade to fastLED 3.6.0 +- upgrade to NeoPixelBus 2.7.1 +- woraround for spurious crash in serializePalettes +- audio input filtering improvements +- Low-Cut filter for all audio inputs (reduces noise) +- better handling of analog audio +- Audio core and FFT optimizations +- I2S MCLK pin is configurable, sound settings page cleanups +- Improvements for Line-In I2S boards + +(list of bugfixed to be completed) + + +## WLED upstream changelog + +### Upstream changes backported to WLED-SR +- bugfix for large presets files (>64Kb) +- updated NeoPixelBus to 2.7.1 +- Fixed APA102 output on Ethernet enabled controllers +- Added ability to disable ADAlight (-D WLED_DISABLE_ADALIGHT) +- Remove DST from CST timezone +- Pakistan time-zone (PKT) +- various fixes and enhancements +- Removed Blynk support (servers shut down on 31st Dec 2022) ### WLED release 0.13.3 diff --git a/boards/esp32_16MB-poe.json b/boards/esp32_16MB-poe.json new file mode 100644 index 0000000000..1a8a2c86cd --- /dev/null +++ b/boards/esp32_16MB-poe.json @@ -0,0 +1,38 @@ +{ +"build": { + "arduino": { + "ldscript": "esp32_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_ESP32_POE", + "f_cpu": "240000000L", + "f_flash": "40000000L", + "flash_mode": "dio", + "mcu": "esp32", + "variant": "esp32-poe", + "partitions": "partitions_16M.csv" +}, +"connectivity": [ + "wifi", + "bluetooth", + "ethernet", + "can" +], +"debug": { + "openocd_board": "esp-wroom-32.cfg" +}, +"frameworks": [ + "arduino", + "espidf" +], +"name": "ESP32 16MB", +"upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 2000000 +}, +"url": "https://en.wikipedia.org/wiki/ESP32", +"vendor": "Multiple" +} diff --git a/boards/esp32_16MB.json b/boards/esp32_16MB.json new file mode 100644 index 0000000000..288dbfe969 --- /dev/null +++ b/boards/esp32_16MB.json @@ -0,0 +1,38 @@ +{ +"build": { + "arduino": { + "ldscript": "esp32_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_ESP32_DEV", + "f_cpu": "240000000L", + "f_flash": "40000000L", + "flash_mode": "dio", + "mcu": "esp32", + "variant": "esp32", + "partitions": "partitions_16M.csv" +}, +"connectivity": [ + "wifi", + "bluetooth", + "ethernet", + "can" +], +"debug": { + "openocd_board": "esp-wroom-32.cfg" +}, +"frameworks": [ + "arduino", + "espidf" +], +"name": "ESP32 16MB", +"upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 2000000 +}, +"url": "https://en.wikipedia.org/wiki/ESP32", +"vendor": "Multiple" +} diff --git a/package-lock.json b/package-lock.json index 11d0c1b3e3..058d097602 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wled", - "version": "0.13.3", + "version": "0.13.4-beta", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wled", - "version": "0.13.3", + "version": "0.13.4-beta", "license": "ISC", "dependencies": { "clean-css": "^4.2.3", diff --git a/package.json b/package.json index 11f9447e7f..02511959d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.13.3", + "version": "0.13.4-beta", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py index 381970ea68..89719d711f 100644 --- a/pio-scripts/output_bins.py +++ b/pio-scripts/output_bins.py @@ -35,7 +35,7 @@ def bin_rename_copy(source, target, env): if release_name: _create_dirs(["release"]) version = _get_cpp_define_value(env, "WLED_VERSION") - release_file = "{}release{}soundReactive_WLED_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, version, release_name) + release_file = "{}release{}WLEDSR_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, version, release_name) #WLEDSR: add SR postfix to WLED shutil.copy(str(target[0]), release_file) # check if new target files exist and remove if necessary diff --git a/platformio.ini b/platformio.ini index 87faae1ae9..fa6c72b720 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,12 +14,34 @@ # Release binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32s2_saola, esp32c3 +# WLEDSR Release binaries +default_envs = + soundReactive_esp32dev + soundReactive_esp32_eth + esp32_4MB_S + esp32_4MB_M ; recommended default + esp32_4MB_S_debug + esp32_4MB_S_micdebug + esp32_16MB_M + esp32_pico_4MB_S + wemos_shield_esp32_4MB_M + wemos_shield_esp32_16MB_M + # WLED sound-reactive binaries ; default_envs = soundReactive_lolin_d32 -default_envs = soundReactive_esp32dev, soundReactive_esp32_eth +; default_envs = soundReactive_esp32dev +; default_envs = soundReactive_esp32_eth +; default_envs = soundReactive_m5atom +; default_envs = soundReactive_m5StickC_Plus +; default_envs = soundReactive_m5stamp-pico + +; WLEDSR binaries +; =================== +; min = SR core (audio, 2D, ARTIFX) +; max = min + USERMOD_DALLASTEMPERATURE + USERMOD_FOUR_LINE_DISPLAY+ USERMOD_ROTARY_ENCODER_UI + USERMOD_AUTO_SAVE # Build everything -; default_envs = esp32dev, esp8285_4CH_MagicHome, codm-controller-0.6-rev2, codm-controller-0.6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, travis_esp8266, travis_esp32, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips +; default_envs = esp32dev, esp8285_4CH_MagicHome, codm-controller-0_6-rev2, codm-controller-0_6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, travis_esp8266, travis_esp32, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips # Single binaries (uncomment your board) ; default_envs = elekstube_ips @@ -79,7 +101,7 @@ platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7 # # ------------------------------------------------------------------------------ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM -#if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h" +#if needed (for memory leaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h" #-DDEBUG_ESP_CORE is not working right now # ------------------------------------------------------------------------------ @@ -160,22 +182,24 @@ upload_speed = 115200 # LIBRARIES: required dependencies # Please note that we don't always use the latest version of a library. # -# The following libraries have been included (and some of them changd) in the source: +# The following libraries have been included (and some of them changed) in the source: # ArduinoJson@5.13.5, Blynk@0.5.4(changed), E131@1.0.0(changed), Time@1.5, Timezone@1.2.1 # ------------------------------------------------------------------------------ lib_compat_mode = strict lib_deps = - fastled/FastLED @ 3.5.0 - IRremoteESP8266 @ 2.8.2 - https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7 - #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line + fastled/FastLED @ ~3.6.0 + ;;https://github.com/FastLED/FastLED.git#master @3.6.0+sha.23c67b7 + IRremoteESP8266 @ ~2.8.2 + ;; https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7 + https://github.com/lost-hope/ESPAsyncWebServer.git#master ;; WLEDSR to display .log and .wled files in /edit + #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI - #For use SSD1306 OLED display uncomment following + #For use SSD1306 OLED display uncomment following #U8g2@~2.27.2 - #For Dallas sensor uncomment following 2 lines + #For Dallas sensor uncomment following 2 lines #OneWire@~2.3.5 #milesburton/DallasTemperature@^3.9.0 - #For BME280 sensor uncomment following + #For BME280 sensor uncomment following #BME280@~3.0.0 ; adafruit/Adafruit BMP280 Library @ 2.1.0 ; adafruit/Adafruit CCS811 Library @ 1.0.4 @@ -190,23 +214,23 @@ build_flags = ;-Wno-deprecated-declarations -Wno-register -Wno-misleading-indentation -; NONOSDK22x_190703 = 2.2.2-dev(38a443e) + ; NONOSDK22x_190703 = 2.2.2-dev(38a443e) -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 -; lwIP 2 - Higher Bandwidth no Features -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH -; lwIP 1.4 - Higher Bandwidth (Aircoookie has) - -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; VTABLES in Flash + ; lwIP 2 - Higher Bandwidth no Features + ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH + ; lwIP 1.4 - Higher Bandwidth (Aircoookie has) + -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH + ; VTABLES in Flash -DVTABLES_IN_FLASH -; restrict to minimal mime-types + ; restrict to minimal mime-types -DMIMETYPE_MINIMAL lib_deps = - ${env.lib_deps} #https://github.com/lorol/LITTLEFS.git ESPAsyncTCP @ 1.2.2 ESPAsyncUDP makuna/NeoPixelBus @ 2.6.9 + ${env.lib_deps} [esp32] #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip @@ -215,49 +239,28 @@ platform = espressif32@3.5.0 platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4 build_flags = -g + -Wno-attributes -Wno-unused-variable -Wno-unused-function ;; WLEDSR disables some stupid warnings, like NeoPixelBus warning: 'maybe_unused' attribute directive ignored -DARDUINO_ARCH_ESP32 #-DCONFIG_LITTLEFS_FOR_IDF_3_2 -D CONFIG_ASYNC_TCP_USE_WDT=0 -#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x + #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv lib_deps = - ${env.lib_deps} ; https://github.com/lorol/LITTLEFS.git ; WLEDSR specific: use patched version of lorol LittleFS https://github.com/softhack007/LITTLEFS-threadsafe.git#master - makuna/NeoPixelBus @ 2.6.9 + makuna/NeoPixelBus @ 2.7.1 https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 - https://github.com/kosme/arduinoFFT#develop @ 1.9.2 - ; arduinoFFT @ 1.5.6 - -[esp32s2] -build_flags = -g - -DARDUINO_ARCH_ESP32 - -DARDUINO_ARCH_ESP32S2 - -DCONFIG_IDF_TARGET_ESP32S2 - -D CONFIG_ASYNC_TCP_USE_WDT=0 - -DCO - -lib_deps = + https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ${env.lib_deps} - makuna/NeoPixelBus @ 2.6.9 - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 -[esp32c3] -build_flags = -g - -DARDUINO_ARCH_ESP32 - -DARDUINO_ARCH_ESP32C3 - -DCONFIG_IDF_TARGET_ESP32C3 - -D CONFIG_ASYNC_TCP_USE_WDT=0 - -DCO +## WLEDSR : build-env for ESP32-S2 and ESP32-C3 deleted. They never worked on 0.13.x any way. +## Use MoonModules if you are looking for soundreactive on ESP32-S3 / ESP32-S2 / ESP32-C3 +## https://github.com/MoonModules/WLED -lib_deps = - ${env.lib_deps} - makuna/NeoPixelBus @ 2.6.9 - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 # ------------------------------------------------------------------------------ # WLED BUILDS @@ -269,7 +272,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_4m1m} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=nodemcuv2 lib_deps = ${esp8266.lib_deps} [env:esp8266_2m] @@ -278,7 +281,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_2m512k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02 +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=esp8266_2m lib_deps = ${esp8266.lib_deps} [env:esp01_1m_full] @@ -287,7 +290,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=esp01_1m_full -D WLED_DISABLE_OTA lib_deps = ${esp8266.lib_deps} [env:esp07] @@ -333,7 +336,7 @@ board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=esp32dev #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET upload_speed = 921600 lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder @@ -354,7 +357,7 @@ board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_qio80 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=esp32dev_qio80 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} @@ -367,30 +370,11 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=esp32_eth -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} -[env:esp32s2_saola] -board = esp32-s2-saola-1 -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip -platform_packages = -framework = arduino -board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv -board_build.flash_mode = qio -upload_speed = 460800 -build_unflags = ${common.build_unflags} -lib_deps = ${esp32s2.lib_deps} - -[env:esp32c3] -board = esp32-c3-devkitm-1 -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip -platform_packages = -framework = arduino -board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv -upload_speed = 460800 -build_unflags = ${common.build_unflags} -lib_deps = ${esp32c3.lib_deps} +## WLEDSR : buildenv for ESP32-S2 and ESP32-C3 deleted. They never worked on 0.13.x any way. [env:esp8285_4CH_MagicHome] board = esp8285 @@ -462,9 +446,10 @@ lib_deps = ${esp8266.lib_deps} board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} -upload_speed = 921600 +upload_speed = 460800 ; 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=soundReactive_esp32dev -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} @@ -477,7 +462,8 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=soundReactive_esp32_eth -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} ; board_build.f_flash = 80000000L @@ -490,6 +476,7 @@ platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} @@ -503,60 +490,88 @@ platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.f_cpu = 240000000L board_upload.flash_size = 16MB board_upload.maximum_size = 16777216 -board_build.partitions = tools/SoundReactive_ESP32_16MB.csv +board_build.partitions = tools/WLED_ESP32_16MB.csv ; for esp32_16MB with 16MB flash board_build.f_flash = 80000000L board_build.flash_mode = qio [env:soundReactive_m5atom] -board = esp32dev +board = m5stack-atom platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 1500000 monitor_speed = 115200 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} - -D WLED_RELEASE_NAME=ESP32 + -D WLED_RELEASE_NAME=soundReactive_m5atom -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE -D LEDPIN=27 -D BTNPIN=39 - -D DMENABLED=5 - -D I2S_SDPIN=26 - -D I2S_WSPIN=32 - -D I2S_CKPIN=-1 + -D I2S_SDPIN=26 -D I2S_WSPIN=32 -D I2S_CKPIN=-1 -D MCLK_PIN=-1 ;; PDM microphone pins + -D DMENABLED=5 -D SR_SQUELCH=5 -D SR_GAIN=75 ;; SPM1423 specific sound settings + ;-D I2S_USE_RIGHT_CHANNEL ;; might be needed, if your microphone uses the right channel instead of left + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} + m5stack/M5Atom @ ~0.1.0 ;; specific hardware driver library monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L board_build.flash_mode = dio +[env:soundReactive_m5StickC_Plus] +board = m5stick-c +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +upload_speed = 1500000 +monitor_speed = 115200 +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32} + -D WLED_RELEASE_NAME=soundReactive_m5StickC_Plus + -D WLED_DISABLE_MQTT + -D WLED_DISABLE_LOXONE + -D LEDPIN=32 + -D BTNPIN=37 + ; -D IRPIN=9 ;; gpio 9 will not work in WLED - its a "reserved pin" for flash memory + ; -D STATUSLED=10 ;; gpio 10 will not work either, for the same reason + -D I2S_SDPIN=34 -D I2S_WSPIN=0 -D I2S_CKPIN=-1 -D MCLK_PIN=-1 ;; PDM microphone pins + -D DMENABLED=5 -D SR_SQUELCH=5 -D SR_GAIN=75 ;; SPM1423 specific sound settings + -D I2S_USE_RIGHT_CHANNEL ;; might be needed, if your microphone uses the right channel instead of left + -D USERMOD_ARTIFX ; WLEDMM usermod +lib_deps = ${esp32.lib_deps} + https://github.com/m5stack/M5StickC-Plus.git @ ~0.0.8 ;; specific hardware driver library +monitor_filters = esp32_exception_decoder +board_build.partitions = ${esp32.default_partitions} +board_build.f_flash = 80000000L +;; board_build.flash_mode = dio + [env:soundReactive_m5stamp-pico] -board = esp32dev +board = pico32 platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 1500000 monitor_speed = 115200 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} - -D WLED_RELEASE_NAME=ESP32 + -D WLED_RELEASE_NAME=soundReactive_m5stamp-pico -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE -D LEDPIN=27 -D BTNPIN=39 - -D DMENABLED=5 - -D I2S_SDPIN=32 - -D I2S_WSPIN=33 - -D I2S_CKPIN=-1 + -D I2S_SDPIN=26 -D I2S_WSPIN=32 -D I2S_CKPIN=-1 -D MCLK_PIN=-1 ;; PDM microphone pins + -D DMENABLED=5 -D SR_SQUELCH=5 -D SR_GAIN=75 ;; SPM1423 specific sound settings + ;-D I2S_USE_RIGHT_CHANNEL ;; might be needed, if your microphone uses the right channel instead of left + -D USERMOD_ARTIFX ; WLEDMM usermod lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L -board_build.flash_mode = dio +board_build.flash_mode = dout # ------------------------------------------------------------------------------ # custom board configurations @@ -564,7 +579,7 @@ board_build.flash_mode = dio [env:wemos_shield_esp32] board = esp32dev -platform = espressif32@3.2 +platform = ${esp32.platform} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} @@ -575,6 +590,7 @@ build_flags = ${common.build_flags_esp32} -D UWLED_USE_MY_CONFIG -D USERMOD_DALLASTEMPERATURE -D USERMOD_FOUR_LINE_DISPLAY + -D USERMOD_ARTIFX ; WLEDMM usermod -D TEMPERATURE_PIN=23 lib_deps = ${esp32.lib_deps} OneWire@~2.3.5 @@ -582,6 +598,206 @@ lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} ; board_build.partitions = tools/SoundReactive_ESP32_16MB.csv ; ESP32 16MB +# ------------------------------------------------------------------------------ +# Soundreactive configs (MoonModules style, should eventually replace above) +# ------------------------------------------------------------------------------ + +; shared build flags and lib deps for minimum and maximum config +[common_sr] +build_flags_S = + -Wall -Wformat -Woverflow -Wuninitialized -Winit-self -Warray-bounds ; enables more warnings + -Wno-attributes -Wno-unused-variable -Wno-unused-function -Wno-deprecated-declarations ;disables some stupid warnings + -D WLED_DISABLE_MQTT -D WLED_DISABLE_LOXONE + ;-D WLED_DISABLE_BLYNK ; BLYNK is only provided for backwards compatibility (no new users accepted). Additionally, it calls analogRead() which could confuse analog mics + ;-D WLED_DISABLE_BROWNOUT_DET ; enable if you get "brownout detected" errors at startup + -D USERMOD_ARTIFX ; WLEDMM usermod + ; -D WLED_DEBUG ; lots of generic debug messages + ; -D SR_DEBUG -D NO_MIC_LOGGER ; some extra debug messages from audioreactive + ; -D MIC_LOGGER ; mic signal plotting with arduino serial plotter + ; -D WLED_USE_MY_CONFIG + +lib_deps_S = + ; https://github.com/kosme/arduinoFFT#develop @ 1.9.2 ; used for USERMOD_AUDIOREACTIVE +; monitor_filters = esp32_exception_decoder ; used to show crash details + +build_flags_M = + ; -D WLED_MAX_USERMODS=9 ; default only 4-6 + -D USERMOD_DALLASTEMPERATURE + -D USE_ALT_DISPLAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI + -D USERMOD_FOUR_LINE_DISPLAY + -D USERMOD_ROTARY_ENCODER_UI + -D USERMOD_AUTO_SAVE + +lib_deps_M = + OneWire@~2.3.5 ; used for USERMOD_FOUR_LINE_DISPLAY and USERMOD_DALLASTEMPERATURE + olikraus/U8g2 @ ^2.28.8 ; used for USERMOD_FOUR_LINE_DISPLAY + +; end of common + +; base entries (without WLED_RELEASE_NAME) + +; esp32_4MB_S_base: basis for min entries and for max_base +[esp32_4MB_S_base] +board = esp32dev +platform = ${esp32.platform} +upload_speed = 460800 ; or 921600 +platform_packages = ${esp32.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32} ${common_sr.build_flags_S} +lib_deps = ${esp32.lib_deps} ${common_sr.lib_deps_S} +board_build.partitions = ${esp32.default_partitions} +board_build.f_flash = 80000000L ; use full 80MHz speed for flash (default = 40Mhz) +board_build.flash_mode = dio ; (dio = dual i/o; more compatible than qio = quad i/o) + +;esp32_4MB_M_base: basis for max entries, uses esp32_4MB_S_base, build_flags_M and lib_deps_M +[esp32_4MB_M_base] +extends = esp32_4MB_S_base +build_flags = ${esp32_4MB_S_base.build_flags} ${common_sr.build_flags_M} +lib_deps = ${esp32_4MB_S_base.lib_deps} ${common_sr.lib_deps_M} +board_build.partitions = ${esp32_4MB_S_base.board_build.partitions} +; board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv + +; end of base entries + +; bin entries (with WLED_RELEASE_NAME) + +; esp32_4MB_S: bin entry, uses esp32_4MB_S_base +[env:esp32_4MB_S] +extends = esp32_4MB_S_base +build_flags = ${esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=esp32_4MB_S ; This will be included in the firmware.bin filename +; RAM: [== ] 24.1% (used 78900 bytes from 327680 bytes) +; Flash: [======== ] 83.7% (used 1315729 bytes from 1572864 bytes) + +; esp32_4MB_S_debug: bin entry, uses esp32_4MB_S_base + WLED_DEBUG +[env:esp32_4MB_S_debug] +extends = esp32_4MB_S_base +build_flags = ${esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=esp32_4MB_S_debug ; This will be included in the firmware.bin filename + -D WLED_DEBUG ; lots of generic debug messages + -D SR_DEBUG -D NO_MIC_LOGGER ; some extra debug messages from audioreactive + +; esp32_4MB_S_micdebug: bin entry, uses esp32_4MB_S_base + MIC_LOGGER +[env:esp32_4MB_S_micdebug] +extends = esp32_4MB_S_base +build_flags = ${esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=esp32_4MB_S_micdebug ; This will be included in the firmware.bin filename + -D MIC_LOGGER ;; mic signal plotting with arduino serial plotter + +; esp32_4MB_M: bin entry, uses esp32_4MB_M_base +[env:esp32_4MB_M] +extends = esp32_4MB_M_base +build_flags = ${esp32_4MB_M_base.build_flags} + -D WLED_RELEASE_NAME=esp32_4MB_M ; This will be included in the firmware.bin filename +; RAM: [== ] 24.4% (used 79812 bytes from 327680 bytes) +; Flash: [========= ] 88.6% (used 1393397 bytes from 1572864 bytes) + +; esp32_16MB_M: bin entry, uses esp32_4MB_M_base and adds 16MB settings +[env:esp32_16MB_M] +extends = esp32_4MB_M_base +board = esp32_16MB ; ESP32 with 16MB Flash +board_build.partitions = tools/WLED_ESP32_16MB.csv ; for esp32_16MB with 16MB flash +build_flags = ${esp32_4MB_M_base.build_flags} + -D WLED_RELEASE_NAME=esp32_16MB_M ; This will be included in the firmware.bin filename +; RAM: [=== ] 32.4% (used 106332 bytes from 327680 bytes) +; Flash: [====== ] 62.5% (used 1311017 bytes from 2097152 bytes) + + +; esp8266_4MB_S: bin entry for 8266, with 2D (WIP) +; [env:esp8266_4MB_S] +; extends = env:d1_mini +; upload_speed = 460800 ;115200 +; build_flags = ${common.build_flags_esp8266} +; -D WLED_RELEASE_NAME=esp8266_4MB_S ; This will be included in the firmware.bin filename +; ; -D WLED_DEBUG +; -D WLED_DISABLE_ALEXA +; -D WLED_DISABLE_BLYNK +; -D WLED_DISABLE_HUESYNC +; -D WLED_DISABLE_SOUND +; ; -D WLED_DISABLE_2D +; -UWLED_USE_MY_CONFIG +; ; monitor_filters = esp8266_exception_decoder +; ; RAM: [====== ] 58.7% (used 48056 bytes from 81920 bytes) +; ; Flash: [======== ] 75.7% (used 790428 bytes from 1044464 bytes) + +;; experiemtal environment for boards with PSRAM. +; ; esp32_4MB_PSRAM_M: bin entry, uses esp32_4MB_M_base and adds specific settings +; [env:esp32_4MB_PSRAM_M] +; extends = esp32_4MB_M_base +; board = lolin_d32_pro +; ;board = esp32cam +; build_flags = ${esp32_4MB_M_base.build_flags} +; -D WLED_RELEASE_NAME=esp32_4MB_PSRAM_M +; -D WLED_DISABLE_BROWNOUT_DET +; -D WLED_USE_PSRAM +; ; -D WLED_DEBUG +; ; -D SR_DEBUG -D NO_MIC_LOGGER +; ; -D MIC_LOGGER +# ------------------------------------------------------------------------------ +# custom board configurations +# ------------------------------------------------------------------------------ + +;wemos_shield_esp32_4MB_M_base: base entry, uses esp32_4MB_M_base +[wemos_shield_esp32_4MB_M_base] +extends = esp32_4MB_M_base +build_flags = ${esp32_4MB_M_base.build_flags} + -D ABL_MILLIAMPS_DEFAULT=9500 ; Wemos max 10A + -D LEDPIN=16 + -D RLYPIN=19 + -D BTNPIN=17 + -D IRPIN=18 + -D AUDIOPIN=-1 -D DMENABLED=1 -D I2S_SDPIN=32 -D I2S_WSPIN=15 -D I2S_CKPIN=14 -D MCLK_PIN=0 + -D TEMPERATURE_PIN=23 + -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21 + ; -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19 + +;wemos_shield_esp32_4MB_M: bin entry, uses wemos_shield_esp32_4MB_M_base +[env:wemos_shield_esp32_4MB_M] +extends = wemos_shield_esp32_4MB_M_base +build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} + -D WLED_RELEASE_NAME=wemos_shield_esp32_4MB_M ; This will be included in the firmware.bin filename +; RAM: [=== ] 32.5% (used 106340 bytes from 327680 bytes) +; Flash: [======== ] 83.4% (used 1311049 bytes from 1572864 bytes) + +;wemos_shield_esp32_16MB_M: bin entry, uses wemos_shield_esp32_4MB_M_base and adds 16MB settings +[env:wemos_shield_esp32_16MB_M] +extends = wemos_shield_esp32_4MB_M_base +board = esp32_16MB ; ESP32 with 16MB Flash +board_build.partitions = tools/WLED_ESP32_16MB.csv ; for esp32_16MB with 16MB flash +build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} + -D WLED_RELEASE_NAME=wemos_shield_esp32_16MB_M ; This will be included in the firmware.bin filename +; RAM: [=== ] 32.5% (used 106340 bytes from 327680 bytes) +; Flash: [====== ] 62.5% (used 1311049 bytes from 2097152 bytes) + +; ESP32 WLED pico board with builtin ICS-43432 microphpone +[env:esp32_pico_4MB_S] +extends = esp32_4MB_S_base +board = pico32 +board_build.flash_mode = dout ;; (dout = dual out; more compatible than qio = quad i/o) +upload_speed = 256000 ;; or 115200 ;; or 460800 ; or 921600 (slower speeds are better when flashing without a soldered connection) +build_flags = ${esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=esp32_pico_4MB_S ; This will be included in the firmware.bin filename + -D WLED_DISABLE_BROWNOUT_DET + -D SERVERNAME='"WLEDSR-pico32"' + -D WLED_DISABLE_ADALIGHT ;; WLEDSR this board does not have an onboard serial-to-USB chip. Better to disable serial protocols, to avoid crashes (see upstream #3128) + -D USERMOD_AUTO_SAVE + -D LEDPIN=2 + -D RLYPIN=-1 -D BTNPIN=-1 -D IRPIN=-1 + -D HW_PIN_SCL=22 -D HW_PIN_SDA=21 + -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21 + -D AUDIOPIN=-1 -D DMENABLED=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14 + -D SR_SQUELCH=6 -D SR_GAIN=30 ; ICS-4343x specific + ; -D MCLK_PIN=0 + ; -D WLED_DEBUG ; lots of generic debug messages + ; -D SR_DEBUG -D NO_MIC_LOGGER ; some extra debug messages from audioreactive + ; -D MIC_LOGGER ; mic signal plotting with arduino serial plotter + ; -D WLED_USE_MY_CONFIG + ; -D WLED_USE_CIE_BRIGHTNESS_TABLE +; RAM: [=== ] 32.5% (used 106356 bytes from 327680 bytes) +; Flash: [======== ] 81.3% (used 1278269 bytes from 1572864 bytes) +monitor_filters = esp32_exception_decoder +lib_ignore = IRremoteESP8266 ;; for faster compilation + [env:m5atom] board = esp32dev build_unflags = ${common.build_unflags} @@ -624,7 +840,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA -D USERMOD_MY9291 +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=MY9291 -D WLED_DISABLE_OTA -D USERMOD_MY9291 lib_deps = ${esp8266.lib_deps} # ------------------------------------------------------------------------------ @@ -645,10 +861,10 @@ build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_f # ------------------------------------------------------------------------------ # codm pixel controller board configurations -# codm-controller-0.6 can also be used for the TYWE3S controller +# codm-controller-0_6 can also be used for the TYWE3S controller # ------------------------------------------------------------------------------ -[env:codm-controller-0.6] +[env:codm-controller-0_6] board = esp_wroom_02 platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} @@ -657,7 +873,7 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp8266} lib_deps = ${esp8266.lib_deps} -[env:codm-controller-0.6-rev2] +[env:codm-controller-0_6-rev2] board = esp_wroom_02 platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} diff --git a/readme.md b/readme.md index 5746bb883b..af43288bf4 100644 --- a/readme.md +++ b/readme.md @@ -10,12 +10,13 @@

-# Stable Branch -This is the SR `master` branch - the source code for our latest release version [SR WLED v0.13.3](https://github.com/atuline/WLED/releases/tag/v0.13.3). +# Development Branch + +This is the SR `dev`elopment branch, where we test new features and enhancements. The code may or may not work - it is work in progress. - For ESP32 devices (8266 no longer supported) -- *This* branch (`master`) can be a stable baseline for your own project. Use it. -- *Pull Requests* should be created against our [`dev`elopment branch](https://github.com/atuline/WLED/tree/dev). +- *Pull Requests* should be created against this `dev` branch. +- If you are looking for a stable baseline for your own project, please use the released source code from [`master` branch](https://github.com/atuline/WLED/tree/master) diff --git a/tools/SoundReactive_ESP32_16MB.csv b/tools/SoundReactive_ESP32_16MB.csv deleted file mode 100644 index e547a82468..0000000000 --- a/tools/SoundReactive_ESP32_16MB.csv +++ /dev/null @@ -1,6 +0,0 @@ -# Name, Type, SubType, Offsaet, Size, Flags -nvs, data, nvs, 0x9000, 0x5000, -otadata, data, ota, 0xe000, 0x2000, -app0, app, ota_0, 0x10000, 0x200000, -app1, app, ota_1, 0x210000, 0x200000, -spiffs, data, spiffs, 0x410000, 0x7f0000, diff --git a/tools/WLED_ESP32_16MB_9MB_FS.csv b/tools/WLED_ESP32_16MB_9MB_FS.csv new file mode 100644 index 0000000000..9ecac04e39 --- /dev/null +++ b/tools/WLED_ESP32_16MB_9MB_FS.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x300000, +app1, app, ota_1, 0x310000,0x300000, +spiffs, data, spiffs, 0x610000,0x9E0000, +coredump, data, coredump,0xFF0000,0x10000, +# to create/use ffat, see https://github.com/marcmerlin/esp32_fatfsimage \ No newline at end of file diff --git a/tools/WLED_ESP32_2MB_noOTA.csv b/tools/WLED_ESP32_2MB_noOTA.csv new file mode 100644 index 0000000000..7a1cf15f89 --- /dev/null +++ b/tools/WLED_ESP32_2MB_noOTA.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 20K, +otadata, data, ota, 0xe000, 8K, +app0, app, ota_0, 0x10000, 1536K, +spiffs, data, spiffs, 0x190000, 384K, diff --git a/tools/WLED_ESP32_4MB_256KB_FS.csv b/tools/WLED_ESP32_4MB_256KB_FS.csv new file mode 100644 index 0000000000..f9e1be26cb --- /dev/null +++ b/tools/WLED_ESP32_4MB_256KB_FS.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1D0000, +app1, app, ota_1, 0x1E0000,0x1D0000, +spiffs, data, spiffs, 0x3B0000,0x40000, +coredump, data, coredump,0x3F0000,0x10000, \ No newline at end of file diff --git a/tools/cdata.js b/tools/cdata.js index 6508772e72..f6d8497fcb 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -413,6 +413,14 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()====="; append: ")=====", method: "plaintext", filter: "html-minify", + mangle: (str) => + str + .replace(/\/gms, "") + .replace(/\.*\<\/style\>/gms, "%CSS%%SCSS%") + .replace( + /function GetV().*\<\/script\>/gms, + "function GetV() {var d=document;\n" + ), }, { file: "welcome.htm", diff --git a/tools/partitions-4MB_spiffs-tinyuf2.csv b/tools/partitions-4MB_spiffs-tinyuf2.csv new file mode 100644 index 0000000000..4979c12722 --- /dev/null +++ b/tools/partitions-4MB_spiffs-tinyuf2.csv @@ -0,0 +1,11 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +# bootloader.bin,, 0x1000, 32K +# partition table, 0x8000, 4K + +nvs, data, nvs, 0x9000, 20K, +otadata, data, ota, 0xe000, 8K, +ota_0, 0, ota_0, 0x10000, 1408K, +ota_1, 0, ota_1, 0x170000, 1408K, +uf2, app, factory,0x2d0000, 256K, +spiffs, data, spiffs, 0x310000, 960K, diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h index 742066f7b2..c9b5d71e8c 100644 --- a/usermods/BME280_v2/usermod_bme280.h +++ b/usermods/BME280_v2/usermod_bme280.h @@ -26,6 +26,7 @@ class UsermodBME280 : public Usermod bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information // set the default pins based on the architecture, these get overridden by Usermod menu settings + #if !defined(HW_PIN_SDA) && !defined(HW_PIN_SCL) // WLEDSR do not overwrite global pins #ifdef ARDUINO_ARCH_ESP32 // ESP32 boards #define HW_PIN_SCL 22 #define HW_PIN_SDA 21 @@ -34,6 +35,7 @@ class UsermodBME280 : public Usermod #define HW_PIN_SDA 4 //uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 #endif + #endif int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup() bool initDone = false; @@ -181,6 +183,7 @@ class UsermodBME280 : public Usermod PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins + if ((pins[0].pin < 0) || (pins[1].pin < 0)) { sensorType=0; return; } // WLEDSR if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; } Wire.begin(ioPin[1], ioPin[0]); diff --git a/usermods/RTC/usermod_rtc.h b/usermods/RTC/usermod_rtc.h index 8c174e6fa8..687038fdfa 100644 --- a/usermods/RTC/usermod_rtc.h +++ b/usermods/RTC/usermod_rtc.h @@ -1,8 +1,10 @@ #pragma once +#include // WLEDSR - make sure the "right" Wire object is availeable #include "src/dependencies/time/DS1307RTC.h" #include "wled.h" +#if !defined(HW_PIN_SDA) && !defined(HW_PIN_SCL) // WLEDSR - don't overwrite global pins #ifdef ARDUINO_ARCH_ESP32 #define HW_PIN_SCL 22 #define HW_PIN_SDA 21 @@ -10,6 +12,7 @@ #define HW_PIN_SCL 5 #define HW_PIN_SDA 4 #endif +#endif //Connect DS1307 to standard I2C pins (ESP32: GPIO 21 (SDA)/GPIO 22 (SCL)) @@ -22,6 +25,9 @@ class RTCUsermod : public Usermod { void setup() { PinManagerPinType pins[2] = { { HW_PIN_SCL, true }, { HW_PIN_SDA, true } }; if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; } + Wire.begin(pins[1].pin, pins[0].pin); // WLEDSR this will silently fail if Wire is already started + // Wire.setClock(400000); + RTC.begin(); time_t rtcTime = RTC.get(); if (rtcTime) { toki.setTime(rtcTime,TOKI_NO_MS_ACCURACY,TOKI_TS_RTC); @@ -35,7 +41,7 @@ class RTCUsermod : public Usermod { if (strip.isUpdating()) return; if (!disabled && toki.isTick()) { time_t t = toki.second(); - if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value + if (abs(t - RTC.get())> 2) RTC.set(t); //set RTC to NTP/UI-provided value - WLEDSR allow up to 3 sec deviation } } @@ -46,10 +52,10 @@ class RTCUsermod : public Usermod { */ void addToConfig(JsonObject& root) { - JsonObject top = root.createNestedObject("RTC"); - JsonArray pins = top.createNestedArray("pin"); - pins.add(HW_PIN_SCL); - pins.add(HW_PIN_SDA); + //JsonObject top = root.createNestedObject("RTC"); + //JsonArray pins = top.createNestedArray("pin"); + //pins.add(HW_PIN_SCL); + //pins.add(HW_PIN_SDA); } uint16_t getId() diff --git a/wled00/src/dependencies/arti/arti.h b/usermods/artifx/arti.h similarity index 99% rename from wled00/src/dependencies/arti/arti.h rename to usermods/artifx/arti.h index 34af5661b2..80a823f5bc 100644 --- a/wled00/src/dependencies/arti/arti.h +++ b/usermods/artifx/arti.h @@ -1,7 +1,6 @@ /* @title Arduino Real Time Interpreter (ARTI) @file arti.h - @version 0.3.1 @date 20220818 @author Ewoud Wijma @repo https://github.com/ewoudwijma/ARTI @@ -42,8 +41,8 @@ #define ARTI_FILE 2 #if ARTI_PLATFORM == ARTI_ARDUINO //defined in arti_definition.h e.g. arti_wled.h! - #include "../../../wled.h" - #include "../json/ArduinoJson-v6.h" + #include "../../wled00/wled.h" + #include "../../wled00/src/dependencies/json/ArduinoJson-v6.h" File logFile; @@ -1041,8 +1040,8 @@ class ARTI { private: Lexer *lexer = nullptr; - DynamicJsonDocument *definitionJsonDoc = nullptr; - DynamicJsonDocument *parseTreeJsonDoc = nullptr; + PSRAMDynamicJsonDocument *definitionJsonDoc = nullptr; + PSRAMDynamicJsonDocument *parseTreeJsonDoc = nullptr; JsonObject definitionJson; JsonVariant parseTreeJson; @@ -1497,11 +1496,12 @@ class ARTI { Symbol* var_symbol = current_scope->lookup(variable_name); //lookup here and parent scopes if (node == F_VarRef) { - if (var_symbol == nullptr) + if (var_symbol == nullptr) { WARNING_ARTI("%s VarRef %s ID not found in scope of %s\n", spaces+50-depth, variable_name, current_scope->scope_name); //only warning: value 0 in interpreter (div 0 is captured) - else + } else { ANDBG_ARTI("%s VarRef found %s.%s (%u)\n", spaces+50-depth, var_symbol->scope->scope_name, variable_name, depth); + } } else //assign and var/formal { @@ -2008,8 +2008,9 @@ class ARTI { // valueStack->push(callResult); } //function_symbol != nullptr - else + else { RUNLOG_ARTI("%s %s not found %s\n", spaces+50-depth, key, function_name); + } } //external functions visitedAlready = true; @@ -2277,8 +2278,9 @@ class ARTI { valueStack->push(-valueStack->floatStack[oldIndex + 1]); RUNLOG_ARTI("%s unary - %f (push %u)\n", spaces+50-depth, valueStack->floatStack[oldIndex + 1], valueStack->stack_index ); } - else + else { RUNLOG_ARTI("%s unary operator not supported %u %s\n", spaces+50-depth, operatorx, tokenToString(operatorx)); + } } visitedAlready = true; @@ -2474,15 +2476,15 @@ class ARTI { if (!definitionFile) { - ERROR_ARTI("Definition file %s not found. Press Download wled.json\n", definitionName); + ERROR_ARTI("Definition file %s not found. Press Download wled json\n", definitionName); return false; } //open definitionFile #if ARTI_PLATFORM == ARTI_ARDUINO - definitionJsonDoc = new DynamicJsonDocument(8192); //currently 5335 + definitionJsonDoc = new PSRAMDynamicJsonDocument(8192); //currently 5335 #else - definitionJsonDoc = new DynamicJsonDocument(16384); //currently 9521 + definitionJsonDoc = new PSRAMDynamicJsonDocument(16384); //currently 9521 #endif // mandatory tokens: @@ -2504,9 +2506,9 @@ class ARTI { JsonObject::iterator objectIterator = definitionJson.begin(); JsonObject metaData = objectIterator->value(); const char * version = metaData["version"]; - if (strcmp(version, "0.3.1") != 0) + if (strcmp(version, "v033") != 0) { - ERROR_ARTI("Version of definition.json file (%s) should be 0.3.1.\nPress Download wled.json\n", version); + ERROR_ARTI("Version of definition.json file (%s) should be v033.\nPress Download wled json\n", version); return false; } const char * startNode = metaData["start"]; @@ -2553,9 +2555,9 @@ class ARTI { // strcpy(parseTreeName, "Gen"); strcat(parseTreeName, ".json"); #if ARTI_PLATFORM == ARTI_ARDUINO - parseTreeJsonDoc = new DynamicJsonDocument(32768); //less memory on arduino: 32 vs 64 bit? + parseTreeJsonDoc = new PSRAMDynamicJsonDocument(32768); //less memory on arduino: 32 vs 64 bit? #else - parseTreeJsonDoc = new DynamicJsonDocument(65536); + parseTreeJsonDoc = new PSRAMDynamicJsonDocument(65536); #endif MEMORY_ARTI("parseTree %u => %u ✓\n", (unsigned int)parseTreeJsonDoc->capacity(), FREE_SIZE); @@ -2715,4 +2717,4 @@ class ARTI { WLED_FS.remove(logFileName); //cleanup the /edit folder a bit #endif } -}; //ARTI +}; //ARTI \ No newline at end of file diff --git a/wled00/src/dependencies/arti/arti_wled.h b/usermods/artifx/arti_wled.h similarity index 72% rename from wled00/src/dependencies/arti/arti_wled.h rename to usermods/artifx/arti_wled.h index 9e9d7de3ed..4939a06d91 100644 --- a/wled00/src/dependencies/arti/arti_wled.h +++ b/usermods/artifx/arti_wled.h @@ -1,7 +1,6 @@ /* @title Arduino Real Time Interpreter (ARTI) - @file arti_wled_plugin.h - @version 0.3.1 + @file arti_wled.h @date 20220818 @author Ewoud Wijma @repo https://github.com/ewoudwijma/ARTI @@ -21,10 +20,10 @@ #if ARTI_PLATFORM == ARTI_ARDUINO #include "arti.h" -// #include "FX.h" extern float sampleAvg; extern float sampleAgc; extern byte soundAgc; + extern uint8_t *fftResult; #else #include "../arti.h" #include @@ -32,15 +31,14 @@ #include #endif -//make sure the numbers here correspond to the order in which these functions are defined in wled.json!! +//make sure the numbers here correspond to the order in which these functions are defined in wled000.json!! enum Externals { F_ledCount, - F_matrixWidth, - F_matrixHeight, + F_width, + F_height, F_setPixelColor, F_leds, - F_setPixels, F_hsv, F_rgbw, @@ -61,10 +59,13 @@ enum Externals F_custom1Slider, F_custom2Slider, F_custom3Slider, - F_sampleAvg, + F_volume, + F_fftResult, F_shift, F_circle2D, + F_drawLine, + F_drawArc, F_constrain, F_map, @@ -92,102 +93,74 @@ enum Externals }; #if ARTI_PLATFORM != ARTI_ARDUINO - class WS2812FX { - public: - uint16_t matrixWidth = 16, matrixHeight = 16; - - uint16_t XY(uint16_t x, uint16_t y) - { - return x%matrixWidth + y%matrixHeight * matrixWidth; - } - - uint32_t millis() - { - return 1000; // no millis defined for non embedded yet - } - - float arti_external_function(uint8_t function, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull, float par4 = floatNull, float par5 = floatNull); - float arti_get_external_variable(uint8_t variable, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull); - void arti_set_external_variable(float value, uint8_t variable, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull); - }; //class WS2812FX - - WS2812FX strip = WS2812FX(); - #define PI 3.141592654 - #endif float ARTI::arti_external_function(uint8_t function, float par1, float par2, float par3, float par4, float par5) { - return strip.arti_external_function(function, par1, par2, par3, par4, par5); -} - -float ARTI::arti_get_external_variable(uint8_t variable, float par1, float par2, float par3) -{ - return strip.arti_get_external_variable(variable, par1, par2, par3); -} - -void ARTI::arti_set_external_variable(float value, uint8_t variable, float par1, float par2, float par3) -{ - strip.arti_set_external_variable(value, variable, par1, par2, par3); -} - -float WS2812FX::arti_external_function(uint8_t function, float par1, float par2, float par3, float par4, float par5) { // MEMORY_ARTI("fun %d(%f, %f, %f)\n", function, par1, par2, par3); #if ARTI_PLATFORM == ARTI_ARDUINO switch (function) { case F_setPixelColor: { if (par3 == floatNull) - setPixelColor(((uint16_t)par1)%SEGLEN, (uint32_t)par2); + strip.setPixelColor(((uint16_t)par1)%SEGLEN, (uint32_t)par2); else - setPixelColor(XY((uint16_t)par1, (uint16_t)par2), (uint32_t)par3); + strip.setPixelColor(strip.XY((uint16_t)par1, (uint16_t)par2), (uint32_t)par3); return floatNull; } - case F_setPixels: - setPixels(leds); - return floatNull; case F_hsv: - return crgb_to_col(CHSV((uint8_t)par1, (uint8_t)par2, (uint8_t)par3)); + { + CRGB color = CHSV((uint8_t)par1, (uint8_t)par2, (uint8_t)par3); + return RGBW32(color.r, color.g, color.b, 0); + } case F_rgbw: return RGBW32((uint8_t)par1, (uint8_t)par2, (uint8_t)par3, (uint8_t)par4); + case F_setRange: { - setRange((uint16_t)par1, (uint16_t)par2, (uint32_t)par3); + strip.setRange((uint16_t)par1, (uint16_t)par2, (uint32_t)par3); return floatNull; } case F_fill: { - fill((uint32_t)par1); + strip.fill((uint32_t)par1); return floatNull; } case F_colorBlend: - return color_blend((uint32_t)par1, (uint32_t)par2, (uint16_t)par3); + return strip.color_blend((uint32_t)par1, (uint32_t)par2, (uint16_t)par3); case F_colorWheel: - return color_wheel((uint8_t)par1); - case F_colorFromPalette: + return strip.color_wheel((uint8_t)par1); + case F_colorFromPalette: + { + CRGB color; if (par2 == floatNull) - return crgb_to_col(ColorFromPalette(currentPalette, (uint8_t)par1)); + color = ColorFromPalette(strip.currentPalette, (uint8_t)par1); else - return crgb_to_col(ColorFromPalette(currentPalette, (uint8_t)par1, (uint8_t)par2)); //brightness + color = ColorFromPalette(strip.currentPalette, (uint8_t)par1, (uint8_t)par2); //brightness + return RGBW32(color.r, color.g, color.b, 0); + } case F_beatSin: return beatsin8((uint8_t)par1, (uint8_t)par2, (uint8_t)par3, (uint8_t)par4, (uint8_t)par5); case F_fadeToBlackBy: - fadeToBlackBy(leds, (uint8_t)par1); + strip.fade2black((uint8_t)par1); return floatNull; case F_iNoise: return inoise16((uint32_t)par1, (uint32_t)par2); case F_fadeOut: - fade_out((uint8_t)par1); + strip.fade_out((uint8_t)par1); return floatNull; case F_segcolor: return SEGCOLOR((uint8_t)par1); + case F_fftResult: + return fftResult[(uint8_t)par1%16]; + case F_shift: { - uint32_t saveFirstPixel = getPixelColor(0); + uint32_t saveFirstPixel = strip.getPixelColor(0); for (uint16_t i=0; ilookup(function_name); - ledsSet = false; - if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print foundRenderFunction = true; @@ -529,9 +509,12 @@ bool ARTI::loop() for (int i = 0; i< arti_get_external_variable(F_ledCount); i++) { - ar->set(function_symbol->function_scope->symbols[0]->scope_index, i%strip.matrixWidth); // set x - if (function_symbol->function_scope->nrOfFormals == 2) // 2D + if (function_symbol->function_scope->nrOfFormals == 2) {// 2D + ar->set(function_symbol->function_scope->symbols[0]->scope_index, i%strip.matrixWidth); // set x ar->set(function_symbol->function_scope->symbols[1]->scope_index, i/strip.matrixWidth); // set y + } + else + ar->set(function_symbol->function_scope->symbols[0]->scope_index, i); // set x this->callStack->push(ar); @@ -545,14 +528,6 @@ bool ARTI::loop() } - // if leds has been set during interpret(renderLed) - if (ledsSet) { - // Serial.println("ledsSet"); - arti_external_function(F_setPixels); - } - // else - // Serial.println("not ledsSet"); - if (!foundRenderFunction) { ERROR_ARTI("%s renderFrame or renderLed not found\n", spaces+50-depth); @@ -575,82 +550,20 @@ bool ARTI::loop() return true; } // loop -#if ARTI_PLATFORM == ARTI_ARDUINO - +//declare global variables ARTI * arti; -//Adding ARTI to this structure seems to be needed to make the pointers used in ARTI survive in subsequent calls of mode_customEffect -// otherwise: Interpret renderFrame: No parsetree created -// initially added parseTreeJsonDoc in this struct to save it explicitly but that was not needed -// maybe because this struct is not deleted -// typedef struct ArtiWrapper { -// ARTI * arti; -// } artiWrapper; - -uint16_t WS2812FX::mode_customEffect(void) -{ - // //brightpulse - // uint8_t lum = constrain(sampleAvg * 256.0 / (256.0 - SEGMENT.speed), 0, 255); - // fill(color_blend(SEGCOLOR(1), SEGCOLOR(0), lum)); - - // return FRAMETIME; - - // float t = (sin((float)millis() / 1000.) + 1.0) / 2.; // Make a slow sine wave and convert output range from -1.0 and 1.0 to between 0 and 1.0. - // t = t * (float)SEGLEN; // Now map to the length of the strand. - - // for (int i = 0; i < SEGLEN; i++) - // { - // float diff = abs(t - (float)i); // Get difference between t and current location. Greater distance = lower brightness. - // if (diff > 2.0) diff = 2.0; // Let's not overflow. - // float bri = 256 - diff * 128; // Scale the brightness to up to 255. Closer = brighter. - // leds[i] = CHSV(0, 255, (uint8_t)bri); - // } - - // setPixels(leds); - - // return FRAMETIME; - - - // //Random - // for (int i = 0; i < ledCount; i = i + 1) { - // uint16_t color = random16(); - // setPixelColor(i%ledCount, color_wheel(color%256)); - // } - - // return 0; - - // //Kitt - - // static int pixelCounter; - // static int goingUp; - - // if (pixelCounter > (ledCount-5)) { - // goingUp = 0; - // } - // if (pixelCounter == 0) { - // goingUp = 1; - // } - // setPixelColor(pixelCounter%ledCount, color_wheel(pixelCounter%256)); - // if (goingUp) { - // setPixelColor((pixelCounter-5)%ledCount, CRGB::Black); - // pixelCounter = pixelCounter + 1; - // } - // else { - // setPixelColor((pixelCounter+5)%ledCount, CRGB::Black); - // pixelCounter = pixelCounter - 1; - // } - - // return 0; - - // ArtiWrapper* artiWrapper = reinterpret_cast(SEGENV.data); - +//effect function +uint16_t WS2812FX::mode_ARTIFX(void) { //tbd: move statics to SEGMENT.data static bool succesful; static bool notEnoughHeap; static char previousEffect[charLength]; - if (SEGENV.call == 0) + if (SEGENV.call == 0) { strcpy(previousEffect, ""); //force init + fill(BLACK); //in case not all leds used e.g. when using expand 1d Circles. Tbd: fill black should never be used to allow for blends/transitions + } char currentEffect[charLength]; strcpy(currentEffect, (SEGMENT.name != nullptr)?SEGMENT.name:"default"); //note: switching preset with segment name to preset without does not clear the SEGMENT.name variable, but not gonna solve here ;-) @@ -675,7 +588,7 @@ uint16_t WS2812FX::mode_customEffect(void) strcat(programFileName, currentEffect); strcat(programFileName, ".wled"); - succesful = arti->setup("/wled.json", programFileName); + succesful = arti->setup("/wledv033.json", programFileName); if (!succesful) ERROR_ARTI("Setup not succesful\n"); @@ -712,12 +625,13 @@ uint16_t WS2812FX::mode_customEffect(void) notEnoughHeap = false; strcpy(previousEffect, ""); // force new create } - else - return mode_blink(); + else { + //mode_static + strip.fill(SEGCOLOR(0)); + return 350; + } } } return FRAMETIME; -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/usermods/artifx/artifx.css b/usermods/artifx/artifx.css new file mode 100644 index 0000000000..39ef39676b --- /dev/null +++ b/usermods/artifx/artifx.css @@ -0,0 +1,12 @@ +.ceTextarea { + width: 90%; + height: 300px; + resize: none; + white-space: pre; +} + +#kceEditor { + max-width: 490px; + display: inline-block; +} + diff --git a/usermods/artifx/artifx.js b/usermods/artifx/artifx.js new file mode 100644 index 0000000000..56e32a8fc1 --- /dev/null +++ b/usermods/artifx/artifx.js @@ -0,0 +1,178 @@ + +var isCEEditor = false; + +function toggleCEEditor(name, segID) { + if (isInfo) toggleInfo(); + if (isNodes) toggleNodes(); + isCEEditor = !isCEEditor; + if (isCEEditor) populateCEEditor(name, segID); + d.getElementById('ceEditor').style.transform = (isCEEditor) ? "translateY(0px)":"translateY(100%)"; +} + +function fetchAndExecute(url, name, callback, callError) +{ + fetch + (url+name, { + method: 'get' + }) + .then(res => { + if (!res.ok) { + callError("File " + name + " not found"); + return ""; + } + return res.text(); + }) + .then(text => { + callback(text); + }) + .catch(function (error) { + callError("Error getting " + name); + }) + .finally(() => { + // if (callback) setTimeout(callback,99); + }); +} + +function loadLogFile(name, attempt) { + var ceLogArea = d.getElementById("ceLogArea"); + fetchAndExecute((loc?`http://${locip}`:'.') + "/", name , function(logtext) + { + if (logtext == "") { + if (attempt < 10) { + ceLogArea.value = ("...........").substring(0, attempt + 1); + setTimeout(() => + { + loadLogFile(name, attempt + 1); + }, 1000); + } + else + ceLogArea.value = "log not found after 10 seconds"; + } + else + ceLogArea.value = logtext; + }, function(error){ + showToast(error); + console.log(error); + }); +} + +function uploadFileWithText(name, text) +{ + var req = new XMLHttpRequest(); + req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); + req.addEventListener('error', function(e){showToast(e.stack,true);}); + req.open("POST", "/upload"); + var formData = new FormData(); + + var blob = new Blob([text], {type : 'application/text'}); + var fileOfBlob = new File([blob], name); + formData.append("upload", fileOfBlob); + + req.send(formData); +} + +function saveCE(name, segID) { + showToast("Saving " + name); + + var ceProgramArea = d.getElementById("ceProgramArea"); + + uploadFileWithText("/" + name, ceProgramArea.value); + + var obj = {"seg": {"id": segID, "reset": true}}; + requestJson(obj); + + var ceLogArea = d.getElementById("ceLogArea"); + ceLogArea.value = "."; + setTimeout(() => + { + loadLogFile(name + ".log", 1); + }, 1000); +} + +function populateCEEditor(name, segID) +{ + fetchAndExecute((loc?`http://${locip}`:'.') + "/", name + ".wled", function(text) + { + var cn=`ARTI-FX Editor
+ ${name}.wled
+
+ +
+ +
+ +
+ +
+
Compile and Run Log
+
+ Run log > 3 seconds is send to Serial Ouput.
+ 🥚 + 🥚`; + + d.getElementById('kceEditor').innerHTML = cn; + + var ceLogArea = d.getElementById("ceLogArea"); + ceLogArea.value = "."; + loadLogFile(name + ".wled.log", 1); + + }, function(error){ + showToast(error); + console.log(error); + }); +} + +function downloadCEFile(url, name) { + if (url == "CE") url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/ARTIFX/wled/"; + if (url == "HBB") url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/Presets/HB_PresetPack210808_32x32_16seg/Base%20pack/"; + if (url == "HBE") url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/Presets/HB_PresetPack210808_32x32_16seg/Effects%20pack/"; + + fetchAndExecute(url, name, function(text) { + if (name == "wledv033.json" || name == "presets.json") { + if (!confirm('Are you sure to download/overwrite ' + name + '?')) + return; + uploadFileWithText("/" + name, text); + } + else + { + var ceProgramArea = d.getElementById("ceProgramArea"); + ceProgramArea.value = text; + } + }, function(error){ + showToast(error); + console.log(error); + }); + + return; + + var request = new XMLHttpRequest(); + request.onload = function() { + if (name == "wledv033.json" || name == "presets.json") { + if (!confirm('Are you sure to download ' + name + '?')) + return; + uploadFileWithText("/" + name, request.response); + } + else + { + var ceProgramArea = d.getElementById("ceProgramArea"); + ceProgramArea.value = request.response; + } + } + request.open("GET", url); + request.send(); + } + +function loadCETemplate(name) { + var ceProgramArea = d.getElementById("ceProgramArea"); + ceProgramArea.value = `/* + ARTI-FX Template + */ + program ${name} + { + function renderFrame() + { + setPixelColor(counter, colorFromPalette(counter, counter)) + } + }`; + +} \ No newline at end of file diff --git a/usermods/artifx/usermod_v2_artifx.h b/usermods/artifx/usermod_v2_artifx.h new file mode 100644 index 0000000000..917c562b46 --- /dev/null +++ b/usermods/artifx/usermod_v2_artifx.h @@ -0,0 +1,117 @@ +#pragma once + +#include "wled.h" + +#include "arti_wled.h" + +class ARTIFXUserMod : public Usermod { + private: + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; //usermod name + + char errorMessage[100] = ""; + + bool enabled = false; + bool initDone = false; + + public: + + void setup() { + // if (!initDone) + // strip.addEffect(FX_MODE_ARTIFX, &mode_ARTIFX, _data_FX_MODE_ARTIFX); + initDone = true; + enabled = true; + } + + void connected() { + } + + void loop() { + } + + /* + * 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)); + infoArr.add(errorMessage); //value + // infoArr.add(""); //unit + } + + + /* + * 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) + { + //root["user0"] = userVar0; + if (!initDone) return; // prevent crash on boot applyPreset() + JsonObject usermod = root[FPSTR(_name)]; + if (usermod.isNull()) { + usermod = root.createNestedObject(FPSTR(_name)); + } + usermod["on"] = enabled; + } + + + /* + * 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) + { + // userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value + //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); + } + + + void addToConfig(JsonObject& root) + { + } + + + bool readFromConfig(JsonObject& root) + { + JsonObject top = root[FPSTR(_name)]; + + bool configComplete = !top.isNull(); + + + // * Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings) + return configComplete; + } + + void appendConfigData() + { + } + + /* + * handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors. + * Use this to blank out some LEDs or set them to a different color regardless of the set effect mode. + * Commonly used for custom clocks (Cronixie, 7 segment) + */ + void handleOverlayDraw() + { + //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black + } + + + /* + * 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_ARTIFX; + } +}; + +// strings to reduce flash memory usage (used more than twice) +const char ARTIFXUserMod::_name[] PROGMEM = "ARTIFX"; diff --git a/usermods/blynk_relay_control/README.md b/usermods/blynk_relay_control/README.md deleted file mode 100644 index b6494b46e7..0000000000 --- a/usermods/blynk_relay_control/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Blynk controllable relay -This usermod allows controlling a relay state from the user variables. It also allows the user variables to be set over Blynk. - -Optionally, the servo can have a reset timer to go back to it's default state after an interval. This interval is set through userVar1. - -## Instalation - -Replace the WLED06_usermod.ino file in Aircoookies WLED folder with the one here. - -## Customizations - -Update the following parameters in WLED06_usermod.ino to configure the mod's behavior: - -```cpp -//Which pin is the relay connected to -#define RELAY_PIN 5 -//Which pin state should the relay default to -#define RELAY_PIN_DEFAULT LOW -//If >0 The controller returns to RELAY_PIN_DEFAULT after this time in milliseconds -#define RELAY_PIN_TIMER_DEFAULT 3000 - -//Blynk virtual pin for controlling relay -#define BLYNK_USER_VAR0_PIN V9 -//Blynk virtual pin for controlling relay timer -#define BLYNK_USER_VAR1_PIN V10 -//Number of milliseconds between updating blynk -#define BLYNK_RELAY_UPDATE_INTERVAL 5000 -``` diff --git a/usermods/blynk_relay_control/wled06_usermod.ino b/usermods/blynk_relay_control/wled06_usermod.ino deleted file mode 100644 index d4028ea5da..0000000000 --- a/usermods/blynk_relay_control/wled06_usermod.ino +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality - * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h) - * bytes 2400+ are currently ununsed, but might be used for future wled features - */ - -//Use userVar0 (API calls &U0=, uint16_t) to set relay state -#define relayPinState userVar0 -//Use userVar1 (API calls &U1=, uint16_t) to set relay timer duration -//Ignored if 0, otherwise number of milliseconds to allow relay to stay in -//non default state. -#define relayTimerInterval userVar1 - -//Which pin is the relay connected to -#define RELAY_PIN 5 -//Which pin state should the relay default to -#define RELAY_PIN_DEFAULT LOW -//If >0 The controller returns to RELAY_PIN_DEFAULT after this time in milliseconds -#define RELAY_PIN_TIMER_DEFAULT 3000 - -//Blynk virtual pin for controlling relay -#define BLYNK_USER_VAR0_PIN V9 -//Blynk virtual pin for controlling relay timer -#define BLYNK_USER_VAR1_PIN V10 -//Number of milliseconds between updating blynk -#define BLYNK_RELAY_UPDATE_INTERVAL 5000 - -//Is the timer for resetting the relay active -bool relayTimerStarted = false; -//millis() time after which relay will be reset -unsigned long relayTimeToDefault = 0; -//millis() time after which relay vars in Blynk will be sent -unsigned long relayBlynkUpdateTime = 0; - -//gets called once at boot. Do all initialization that doesn't depend on network here -void userSetup() -{ - relayPinState = RELAY_PIN_DEFAULT; - relayTimerInterval = RELAY_PIN_TIMER_DEFAULT; - pinMode(RELAY_PIN, OUTPUT); - digitalWrite(RELAY_PIN, relayPinState); -} - -//gets called every time WiFi is (re-)connected. Initialize own network interfaces here -void userConnected() -{ -} - -//loop. You can use "if (WLED_CONNECTED)" to check for successful connection -void userLoop() -{ - //Normalize relayPinState to an accepted value - if (relayPinState != HIGH && relayPinState != LOW) { - relayPinState = RELAY_PIN_DEFAULT; - } - //If relay changes and relayTimerInterval is set, start a timer to change back - if (relayTimerInterval != 0 && - relayPinState != RELAY_PIN_DEFAULT && - !relayTimerStarted ) { - relayTimerStarted = true; - relayTimeToDefault = millis() + relayTimerInterval; - } - //If manually changed back to default, cancel timer - if (relayTimerStarted && relayPinState == RELAY_PIN_DEFAULT ) { - relayTimerStarted = false; - } - //If timer completes, set relay back to default - if (relayTimerStarted && millis() > relayTimeToDefault) { - relayPinState = RELAY_PIN_DEFAULT; - relayTimerStarted = false; - } - digitalWrite(RELAY_PIN, relayPinState); - updateRelayBlynk(); -} - -//Update Blynk with state of userVars at BLYNK_RELAY_UPDATE_INTERVAL -void updateRelayBlynk() -{ - if (!WLED_CONNECTED) return; - if (relayBlynkUpdateTime > millis()) return; - Blynk.virtualWrite(BLYNK_USER_VAR0_PIN, userVar0); - Blynk.virtualWrite(BLYNK_USER_VAR1_PIN, userVar1); - relayBlynkUpdateTime = millis() + BLYNK_RELAY_UPDATE_INTERVAL; -} - -//Add Blynk callback for setting userVar0 -BLYNK_WRITE(BLYNK_USER_VAR0_PIN) -{ - userVar0 = param.asInt(); -} -//Add Blynk callback for setting userVar1 -BLYNK_WRITE(BLYNK_USER_VAR1_PIN) -{ - userVar1 = param.asInt(); -} diff --git a/usermods/mpu6050_imu/usermod_mpu6050_imu.h b/usermods/mpu6050_imu/usermod_mpu6050_imu.h index 4aa2a128fb..2f8d3e2bbf 100644 --- a/usermods/mpu6050_imu/usermod_mpu6050_imu.h +++ b/usermods/mpu6050_imu/usermod_mpu6050_imu.h @@ -31,6 +31,7 @@ 5. Wire up the MPU6050 as detailed above. */ +#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE // WLEDSR #include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" @@ -42,6 +43,7 @@ #include "Wire.h" #endif +#if !defined(HW_PIN_SCL) && !defined(HW_PIN_SDA) #ifdef ARDUINO_ARCH_ESP32 #define HW_PIN_SCL 22 #define HW_PIN_SDA 21 @@ -49,6 +51,7 @@ #define HW_PIN_SCL 5 #define HW_PIN_SDA 4 #endif +#endif // ================================================================ // === INTERRUPT DETECTION ROUTINE === @@ -97,7 +100,7 @@ class MPU6050Driver : public Usermod { if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; } // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE - Wire.begin(); + Wire.begin(HW_PIN_SDA, HW_PIN_SCL); // WLEDSR bugfix Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h index 4926469d6d..f27c6c60ee 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h @@ -61,7 +61,7 @@ class AutoSaveUsermod : public Usermod { void inline saveSettings() { char presetNameBuffer[PRESET_NAME_BUFFER_SIZE]; updateLocalTime(); - sprintf_P(presetNameBuffer, + snprintf_P(presetNameBuffer, PRESET_NAME_BUFFER_SIZE -1, PSTR("~ %02d-%02d %02d:%02d:%02d ~"), month(localTime), day(localTime), hour(localTime), minute(localTime), second(localTime)); diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h index 8de9b2e7ea..466b7d7235 100644 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h @@ -1,5 +1,6 @@ #pragma once +#include #include "wled.h" #include // from https://github.com/olikraus/u8g2/ #include "Wire.h" @@ -26,21 +27,29 @@ //The SCL and SDA pins are defined here. #ifdef ARDUINO_ARCH_ESP32 + #if !defined(HW_PIN_SCL) #define HW_PIN_SCL 22 + #endif + #if !defined(HW_PIN_SDA) #define HW_PIN_SDA 21 + #endif + #if !defined(HW_PIN_CLOCKSPI) #define HW_PIN_CLOCKSPI 18 + #endif + #if !defined(HW_PIN_DATASPI) #define HW_PIN_DATASPI 23 + #endif #ifndef FLD_PIN_SCL - #define FLD_PIN_SCL 22 + #define FLD_PIN_SCL HW_PIN_SCL #endif #ifndef FLD_PIN_SDA - #define FLD_PIN_SDA 21 + #define FLD_PIN_SDA HW_PIN_SDA #endif #ifndef FLD_PIN_CLOCKSPI - #define FLD_PIN_CLOCKSPI 18 + #define FLD_PIN_CLOCKSPI HW_PIN_CLOCKSPI #endif #ifndef FLD_PIN_DATASPI - #define FLD_PIN_DATASPI 23 + #define FLD_PIN_DATASPI HW_PIN_DATASPI #endif #ifndef FLD_PIN_DC #define FLD_PIN_DC 19 diff --git a/usermods/usermod_v2_four_line_display_ALT/readme.md b/usermods/usermod_v2_four_line_display_ALT/readme.md index 67cde35326..7b466c0186 100644 --- a/usermods/usermod_v2_four_line_display_ALT/readme.md +++ b/usermods/usermod_v2_four_line_display_ALT/readme.md @@ -31,8 +31,8 @@ Also shows if the timer is enabled ## Installation Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions -Then to activate this alternative usermod add `#define USE_ALT_DISPlAY` to the `usermods_list.cpp` file, - or add `-D USE_ALT_DISPlAY` to the original `platformio_override.ini.sample` file +Then to activate this alternative usermod add `#define USE_ALT_DISPLAY` to the `usermods_list.cpp` file, + or add `-D USE_ALT_DISPLAY` to the original `platformio_override.ini.sample` file ### PlatformIO requirements diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index 40d534f8e8..74265ca7c9 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -1,5 +1,6 @@ #pragma once +#include #include "wled.h" #include // from https://github.com/olikraus/u8g2/ #include "4LD_wled_fonts.c" @@ -26,21 +27,31 @@ //The SCL and SDA pins are defined here. #ifdef ARDUINO_ARCH_ESP32 + #if !defined(HW_PIN_SCL) #define HW_PIN_SCL 22 + #endif + #if !defined(HW_PIN_SDA) #define HW_PIN_SDA 21 + #endif + + #if !defined(HW_PIN_CLOCKSPI) #define HW_PIN_CLOCKSPI 18 + #endif + #if !defined(HW_PIN_DATASPI) #define HW_PIN_DATASPI 23 + #endif + #ifndef FLD_PIN_SCL - #define FLD_PIN_SCL 22 + #define FLD_PIN_SCL HW_PIN_SCL #endif #ifndef FLD_PIN_SDA - #define FLD_PIN_SDA 21 + #define FLD_PIN_SDA HW_PIN_SDA #endif #ifndef FLD_PIN_CLOCKSPI - #define FLD_PIN_CLOCKSPI 18 + #define FLD_PIN_CLOCKSPI HW_PIN_CLOCKSPI #endif #ifndef FLD_PIN_DATASPI - #define FLD_PIN_DATASPI 23 + #define FLD_PIN_DATASPI HW_PIN_DATASPI #endif #ifndef FLD_PIN_DC #define FLD_PIN_DC 19 diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md index a140f25b91..f5ebe0eb3f 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md @@ -31,8 +31,8 @@ Also shows if the timer is enabled ## Installation Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions -Then to activate this alternative usermod add `#define USE_ALT_DISPlAY` to the `usermods_list.cpp` file, - or add `-D USE_ALT_DISPlAY` to the original `platformio_override.ini.sample` file +Then to activate this alternative usermod add `#define USE_ALT_DISPLAY` to the `usermods_list.cpp` file, + or add `-D USE_ALT_DISPLAY` to the original `platformio_override.ini.sample` file ### PlatformIO requirements diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 4629f547a7..d8e7f6c86d 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -339,8 +339,10 @@ class RotaryEncoderUIUsermod : public Usermod { findCurrentEffectAndPalette(); } - if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) { - currentEffectAndPaletteInitialized = false; + if ((modes_alpha_indexes != nullptr) && (palettes_alpha_indexes != nullptr)) { // WLEDSR bugfix + if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) { + currentEffectAndPaletteInitialized = false; + } } if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz @@ -429,11 +431,13 @@ class RotaryEncoderUIUsermod : public Usermod { void displayNetworkInfo() { #ifdef USERMOD_FOUR_LINE_DISPLAY - display->networkOverlay(PSTR("NETWORK INFO"), 10000); + if (display != nullptr) // WLEDSR bugfix + display->networkOverlay(PSTR("NETWORK INFO"), 10000); #endif } void findCurrentEffectAndPalette() { + if (modes_alpha_indexes == nullptr) return; // WLEDSR bugfix currentEffectAndPaletteInitialized = true; for (uint8_t i = 0; i < strip.getModeCount(); i++) { if (modes_alpha_indexes[i] == effectCurrent) { @@ -470,7 +474,8 @@ class RotaryEncoderUIUsermod : public Usermod { // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa //setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required) stateUpdated(CALL_MODE_BUTTON); - updateInterfaces(CALL_MODE_BUTTON); + if ((millis() - lastInterfaceUpdate) > INTERFACE_UPDATE_COOLDOWN) // WLEDSR respect cooldown times, to avoid crash in AsyncWebSocketMessageBuffer + updateInterfaces(CALL_MODE_BUTTON); } void changeBrightness(bool increase) { @@ -500,7 +505,7 @@ class RotaryEncoderUIUsermod : public Usermod { display->updateRedrawTime(); #endif effectCurrentIndex = max(min((increase ? effectCurrentIndex+1 : effectCurrentIndex-1), strip.getModeCount()-1), 0); - effectCurrent = modes_alpha_indexes[effectCurrentIndex]; + if (modes_alpha_indexes != nullptr) effectCurrent = modes_alpha_indexes[effectCurrentIndex]; // WLEDSR bugfix stateChanged = true; if (applyToAll) { for (byte i=0; i SEGENV.step) { if(random8((255-SEGMENT.intensity) >> 4) == 0) { - for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) { + for(uint16_t i = 0; i < max(1, SEGLEN/3); i++) { setPixelColor(random16(SEGLEN), SEGCOLOR(1)); } } @@ -1104,7 +1129,7 @@ uint16_t WS2812FX::mode_comet(void) { /* * Fireworks function. */ -uint16_t WS2812FX::mode_fireworks() { +uint16_t WS2812FX::mode_fireworks_core(bool useAudio) { fade_out(0); if (SEGENV.call == 0) { SEGENV.aux0 = UINT16_MAX; @@ -1115,21 +1140,61 @@ uint16_t WS2812FX::mode_fireworks() { uint32_t sv1 = 0, sv2 = 0; if (valid1) sv1 = getPixelColor(SEGENV.aux0); if (valid2) sv2 = getPixelColor(SEGENV.aux1); - blur(255-SEGMENT.speed); + + // WLEDSR + uint8_t blurAmount = 255 - SEGMENT.speed; // make parameter explicit + uint8_t my_intensity = 129 - (SEGMENT.intensity >> 1); + bool addPixels = true; // false -> inhibit new pixels in silence + int soundColor = -1; // -1 = random color; 0..255 = use as palette index + + if (useAudio) { + if (FFT_MajorPeak < 100) { blurAmount = 254;} // big blobs + else { + if (FFT_MajorPeak > 3200) { blurAmount = 1;} // small blobs + else { // blur + color depends on major frequency + float musicIndex = logf(FFT_MajorPeak); // log scaling of peak freq + blurAmount = mapff(musicIndex, 4.60, 8.08, 253, 1);// map to blur range (low freq = more blur) + blurAmount = constrain(blurAmount, 1, 253); // remove possible "overshot" results + soundColor = mapff(musicIndex, 4.6, 8.08, 0, 255); // pick color from frequency + } } + if (sampleAgc <= 1.0) { // silence -> no new pixels, just blur + valid1 = valid2 = false; // do not copy last pixels + addPixels = false; + blurAmount = 128; + } + my_intensity = 129 - (SEGMENT.speed >> 1); // dirty hack: use "speed" slider value intensity (no idea how to _disable_ the first slider, but show the second one) + if (samplePeak == 1) my_intensity -= my_intensity / 4; // inclease intensity at peaks + if (samplePeak > 1) my_intensity = my_intensity / 2; // double intensity at main peaks + } + // WLEDSR end + + blur(blurAmount); if (valid1) setPixelColor(SEGENV.aux0 , sv1); if (valid2) setPixelColor(SEGENV.aux1, sv2); - for(uint16_t i=0; i> 1)) == 0) { - uint16_t index = random(SEGLEN); - setPixelColor(index, color_from_palette(random8(), false, false, 0)); - SEGENV.aux1 = SEGENV.aux0; - SEGENV.aux0 = index; + if (addPixels) { // WLEDSR + for(uint16_t i=0; i> 16); byte g = (SEGCOLOR(0) >> 8); byte b = (SEGCOLOR(0) ); - byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255; + byte lum = (SEGMENT.palette == 0) ? max(w, max(r, max(g, b))) : 255; lum /= (((256-SEGMENT.intensity)/16)+1); for(uint16_t i = 0; i < SEGLEN; i++) { byte flicker = random8(lum); if (SEGMENT.palette == 0) { - setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); + setPixelColor(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0)); } else { setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker)); } @@ -1201,7 +1266,7 @@ uint16_t WS2812FX::gradient_base(bool loading) { { val = abs(((i>pp) ? p2:pp) -i); } else { - val = MIN(abs(pp-i),MIN(abs(p1-i),abs(p2-i))); + val = min(abs(pp-i),min(abs(p1-i),abs(p2-i))); } val = (brd > val) ? val/brd * 255 : 255; setPixelColor(i, color_blend(SEGCOLOR(0), color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val)); @@ -1557,18 +1622,26 @@ uint16_t WS2812FX::mode_tricolor_fade(void) * Creates random comets * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h */ -uint16_t WS2812FX::mode_multi_comet(void) +#define MAX_COMETS 12 // was 8 +uint16_t WS2812FX::mode_multi_comet_core(bool useAudio) { uint32_t cycleTime = 10 + (uint32_t)(255 - SEGMENT.speed); uint32_t it = now / cycleTime; + if (!SEGENV.allocateData(sizeof(uint16_t) * MAX_COMETS)) return mode_static(); //allocation failed + uint16_t* comets = reinterpret_cast(SEGENV.data); + + if (SEGENV.call == 0) { // do some initializations + for(uint8_t i=0; i < MAX_COMETS; i++) comets[i] = SEGLEN; // WLEDSR make sure comments are started individually + SEGENV.aux0 = 0; + } + if (SEGENV.step == it) return FRAMETIME; - if (!SEGENV.allocateData(sizeof(uint16_t) * 8)) return mode_static(); //allocation failed + uint16_t armed = SEGENV.aux0; // WELDSR allows to delay comet launch + bool shotOne = false; // WLEDSR avoids starting several coments at the same time (invisible due to overlap) fade_out(SEGMENT.intensity); - uint16_t* comets = reinterpret_cast(SEGENV.data); - - for(uint8_t i=0; i < 8; i++) { + for(uint8_t i=0; i < MAX_COMETS; i++) { if(comets[i] < SEGLEN) { uint16_t index = comets[i]; if (SEGCOLOR(2) != 0) @@ -1580,16 +1653,40 @@ uint16_t WS2812FX::mode_multi_comet(void) } comets[i]++; } else { - if(!random(SEGLEN)) { - comets[i] = 0; + // randomly launch a new comet + if (!useAudio) { + if(!random(SEGLEN) && !shotOne) { + comets[i] = 0; + shotOne = true; // WLEDSR avoid starting several comets at once (as they are invisible) + } + } else { // WLEDSR delay comet "launch" during silence, and wait until next beat + if (random(SEGLEN) < 5) armed++; // new comet loaded and ready + if (armed > 2) armed = 2; // max two armed at once (avoid overlap) + if ( (armed > 0) && (shotOne == false) + && (sampleAgc > 1.0) && ((samplePeak > 1) || (int(rawSampleAgc) > 112)) ) { // delayed lauch - wait until peak, don't launch in silence + comets[i] = 0; // start a new comet! + armed--; // un-arm one + shotOne = true; + } } } } + SEGENV.aux0 = armed; // WLEDSR SEGENV.step = it; return FRAMETIME; } +// normal multi-comet +uint16_t WS2812FX::mode_multi_comet(void) +{ + return(mode_multi_comet_core(false)); +} +// audioresponsive multi-comet +uint16_t WS2812FX::mode_multi_comet_audio(void) +{ + return(mode_multi_comet_core(true)); +} /* * Creates two Larson scanners moving in opposite directions @@ -1799,27 +1896,71 @@ uint16_t WS2812FX::mode_juggle(void){ } -uint16_t WS2812FX::mode_palette() +uint16_t WS2812FX::mode_palette_core(bool useAudio) { uint16_t counter = 0; - if (SEGMENT.speed != 0) - { - counter = (now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; - counter = counter >> 8; - } + uint16_t cooldown = 0; // WLEDSR + bool fadeOut = (useAudio && (sampleAgc < 1)); // WLEDSR - fade away when silence + + // WLEDSR + if (useAudio) { + //binNum = SEGMENT.custom2; // Select a bin for peak detection. + //maxVol = SEGMENT.custom3/2; // Our volume comparator. + if(SEGENV.call == 0) { // initialize a few things + counter = (now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; + counter = counter >> 8; + SEGENV.aux0 = counter; + SEGENV.aux1 = 64; + } + + counter = SEGENV.aux0; + cooldown= SEGENV.aux1; + if ((sampleAgc > 1) && ((samplePeak > 1) || (samplePeak > 0 && (SEGMENT.speed < 48 || SEGMENT.speed > 252)))) { + // start rotating on beat + cooldown = 12 + (SEGMENT.speed >> 2) +1; + } + // keep rotating after beat + if (cooldown > 0) { + cooldown--; + counter += (SEGMENT.speed >> 2) +4; + counter += (cooldown >> 2); + } + SEGENV.aux0 = counter; + SEGENV.aux1 = cooldown; + counter = counter >> 5; + counter = counter & 0xFF; + // WLEDSR end - bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0)); - for (uint16_t i = 0; i < SEGLEN; i++) - { - uint8_t colorIndex = (i * 255 / SEGLEN) - counter; + } else { + if (SEGMENT.speed != 0) { + counter = (now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; + counter = counter >> 8; + } } + + if (fadeOut) fade_out(6); // WLEDSR: fade away + else { + bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0)); + for (uint16_t i = 0; i < SEGLEN; i++) + { + uint8_t colorIndex = (i * 255 / SEGLEN) - counter; - if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end" + if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end" - setPixelColor(i, color_from_palette(colorIndex, false, true, 255)); + setPixelColor(i, color_from_palette(colorIndex, false, true, 255)); + } } return FRAMETIME; } +uint16_t WS2812FX::mode_palette(void) { + // standard version + return mode_palette_core(false); +} +uint16_t WS2812FX::mode_palette_audio(void) { + // audioresponsive version: fades out in silence, rotates at beat + return mode_palette_core(true); +} + // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active // Fire2012 by Mark Kriegsman, July 2012 @@ -1884,7 +2025,7 @@ uint16_t WS2812FX::mode_fire_2012() // Step 4. Map from heat cells to LED colors for (uint16_t j = 0; j < SEGLEN; j++) { - CRGB color = ColorFromPalette(currentPalette, MIN(heat[j],240), 255, LINEARBLEND); + CRGB color = ColorFromPalette(currentPalette, min(heat[j],(byte)240), 255U, LINEARBLEND); setPixelColor(j, color.red, color.green, color.blue); } return FRAMETIME; @@ -2655,7 +2796,7 @@ uint16_t WS2812FX::mode_bouncing_balls(void) { uint8_t numBalls = int(((SEGMENT.intensity * (maxNumBalls - 0.8f)) / 255) + 1); float gravity = -9.81; // standard value of gravity - float impactVelocityStart = sqrt( -2 * gravity); + float impactVelocityStart = sqrtf( -2 * gravity); unsigned long time = millis(); @@ -2668,12 +2809,13 @@ uint16_t WS2812FX::mode_bouncing_balls(void) { for (uint8_t i = 0; i < numBalls; i++) { float timeSinceLastBounce = (time - balls[i].lastBounceTime)/((255-SEGMENT.speed)*8/256 +1); - balls[i].height = 0.5 * gravity * pow(timeSinceLastBounce/1000 , 2.0) + balls[i].impactVelocity * timeSinceLastBounce/1000; + float timeSinceLastBounceMs = timeSinceLastBounce/1000.0f; + balls[i].height = 0.5 * gravity * (timeSinceLastBounceMs * timeSinceLastBounceMs) + balls[i].impactVelocity * timeSinceLastBounceMs; if (balls[i].height < 0) { //start bounce balls[i].height = 0; //damping for better effect using multiple balls - float dampening = 0.90 - float(i)/pow(numBalls,2); + float dampening = 0.90 - float(i)/(numBalls * numBalls); balls[i].impactVelocity = dampening * balls[i].impactVelocity; balls[i].lastBounceTime = time; @@ -2684,7 +2826,7 @@ uint16_t WS2812FX::mode_bouncing_balls(void) { uint32_t color = SEGCOLOR(0); if (SEGMENT.palette) { - color = color_wheel(i*(256/MAX(numBalls, 8))); + color = color_wheel(i*(256/max(numBalls, (uint8_t)8))); } else if (hasCol2) { color = SEGCOLOR(i % NUM_COLORS); } @@ -2774,10 +2916,11 @@ typedef struct Spark { * POPCORN * modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h */ -uint16_t WS2812FX::mode_popcorn(void) { +uint16_t WS2812FX::mode_popcorn_core(bool useAudio) { //allocate segment data - uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266 - uint16_t dataSize = sizeof(spark) * maxNumPopcorn; + //constexpr uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266 + constexpr uint16_t maxNumPopcorn = 29; // WLEDSR - max 29 on 16 segment ESP32 + constexpr uint16_t dataSize = sizeof(spark) * maxNumPopcorn; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Spark* popcorn = reinterpret_cast(SEGENV.data); @@ -2787,21 +2930,32 @@ uint16_t WS2812FX::mode_popcorn(void) { bool hasCol2 = SEGCOLOR(2); fill(hasCol2 ? BLACK : SEGCOLOR(1)); + //fade_out(253); - uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255; + uint8_t numPopcorn = (unsigned)SEGMENT.intensity*(unsigned)maxNumPopcorn/255; if (numPopcorn == 0) numPopcorn = 1; for(uint8_t i = 0; i < numPopcorn; i++) { if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position popcorn[i].pos += popcorn[i].vel; - popcorn[i].vel += gravity; + popcorn[i].vel += gravity; } else { // if kernel is inactive, randomly pop it - if (random8() < 2) { // POP!!! + bool doPopCorn = false; + if (!useAudio) { + if (random8() < 2) doPopCorn = true; + } else { + if ( (sampleAgc > 1.0) // WLEDSR - no pops in silence + && ((samplePeak > 0) || (int(rawSampleAgc) > 128)) // WLEDSR - try to pop at onsets + && (random8() < 4) ) // WLEDSR - randomize + doPopCorn = true; + } + + if (doPopCorn) { // POP!!! popcorn[i].pos = 0.01f; uint16_t peakHeight = 128 + random8(128); //0-255 peakHeight = (peakHeight * (SEGLEN -1)) >> 8; - popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight); + popcorn[i].vel = sqrtf(-2.0 * gravity * peakHeight); if (SEGMENT.palette) { @@ -2824,6 +2978,13 @@ uint16_t WS2812FX::mode_popcorn(void) { return FRAMETIME; } +uint16_t WS2812FX::mode_popcorn(void) { + return(mode_popcorn_core(false)); +} +uint16_t WS2812FX::mode_popcorn_audio(void) { + return(mode_popcorn_core(true)); +} + //values close to 100 produce 5Hz flicker, which looks very candle-y //Inspired by https://github.com/avanhanegem/ArduinoCandleEffectNeoPixel @@ -2936,7 +3097,7 @@ typedef struct particle { float fragment[STARBURST_MAX_FRAG]; } star; -uint16_t WS2812FX::mode_starburst(void) { +uint16_t WS2812FX::mode_starburst_core(bool useAudio) { uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 uint8_t segs = getActiveSegmentsNum(); if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs @@ -2959,8 +3120,24 @@ uint16_t WS2812FX::mode_starburst(void) { for (int j = 0; j < numStars; j++) { - // speed to adjust chance of a burst, max is nearly always. - if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) + bool doNewStar = false; + + if (!useAudio) { + // speed to adjust chance of a burst, max is nearly always. + if (random8((144-(SEGMENT.speed >> 1))) == 0) doNewStar = true; // original non-audio version + + } else { // WLEDSR audio responsive version + int burstplus = (sampleAgc > 159)? 128:0; // high volume -> more stars + if (rawSampleAgc <= 56) burstplus = -64; // low volume -> fewer stars + int birthrate = (144-(SEGMENT.speed >> 1)) - burstplus; // original "burstrate formula" + birthrate = constrain(birthrate, 0, 144); + if ( (sampleAgc > 1.0) // no bursts in silence + && ((samplePeak > 1) || (int(rawSampleAgc) > 31)) // try to burst with sound + && (random8(birthrate) == 0 )) // original random rate + doNewStar = true; + } + + if ((doNewStar == true) && (stars[j].birth == 0)) { // Pick a random color and location. uint16_t startPos = random16(SEGLEN-1); @@ -3045,6 +3222,14 @@ uint16_t WS2812FX::mode_starburst(void) { } return FRAMETIME; } + +uint16_t WS2812FX::mode_starburst(void) { + return(mode_starburst_core(false)); +} +uint16_t WS2812FX::mode_starburst_audio(void) { + return(mode_starburst_core(true)); +} + #undef STARBURST_MAX_FRAG /* @@ -3086,7 +3271,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) flare->pos = 0; uint16_t peakHeight = 75 + random8(180); //0-255 peakHeight = (peakHeight * (SEGLEN -1)) >> 8; - flare->vel = sqrt(-2.0 * gravity * peakHeight); + flare->vel = sqrtf(-2.0 * gravity * peakHeight); flare->col = 255; //brightness SEGENV.aux0 = 1; @@ -3332,7 +3517,7 @@ uint16_t WS2812FX::mode_plasma(void) { */ uint16_t WS2812FX::mode_percent(void) { - uint8_t percent = MAX(0, MIN(200, SEGMENT.intensity)); + uint8_t percent = max((uint8_t)0, min((uint8_t)200, SEGMENT.intensity)); uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0 : SEGLEN * (200 - percent) / 100.0; @@ -4263,36 +4448,8 @@ uint16_t WS2812FX::mode_aurora(void) { -// Sound reactive external variables. -extern int sampleRaw; -extern float sampleAvg; -extern bool samplePeak; -extern uint8_t myVals[32]; -//extern int sampleAgc; -extern int rawSampleAgc; -extern float sampleAgc; -extern uint8_t squelch; -extern byte soundSquelch; -extern byte soundAgc; -extern uint8_t maxVol; -extern uint8_t binNum; - -extern float sampleReal; // "sample" as float, to provide bits that are lost otherwise. Needed for AGC. -extern float multAgc; // sampleReal * multAgc = sampleAgc. Our multiplier - -// FFT based variables -extern float FFT_MajorPeak; -extern float FFT_Magnitude; -extern float fftBin[]; // raw FFT data -extern int fftResult[]; // summary of bins array. 16 summary bins. -extern float fftAvg[]; - - -/////////////////////////////////////// -// Helper function(s) // -/////////////////////////////////////// - -double mapf(double x, double in_min, double in_max, double out_min, double out_max); +// Sound reactive external variables and helper functions + /* softhack007: moved up to make them availeable to "normal" effects, too */ //////////////////////////// // set Pixels // @@ -4480,7 +4637,45 @@ void WS2812FX::nscale8( CRGB* leds, uint8_t scale) } } +//line function +void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { + const uint16_t cols = SEGMENT.width; + const uint16_t rows = SEGMENT.height; + if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; + const int16_t dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; + for (;;) { + setPixelColor(XY(x0,y0),c); + if (x0==x1 && y0==y1) break; + e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } +} + +void WS2812FX::drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor) { + // float step = degrees / (2.85f*MAX(radius,1)); + // for (float rad = 0.0f; rad <= degrees+step/2; rad += step) { + // // may want to try float version as well (with or without antialiasing) + // int x = roundf(sin_t(rad) * radius); + // int y = roundf(cos_t(rad) * radius); + // setPixelColorXY(x+x0, y+y0, c); + // } + float minradius = radius - .5; + float maxradius = radius + .5; + for (int x=0; x= minradius * minradius && newX*newX + newY*newY <= maxradius * maxradius) + setPixelColor(XY(x, y), color); + if (fillColor != 0) + if (newX*newX + newY*newY < minradius * minradius) + setPixelColor(XY(x, y), fillColor); + } +} uint16_t WS2812FX::XY(uint16_t x, uint16_t y) { // ewowi20210703: new XY: segmentToReal: Maps XY in 2D segment to to rotated and mirrored logical index. Works for 1D strips and 2D panels return segmentToLogical(x%SEGMENT.width + y%SEGMENT.height * SEGMENT.width); @@ -4672,8 +4867,8 @@ uint16_t WS2812FX::mode_2DDrift() { // By: Stepko https://editor. unsigned long t = millis() / (32 - SEGMENT.speed/8); for (float i = 1; i < maxDim / 2; i += 0.25) { double angle = radians(t * (maxDim / 2 - i)); - int myX = (int)(CenterX + sin(angle) * i); - int myY = (int)(CenterY + cos(angle) * i); + int myX = (int)(CenterX + sinf(angle) * i); + int myY = (int)(CenterY + cosf(angle) * i); leds[XY( myX, myY)] += ColorFromPalette(currentPalette, (i * 20) + (t / 20), 255, LINEARBLEND); } blur2d(leds, SEGMENT.intensity/8); @@ -4893,7 +5088,7 @@ uint16_t WS2812FX::mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired //create new pattern String pattern = ""; - for (int x = 0; x < SEGMENT.width; x+=MAX(SEGMENT.width/8,1)) for (int y = 0; y < SEGMENT.height; y+=MAX(SEGMENT.height/8,1)) + for (int x = 0; x < SEGMENT.width; x+=max(SEGMENT.width/8,1)) for (int y = 0; y < SEGMENT.height; y+=max(SEGMENT.height/8,1)) pattern += leds[XY(x,y)] == backgroundColor?" ":"o"; //string representation if on/off //check if repetition of patterns occurs @@ -5006,8 +5201,8 @@ uint16_t WS2812FX::mode_2DJulia(void) { // An animated reAl = -0.94299; // PixelBlaze example imAg = 0.3162; - reAl += sin((float)millis()/305.)/20.; - imAg += sin((float)millis()/405.)/20.; + reAl += sinf((float)millis()/305.)/20.; + imAg += sinf((float)millis()/405.)/20.; // Serial.print(reAl,4); Serial.print("\t"); Serial.print(imAg,4); Serial.println(" "); @@ -5068,15 +5263,19 @@ uint16_t WS2812FX::mode_2DJulia(void) { // An animated uint16_t WS2812FX::mode_2DLissajous(void) { // By: Andrew Tuline + uint_fast16_t cols = SEGMENT.width; + uint_fast16_t rows = SEGMENT.height; + uint_fast16_t phase = (millis() * (1 + SEGMENT.custom3)) /256; // allow user to control rotation speed + fadeToBlackBy(leds, SEGMENT.intensity); for (int i=0; i < 256; i ++) { - uint8_t xlocn = sin8(millis()/2+i*SEGMENT.speed/64); - uint8_t ylocn = cos8(millis()/2+i*128/64); + uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/64); + uint_fast8_t ylocn = cos8(phase/2 + i*2); - xlocn = map(xlocn,0,255,0,SEGMENT.width-1); - ylocn = map(ylocn,0,255,0,SEGMENT.height-1); + xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "*2 +1" for proper rounding + ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 2" is needed to avoid div/0 in map() leds[XY(xlocn,ylocn)] = ColorFromPalette(currentPalette, millis()/100+i, 255, LINEARBLEND); } @@ -5094,7 +5293,7 @@ uint16_t WS2812FX::mode_2Dmatrix(void) { // Matrix2D. By Jeremy if (SEGENV.call == 0) fill_solid(leds, 0); int fade = map(SEGMENT.custom1, 0, 255, 50, 250); // equals trail size - int speed = (256-SEGMENT.speed) >> map(MIN(SEGMENT.height, 150), 0, 150, 0, 3); // slower speeds for small displays + int speed = (256-SEGMENT.speed) >> map(min(SEGMENT.height, (uint16_t)150), 0, 150, 0, 3); // slower speeds for small displays CRGB spawnColor; CRGB trailColor; @@ -5175,15 +5374,15 @@ uint16_t WS2812FX::mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Ca // and add them together with weightening uint16_t dx = abs(x - x1); uint16_t dy = abs(y - y1); - uint16_t dist = 2 * sqrt((dx * dx) + (dy * dy)); + uint16_t dist = 2 * sqrtf((dx * dx) + (dy * dy)); dx = abs(x - x2); dy = abs(y - y2); - dist += sqrt((dx * dx) + (dy * dy)); + dist += sqrtf((dx * dx) + (dy * dy)); dx = abs(x - x3); dy = abs(y - y3); - dist += sqrt((dx * dx) + (dy * dy)); + dist += sqrtf((dx * dx) + (dy * dy)); // inverse result byte color = 1000 / dist;//dist=0?1000: 1000 / dist; @@ -5590,8 +5789,9 @@ uint16_t WS2812FX::mode_gravcentric(void) { // Gravcentric. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - fade_out(240); - fade_out(240); + //fade_out(240); + //fade_out(240); + fade_out(226); // same as 2x fade_out(240) float tmpSound = (soundAgc) ? sampleAgc : sampleAvg; float segmentSampleAvg = tmpSound * (float)SEGMENT.intensity / 255.0; @@ -5639,7 +5839,7 @@ uint16_t WS2812FX::mode_gravimeter(void) { // Gravmeter. By Andre segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivty" upscaling float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment - int tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. + int tempsamp = constrain(mySampleAvg,0,SEGLEN); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; i= gravcen->topLED) - gravcen->topLED = tempsamp; + gravcen->topLED = max(tempsamp-1, 0); else if (gravcen->gravityCounter % gravity == 0) gravcen->topLED--; - if (gravcen->topLED > 0) { + if ((gravcen->topLED > 0) && (gravcen->topLED < SEGLEN-1)) { setPixelColor(gravcen->topLED, color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; +#if 0 // WLEDSR - for peak detection debugging + if(samplePeak > 0) setPixelColor(0, GREEN); + //if(samplePeak > 1) setPixelColor(1, ORANGE); + if(samplePeak > 0) setPixelColor(SEGLEN-1, GREEN); + //if(samplePeak > 1) setPixelColor(SEGLEN-2, GREEN); +#endif + return FRAMETIME; } // mode_gravimeter() @@ -5684,7 +5891,7 @@ uint16_t WS2812FX::mode_gravimeter(void) { // Gravmeter. By Andre float segmentSampleAvg = 64.0 * tmpSound * (float)SEGMENT.intensity / 128.0; float mySampleAvg = mapf(segmentSampleAvg, 0, 128, 0, (SEGLEN-1)); // map to pixels availeable in current segment - int tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. + int tempsamp = constrain(mySampleAvg,0,SEGLEN); // Keep the sample from overflowing. //tempsamp = SEGLEN - tempsamp; // uncomment to invert direction segmentSampleAvg=fmax(64.0 - fmin(segmentSampleAvg,63),8); // inverted brightness @@ -5736,8 +5943,8 @@ uint16_t WS2812FX::mode_juggles(void) { // Juggles. By Andrew uint16_t WS2812FX::mode_matripix(void) { // Matripix. By Andrew Tuline. if (SEGENV.call == 0) fill_solid(leds, 0); - uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; - if(SEGENV.aux0 != secondHand) { + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500 % 16) : 0; + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { SEGENV.aux0 = secondHand; uint8_t tmpSound = (soundAgc) ? rawSampleAgc : sampleRaw; int pixBri = tmpSound * SEGMENT.intensity / 64; @@ -5758,8 +5965,9 @@ uint16_t WS2812FX::mode_midnoise(void) { // Midnoise. By Andrew // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. - fade_out(SEGMENT.speed); - fade_out(SEGMENT.speed); + //fade_out(SEGMENT.speed); + //fade_out(SEGMENT.speed); + fade_out(int(SEGMENT.speed) * int(SEGMENT.speed) / 255); // same as two fade-out runs float tmpSound = (soundAgc) ? sampleAgc : sampleAvg; float tmpSound2 = tmpSound * (float)SEGMENT.intensity / 256.0; // Too sensitive. @@ -5859,9 +6067,9 @@ uint16_t WS2812FX::mode_pixels(void) { // Pixels. By Andrew T uint16_t WS2812FX::mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. if (SEGENV.call == 0) fill_solid(leds, 0); - uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16; + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500+1 % 16) : 0; - if(SEGENV.aux0 != secondHand) { + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { SEGENV.aux0 = secondHand; uint8_t tmpSound = (soundAgc) ? rawSampleAgc : sampleRaw; @@ -5936,7 +6144,7 @@ uint16_t WS2812FX::mode_puddlepeak(void) { // Puddlepeak. By Andr fade_out(fadeVal); - if (samplePeak == 1 ) { + if (samplePeak > 0 ) { size = sampleAgc * SEGMENT.intensity /256 /4 + 1; // Determine size of the flash based on the volume. if (pos+size>= SEGLEN) size=SEGLEN-pos; } @@ -6004,13 +6212,13 @@ uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By A binNum = SEGMENT.custom2; // Select a bin. maxVol = SEGMENT.custom3/2; // Our volume comparator. - fade_out(240); // Lower frame rate means less effective fading than FastLED - fade_out(240); - + //fade_out(240); // Lower frame rate means less effective fading then FastLED + //fade_out(240); + fade_out(226); for (uint16_t i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples. - if (samplePeak) { + if (samplePeak >0) { ripples[i].state = -1; } @@ -6060,7 +6268,13 @@ uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By A // BEGIN FFT ROUTINES // /////////////////////////////// -double mapf(double x, double in_min, double in_max, double out_min, double out_max){ +double mapf(double x, double in_min, double in_max, double out_min, double out_max){ // for double + if (in_max == in_min) return (out_min); // to avoid division by zero + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +static float mapff(float x, float in_min, float in_max, float out_min, float out_max){ // for float + if (fabs(in_max-in_min) < 0.000001 ) return (out_min); // to avoid division by zero return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } @@ -6092,7 +6306,7 @@ uint16_t WS2812FX::mode_binmap(void) { // Binmap. Scale raw f uint16_t endBin = FIRSTBIN+(i+1)*(LASTBIN-FIRSTBIN)/SEGLEN; // This is the END bin for this particular pixel. if (endBin > startBin) endBin --; // avoid overlapping - double sumBin = 0; + float sumBin = 0; for (int j=startBin; j<=endBin; j++) { sumBin += (fftBin[j] < soundSquelch*1.75) ? 0 : fftBin[j]; // We need some sound temporary squelch for fftBin, because we didn't do it for the raw bins in audio_reactive.h @@ -6106,7 +6320,7 @@ uint16_t WS2812FX::mode_binmap(void) { // Binmap. Scale raw f if (sumBin > maxVal) sumBin = maxVal; // Make sure our bin isn't higher than the max . . which we capped earlier. - uint8_t bright = constrain(mapf(sumBin, 0, maxVal, 0, 255),0,255); // Map the brightness in relation to maxVal and crunch to 8 bits. + uint8_t bright = constrain(mapff(sumBin, 0, maxVal, 0, 255),0,255); // Map the brightness in relation to maxVal and crunch to 8 bits. setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*8+millis()/50, false, PALETTE_SOLID_WRAP, 0), bright)); // 'i' is just an index in the palette. The FFT value, bright, is the intensity. @@ -6148,9 +6362,9 @@ uint16_t WS2812FX::mode_DJLight(void) { // Written by ??? Adap int NUM_LEDS = SEGLEN; // aka SEGLEN int mid = NUM_LEDS / 2; - uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 64; + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500+1 % 64) : 0; - if (SEGENV.aux0 != secondHand) { // Triggered millis timing. + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { // Triggered millis timing. SEGENV.aux0 = secondHand; leds[segmentToLogical(mid)] = CRGB(fftResult[15]/2, fftResult[5]/2, fftResult[0]/2); // 16-> 15 as 16 is out of bounds @@ -6204,16 +6418,16 @@ uint16_t WS2812FX::mode_freqmap(void) { // Map FFT_MajorPeak t uint16_t WS2812FX::mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. - uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500 % 16) : 0; - if(SEGENV.aux0 != secondHand) { + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { SEGENV.aux0 = secondHand; - double sensitivity = mapf(SEGMENT.custom3, 1, 255, 1, 10); + float sensitivity = mapff(SEGMENT.custom3, 1, 255, 1, 10); int pixVal = sampleAgc * SEGMENT.intensity / 256 * sensitivity; if (pixVal > 255) pixVal = 255; - double intensity = map(pixVal, 0, 255, 0, 100) / 100.0; // make a brightness from the last avg + float intensity = mapff(pixVal, 0, 255, 0, 100) / 100.0; // make a brightness from the last avg CRGB color = 0; CHSV c; @@ -6228,7 +6442,7 @@ uint16_t WS2812FX::mode_freqmatrix(void) { // Freqmatrix. By Andr } else { int upperLimit = 20 * SEGMENT.custom2; int lowerLimit = 2 * SEGMENT.custom1; - int i = lowerLimit!=upperLimit?map(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255):FFT_MajorPeak; + int i = lowerLimit!=upperLimit?mapff(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255):FFT_MajorPeak; uint16_t b = 255 * intensity; if (b > 255) b=255; c = CHSV(i, 240, (uint8_t)b); @@ -6307,10 +6521,9 @@ uint16_t WS2812FX::mode_freqwave(void) { // Freqwave. By Andrea // As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz. // Depending on the music stream you have you might find it useful to change the frequency mapping. - uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500 % 16) : 0; -// uint8_t secondHand = millis()/(256-SEGMENT.speed) % 10; - if(SEGENV.aux0 != secondHand) { + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { // Triggered millis timing. SEGENV.aux0 = secondHand; //uint8_t fade = SEGMENT.custom3; @@ -6318,11 +6531,11 @@ uint16_t WS2812FX::mode_freqwave(void) { // Freqwave. By Andrea float tmpSound = (soundAgc) ? sampleAgc : sampleAvg; - float sensitivity = mapf(SEGMENT.custom3, 1, 255, 1, 10); + float sensitivity = mapff(SEGMENT.custom3, 1, 255, 1, 10); float pixVal = tmpSound * (float)SEGMENT.intensity / 256.0 * sensitivity; if (pixVal > 255) pixVal = 255; - float intensity = mapf(pixVal, 0, 255, 0, 100) / 100.0; // make a brightness from the last avg + float intensity = mapff(pixVal, 0, 255, 0, 100) / 100.0; // make a brightness from the last avg CRGB color = 0; CHSV c; @@ -6337,7 +6550,7 @@ uint16_t WS2812FX::mode_freqwave(void) { // Freqwave. By Andrea } else { int upperLimit = 20 * SEGMENT.custom2; int lowerLimit = 2 * SEGMENT.custom1; - int i = lowerLimit!=upperLimit?map(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255):FFT_MajorPeak; + int i = lowerLimit!=upperLimit?mapff(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255):FFT_MajorPeak; if (i<0) i = 0; uint16_t b = 255.0 * intensity; if (b > 255) b=255; @@ -6380,7 +6593,7 @@ uint16_t WS2812FX::mode_gravfreq(void) { // Gravfreq. By Andrew float segmentSampleAvg = tmpSound * (float)SEGMENT.intensity / 255.0; segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment + float mySampleAvg = mapff(segmentSampleAvg*2.0, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -6462,7 +6675,7 @@ uint16_t WS2812FX::mode_rocktaves(void) { // Rocktaves. Same not // leds[beatsin8(8+octCount*4,0,SEGLEN-1,0,octCount*8)] += CHSV((uint8_t)frTemp,255,volTemp); // Back and forth with different frequencies and phase shift depending on current octave. - leds[segmentToLogical(mapf(beatsin8(8+octCount*4,0,255,0,octCount*8),0,255,0,SEGLEN-1))] += color_blend(SEGCOLOR(1), color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp); + leds[segmentToLogical(mapff(beatsin8(8+octCount*4,0,255,0,octCount*8),0,255,0,SEGLEN-1))] += color_blend(SEGCOLOR(1), color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp); setPixels(leds); @@ -6484,24 +6697,26 @@ uint16_t WS2812FX::mode_waterfall(void) { // Waterfall. By: An binNum = SEGMENT.custom2; // Select a bin. maxVol = SEGMENT.custom3/2; // Our volume comparator. - uint8_t secondHand = micros() / (256-SEGMENT.speed)/500 + 1 % 16; + uint8_t secondHand = (SEGMENT.speed < 255) ? (micros() / (256-SEGMENT.speed)/500 + 1 % 16) : 0; - if (SEGENV.aux0 != secondHand) { // Triggered millis timing. + if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { // Triggered millis timing. SEGENV.aux0 = secondHand; float my_magnitude = FFT_Magnitude / 8.0; if (soundAgc) my_magnitude *= multAgc; if (sampleAvg < 1 ) my_magnitude = 0.001; // noise gate closed - mute - int pixCol = (log10f(FFT_MajorPeak) - 2.26) * 177; // log10 frequency range is from 2.26 to 3.7. Let's scale accordingly. + int pixCol = (FFT_MajorPeak > 1.0) ? ((log10f(FFT_MajorPeak) - 2.26) * 177) : 0; // log10 frequency range is from 2.26 to 3.7. Let's scale accordingly. if (pixCol < 0) pixCol=0; - if (samplePeak) { - leds[segmentToLogical(SEGLEN-1)] = CHSV(92,92,92); - } else { - leds[segmentToLogical(SEGLEN-1)] = color_blend(SEGCOLOR(1), color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude); - } - for (int i=0; i 1) { + if (samplePeak >0) { + leds[segmentToLogical(SEGLEN-1)] = CHSV(92,92,92); + } else { + leds[segmentToLogical(SEGLEN-1)] = color_blend(SEGCOLOR(1), color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude); + } + } else leds[segmentToLogical(SEGLEN-1)] = SEGCOLOR(1); + for (int i=0; i 254) || (SEGENV.aux0 != secondHand)) { // Triggered millis timing. SEGENV.aux0 = secondHand; // display values of @@ -6738,7 +6953,7 @@ uint16_t WS2812FX::mode_2DAkemi(void) { // 3D !!!!!!!!!! float distance(uint16_t x1, uint16_t y1, uint16_t z1, uint16_t x2, uint16_t y2, uint16_t z2) { - return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2)); + return sqrtf((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2)); } uint16_t WS2812FX::mode_3DRipples(void) { diff --git a/wled00/FX.h b/wled00/FX.h index 5343369f08..5b01def1cf 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -77,13 +77,14 @@ #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS) // NEED WORKAROUND TO ACCESS PRIVATE CLASS VARIABLE '_frametime' -#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) +#define MIN_SHOW_DELAY (_frametime < 16 ? (_frametime <8? (_frametime <7? (_frametime <6 ? 2 :3) :4) : 8) : 15) // WLEDSR support higher framerates (up to 250fps) #define NUM_COLORS 3 /* number of colors per segment */ -#define SEGMENT _segments[_segment_index] -#define SEGCOLOR(x) _colors_t[x] -#define SEGENV _segment_runtimes[_segment_index] -#define SEGLEN _virtualSegmentLength +#define SEGMENT strip._segments[strip.getCurrSegmentId()] +#define SEGCOLOR(x) strip._colors_t[x] +#define SEGENV strip._segment_runtimes[strip.getCurrSegmentId()] +#define SEGPALETTE strip._currentPalette +#define SEGLEN strip._virtualSegmentLength #define SEGACT SEGMENT.stop #define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN @@ -120,7 +121,7 @@ #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED ) -#define MODE_COUNT 190// WLEDSR: First 128 for AC (incl reserved), rest for SR +#define MODE_COUNT 195 // WLEDSR: First 128 for AC (incl reserved), rest for SR #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -317,11 +318,17 @@ #define FX_MODE_WAVESINS 184 #define FX_MODE_ROCKTAVES 185 #define FX_MODE_2DAKEMI 186 -#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects +#define FX_MODE_ARTIFX 187 //WLEDSR ARTI-FX #define FX_MODE_3DRIPPLES 188 #define FX_MODE_3DSphereMove 189 -#define floatNull -32768 //WLEDSR Custom Effects +// Experimental Audioresponsive modes +#define FX_MODE_POPCORN_AR 190 +#define FX_MODE_MULTI_COMET_AR 191 +#define FX_MODE_STARBURST_AR 192 +#define FX_MODE_PALETTE_AR 193 +#define FX_MODE_FIREWORKS_AR 194 + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of Audio Reactive fork (WLEDSR) // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -424,7 +431,8 @@ class WS2812FX { } inline uint16_t length() { - return (stopX - startX + 1) * (stopY - startY + 1); //WLEDSR: calculate length using SEGMENT x/y. Used by SEGLEN + if ((stopX < startX) || (stopY < startY)) return 0; //WLEDSR: avoid unsigned underflow (stop = 0 is allowed) + else return (stopX - startX + 1) * (stopY - startY + 1); //WLEDSR: calculate length using SEGMENT x/y. Used by SEGLEN } inline uint16_t groupLength() { @@ -433,7 +441,7 @@ class WS2812FX { uint16_t virtualLength() { uint16_t groupLen = groupLength(); - uint16_t vLength = (length() + groupLen - 1) / groupLen; + uint16_t vLength = (groupLen > 0) ? ((length() + groupLen - 1) / groupLen) : 0; //WLEDSR avoid division by zero if (options & MIRROR) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED return vLength; @@ -790,9 +798,11 @@ class WS2812FX { _mode[FX_MODE_WAVESINS] = &WS2812FX::mode_wavesins; _mode[FX_MODE_ROCKTAVES] = &WS2812FX::mode_rocktaves; _mode[FX_MODE_2DAKEMI] = &WS2812FX::mode_2DAkemi; - _mode[FX_MODE_CUSTOMEFFECT] = &WS2812FX::mode_customEffect; //WLEDSR Custom Effects +#ifdef USERMOD_ARTIFX + _mode[FX_MODE_ARTIFX] = &WS2812FX::mode_ARTIFX; //WLEDMM ARTI-FX +#endif _mode[FX_MODE_3DRIPPLES] = &WS2812FX::mode_3DRipples; - _mode[FX_MODE_3DSphereMove] = &WS2812FX::mode_3DSphereMove; + _mode[FX_MODE_3DSphereMove] = &WS2812FX::mode_3DSphereMove; #ifdef WLEDSR_LARGE // _mode[FX_MODE_2DPOOLNOISE] = &WS2812FX::mode_2DPoolnoise; //code not in fx.cpp @@ -801,6 +811,12 @@ class WS2812FX { _mode[FX_MODE_2DJULIA] = &WS2812FX::mode_2DJulia; _mode[FX_MODE_2DGAMEOFLIFE] = &WS2812FX::mode_2Dgameoflife; + + _mode[FX_MODE_POPCORN_AR] = &WS2812FX::mode_popcorn_audio; + _mode[FX_MODE_MULTI_COMET_AR] = &WS2812FX::mode_multi_comet_audio; + _mode[FX_MODE_STARBURST_AR] = &WS2812FX::mode_starburst_audio; + _mode[FX_MODE_PALETTE_AR] = &WS2812FX::mode_palette_audio; + _mode[FX_MODE_FIREWORKS_AR] = &WS2812FX::mode_fireworks_audio; #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -880,6 +896,8 @@ class WS2812FX { gamma8_cal(uint8_t, float), get_random_wheel_index(uint8_t); + inline uint8_t getCurrSegmentId(void) { return _segment_index; } + inline uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 @@ -960,7 +978,9 @@ class WS2812FX { mode_running_random(void), mode_larson_scanner(void), mode_comet(void), + mode_fireworks_core(bool useAudio), // WLEDSR mode_fireworks(void), + mode_fireworks_audio(void), // WLEDSR mode_rain(void), mode_tetrix(void), mode_halloween(void), @@ -978,7 +998,9 @@ class WS2812FX { mode_tricolor_fade(void), mode_lightning(void), mode_icu(void), + mode_multi_comet_core(bool useAudio), // WLEDSR mode_multi_comet(void), + mode_multi_comet_audio(void), // WLEDSR mode_dual_larson_scanner(void), mode_random_chase(void), mode_oscillate(void), @@ -986,7 +1008,9 @@ class WS2812FX { mode_pride_2015(void), mode_bpm(void), mode_juggle(void), + mode_palette_core(bool useAudio), // WLEDSR mode_palette(void), + mode_palette_audio(void), // WLEDSR mode_colorwaves(void), mode_fillnoise8(void), mode_noise16_1(void), @@ -1008,13 +1032,17 @@ class WS2812FX { mode_spots_fade(void), mode_glitter(void), mode_candle(void), + mode_starburst_core(bool useAudio), // WLEDSR mode_starburst(void), + mode_starburst_audio(void), // WLEDSR mode_exploding_fireworks(void), mode_bouncing_balls(void), mode_sinelon(void), mode_sinelon_dual(void), mode_sinelon_rainbow(void), + mode_popcorn_core(bool useAudio), // WLEDSR mode_popcorn(void), + mode_popcorn_audio(void), // WLEDSR mode_drip(void), mode_plasma(void), mode_percent(void), @@ -1138,7 +1166,9 @@ class WS2812FX { mode_2DDrift(void), mode_2DColoredBursts(void), mode_2DJulia(void), - mode_customEffect(void), //WLEDSR Custom Effects +#ifdef USERMOD_ARTIFX + mode_ARTIFX(void), //WLEDMM ARTI-FX +#endif mode_3DRipples(void), mode_3DSphereMove(void); // mode_2DPoolnoise(void), @@ -1154,30 +1184,41 @@ class WS2812FX { bool _skipFirstMode; //private? not in AC (anymore) - //WLEDSR Custom Effects - float arti_external_function(uint8_t function, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull, float par4 = floatNull, float par5 = floatNull); - float arti_get_external_variable(uint8_t variable, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull); - void arti_set_external_variable(float value, uint8_t variable, float par1 = floatNull, float par2 = floatNull, float par3 = floatNull); + void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); + void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline + void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0); + void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of Audio Reactive fork (WLEDSR) // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + CRGBPalette16 currentPalette; + uint32_t _colors_t[3]; + uint16_t _virtualSegmentLength; + segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element + //WLEDSR: add f1,2,3 + // start, stop, offset, speed, intensity, custom1, custom2, custom3, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities + {0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, DEFAULT_Custom1, DEFAULT_Custom2, DEFAULT_Custom3, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0} + }; + uint8_t _segment_index = 0; + friend class Segment; + segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element + friend class Segment_runtime; private: uint32_t crgb_to_col(CRGB fastled); CRGB col_to_crgb(uint32_t); - CRGBPalette16 currentPalette; CRGBPalette16 targetPalette; - uint16_t _length, _virtualSegmentLength; + uint16_t _length; uint16_t _rand16seed; uint8_t _brightness; uint16_t _usedSegmentData = 0; uint16_t _transitionDur = 750; - uint8_t _targetFps = 42; - uint16_t _frametime = (1000/42); + uint8_t _targetFps = WLED_FPS; + uint16_t _frametime = FRAMETIME_FIXED; uint16_t _cumulativeFps = 2; bool @@ -1220,29 +1261,21 @@ class WS2812FX { load_gradient_palette(uint8_t), handle_palette(void); + CRGBPalette16 getAudioPalette(int pal); + uint16_t* customMappingTable = nullptr; uint16_t customMappingSize = 0; uint32_t _lastPaletteChange = 0; uint32_t _lastShow = 0; - uint32_t _colors_t[3]; uint8_t _bri_t; bool _no_rgb = false; - uint8_t _segment_index = 0; uint8_t _segment_index_palette_last = 99; uint8_t _mainSegment; - segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element - //WLEDSR: add f1,2,3 - // start, stop, offset, speed, intensity, custom1, custom2, custom3, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities - {0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, DEFAULT_Custom1, DEFAULT_Custom2, DEFAULT_Custom3, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0} - }; - segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element - friend class Segment_runtime; - ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element friend class ColorTransition; @@ -1413,7 +1446,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ " ♪ Pixelwave@!,Sensitivity=64;!,!;!", " ♪ Juggles@!,# of balls;,!;!", " ♪ Matripix@!,Brightness=64;,!;!", -" ♪ Gravimeter@Rate of fall,Sensitivity=128;,!;!", +" ♪ Gravimeter@Rate of fall,Sensitivity=130;,!;!", " ♪ Plasmoid@Phase=128,# of pixels=128;,!;!", " ♪ Puddles@Fade rate,Puddle size;!,!;!", " ♪ Midnoise@Fade rate,Maximum length=128;,!;!", @@ -1421,15 +1454,15 @@ const char JSON_mode_names[] PROGMEM = R"=====([ " ♫ Freqwave@Time delay,Sound effect,Low bin,High bin,Pre-amp;;", " ♫ Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;", " ♫ 2D GEQ@Bar speed,Ripple decay;,,Peak Color;!", -" ♫ Waterfall@!,Adjust color,,Select bin, Volume (minimum);!,!;!", +" ♫ Waterfall@!,Adjust color,,Select bin=14, Volume (minimum)=62;!,!;!", " ♫ Freqpixels@Fade rate,Starting colour and # of pixels;;", " ♫ Binmap@;!,!;!", " ♪ Noisefire@!,!;;", -" ♪ Puddlepeak@Fade rate,Puddle size,,Select bin,Volume (minimum);!,!;!", +" ♪ Puddlepeak@Fade rate,Puddle size,,Select bin=14,Volume (minimum)=96;!,!;!", " ♫ Noisemove@Speed of perlin movement,Fade rate;,!;!", "2D Noise@Speed,Scale;;!", "Perlin Move@!,# of pixels,fade rate;,!;!", -" ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin,Volume (minimum);!,!;!", +" ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin=14,Volume (minimum)=62;!,!;!", "2D FireNoise@X scale,Y scale;;", "2D Squared Swirl@,,,,Blur;,,;!", "2D Fire2012@Speed;;", @@ -1457,7 +1490,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "2D Tartan@X scale,Y scale;;!", "2D Polar Lights@Speed,X scale,Palette;;", " ♪ 2D Swirl@!,Sensitivity=64,Blur;,Bg Swirl;!", -"2D Lissajous@X frequency,Fadetime;;!", +"2D Lissajous@X frequency=64,Fadetime,,,Speed;;!", "2D Frizzles@X frequency,Y frequency;;!", "2D Plasma Ball@Speed;;!", "Flow Stripe@Hue speed,Effect speed;;", @@ -1468,9 +1501,14 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Wavesins@Speed,Brightness variation,Starting Color,Range of Colors,Color variation;;!", " ♫ Rocktaves@;,!;!", " ♫ 2D Akemi@Color speed,Dance ☑;Head palette,Arms & Legs,Eyes & Mouth;Face palette", -" ⚙️ Custom Effect@Speed,Intensity,Custom 1, Custom 2, Custom 3;!;!", +" ⚙️ ARTI-FX@Speed,Intensity,Custom 1, Custom 2, Custom 3;!;!", "3D Ripples@Speed=128,Interval=128;!;!", -"3D Sphere Move@Speed=128,Interval=128;!;!" +"3D Sphere Move@Speed=128,Interval=128;!;!", +" 🎉 audio Popcorn@Gravity=128,Intensity=200;!;!", +" 🔨 audio Comets@Speed=228,Intensity=240;!;!", +" 🔨 audio Fw Starburst@Speed=128,Intensity=128;!;!", +" 🔨 beat Palette@Speed=164;!;!", +" 🎉 audio Fireworks@Intensity=96;!;!" ])====="; //WLEDSR: second part (not SR specific, but in latest SR, not in AC (Pallettes added in WLEDSR from Retro Clown->END)) @@ -1482,7 +1520,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([ "Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura", "Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2","Retro Clown","Candy","Toxy Reaf","Fairy Reaf", "Semi Blue","Pink Candy","Red Reaf","Aqua Flash","Yelblu Hot","Lite Light","Red Flash","Blink Red","Red Shift","Red Tide", -"Candy2" +"Candy2","Audio Responsive Ratio","Audio Responsive Hue" ])====="; #endif diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 19e0d83e23..c520346c77 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -168,14 +168,14 @@ void WS2812FX::service() { _colors_t[c] = gamma32(_colors_t[c]); } handle_palette(); - //WLEDSR: swap width and height if rotated + //WLEDSR: swap width and height if rotated // softhack first check for stop >= start, to avoid underflow if (IS_ROTATED2D && stripOrMatrixPanel == 1) {//matrix - SEGMENT.height = SEGMENT.stopX - SEGMENT.startX + 1; - SEGMENT.width = SEGMENT.stopY - SEGMENT.startY + 1; + SEGMENT.height = (SEGMENT.stopX >= SEGMENT.startX) ? (SEGMENT.stopX - SEGMENT.startX + 1) : 0; + SEGMENT.width = (SEGMENT.stopY >= SEGMENT.startY) ? (SEGMENT.stopY - SEGMENT.startY + 1) : 0; } else { - SEGMENT.width = SEGMENT.stopX - SEGMENT.startX + 1; - SEGMENT.height = SEGMENT.stopY - SEGMENT.startY + 1; + SEGMENT.width = (SEGMENT.stopX >= SEGMENT.startX) ? (SEGMENT.stopX - SEGMENT.startX + 1) : 0; + SEGMENT.height = (SEGMENT.stopY >= SEGMENT.startY) ? (SEGMENT.stopY - SEGMENT.startY + 1) : 0; } if (_mode[SEGMENT.mode] != nullptr) delay = (this->*_mode[SEGMENT.mode])(); //effect function @@ -290,21 +290,23 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, byte r, byte g, byte b, byte w) i += _segments[segIdx].start; /* Set all the pixels in the group */ - for (uint16_t j = 0; j < SEGMENT.grouping; j++) { - uint16_t indexSet = logicalIndex + (IS_REVERSE ? -j : j); + for (uint_fast16_t j = 0; j < SEGMENT.grouping; j++) { + int indexSet = logicalIndex + (IS_REVERSE ? -j : j); if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { if (IS_MIRROR) { // set the corresponding mirrored pixel - uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1; + int indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1; /* offset/phase */ indexMir += SEGMENT.offset; if (indexMir >= SEGMENT.stop) indexMir -= len; + if (indexMir < SEGMENT.start) indexMir += len; // softhack007: wrap around on both sides if (indexMir >= _segments[segIdx].stop) indexMir -= len; if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir]; - busses.setPixelColor(logicalToPhysical(indexSet), col); + //busses.setPixelColor(logicalToPhysical(indexSet), col); // softhack007: wrong pixel position, and not needed here busses.setPixelColor(logicalToPhysical(indexMir), col); // ewowi20210624: logicalToPhysical: Maps logical led index to physical led index. } indexSet += _segments[segIdx].offset; // offset/phase + if ((SEGMENT.stop > 0) && (indexSet >= SEGMENT.stop)) indexSet -= len; // softhack007: wrap around when offset != 0 (stop == 0 means "segment invalid") if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; // This line is also on L292 busses.setPixelColor(logicalToPhysical(indexSet), col); @@ -443,8 +445,9 @@ uint8_t WS2812FX::getTargetFps() { } void WS2812FX::setTargetFps(uint8_t fps) { - if (fps > 0 && fps <= 120) _targetFps = fps; + if (fps > 0 && fps <= 250) _targetFps = fps; // WLEDSR accept up to 250 fps target _frametime = 1000 / _targetFps; + if (_frametime < 2) _frametime = 2; // WLEDSR } // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC @@ -464,6 +467,15 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) { if (m >= MODE_COUNT) m = MODE_COUNT - 1; + // WLEDSR: check that mode is valid + char lineBuffer[12] = { '\0' }; + extractModeName(m, JSON_mode_names, lineBuffer, 11); + if(strncmp_P("Reserved", lineBuffer, 8) == 0) { + DEBUG_PRINTF("setMode: invalid mode %d\n", m); + m = FX_MODE_RANDOM_COLOR; + } + // WLEDSR end + if (_segments[segid].mode != m) { _segment_runtimes[segid].markForReset(); @@ -1051,7 +1063,7 @@ uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint1 * Fills segment with color */ void WS2812FX::fill(uint32_t c) { - for(uint16_t i = 0; i < SEGLEN; i++) { + for(uint_fast16_t i = 0; i < SEGLEN; i++) { setPixelColor(i, c); } } @@ -1075,7 +1087,7 @@ void WS2812FX::fade2black(uint8_t rate) { mappedRate = mappedRate / 100; - for(uint16_t i = 0; i < SEGLEN; i++) { + for(uint_fast16_t i = 0; i < SEGLEN; i++) { color = getPixelColor(i); int w1 = W(color); int r1 = R(color); @@ -1104,7 +1116,7 @@ void WS2812FX::fade_out(uint8_t rate) { int g2 = G(color); int b2 = B(color); - for(uint16_t i = 0; i < SEGLEN; i++) { + for(uint_fast16_t i = 0; i < SEGLEN; i++) { color = getPixelColor(i); int w1 = W(color); int r1 = R(color); @@ -1134,7 +1146,7 @@ void WS2812FX::blur(uint8_t blur_amount) uint8_t keep = 255 - blur_amount; uint8_t seep = blur_amount >> 1; CRGB carryover = CRGB::Black; - for(uint16_t i = 0; i < SEGLEN; i++) + for(uint_fast16_t i = 0; i < SEGLEN; i++) { CRGB cur = col_to_crgb(getPixelColor(i)); CRGB part = cur; @@ -1239,7 +1251,7 @@ CRGB IRAM_ATTR WS2812FX::col_to_crgb(uint32_t color) void WS2812FX::load_gradient_palette(uint8_t index) { byte i = constrain(index, 0, GRADIENT_PALETTE_COUNT -1); - byte tcp[72]; //support gradient palettes with up to 18 entries + byte tcp[76] = {255}; //support gradient palettes with up to 18 entries // WLEDSR with safety margin memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[i])), 72); targetPalette.loadDynamicGradientPalette(tcp); } @@ -1326,6 +1338,10 @@ void WS2812FX::handle_palette(void) targetPalette = RainbowColors_p; break; case 12: //Rainbow stripe colors targetPalette = RainbowStripeColors_p; break; + case 71: //WLEDMM netmindz ar palette +1 + case 72: //WLEDMM netmindz ar palette +1 + targetPalette = getAudioPalette(paletteIndex); + break; default: //progmem palettes load_gradient_palette(paletteIndex -13); } @@ -1339,6 +1355,41 @@ void WS2812FX::handle_palette(void) } } +// WLEDMM netmindz ar palette +CRGBPalette16 WS2812FX::getAudioPalette(int pal) { + // https://forum.makerforums.info/t/hi-is-it-possible-to-define-a-gradient-palette-at-runtime-the-define-gradient-palette-uses-the/63339 + + uint8_t xyz[16]; // Needs to be 4 times however many colors are being used. + // 3 colors = 12, 4 colors = 16, etc. + + xyz[0] = 0; // anchor of first color - must be zero + xyz[1] = 0; + xyz[2] = 0; + xyz[3] = 0; + + CRGB rgb = getCRGBForBand(1, pal); + + xyz[4] = 1; // anchor of first color + xyz[5] = rgb.r; + xyz[6] = rgb.g; + xyz[7] = rgb.b; + + rgb = getCRGBForBand(128, pal); + xyz[8] = 128; + xyz[9] = rgb.r; + xyz[10] = rgb.g; + xyz[11] = rgb.b; + + rgb = getCRGBForBand(255, pal); + xyz[12] = 255; // anchor of last color - must be 255 + xyz[13] = rgb.r; + xyz[14] = rgb.g; + xyz[15] = rgb.b; + + return CRGBPalette16(xyz); +} + + /* * Gets a single color from the currently selected palette. @@ -1418,6 +1469,7 @@ void WS2812FX::deserializeMap(uint8_t n) { releaseJSONBufferLock(); } +#if !defined(WLED_USE_CIE_BRIGHTNESS_TABLE) //gamma 2.8 lookup table used for color correction byte gammaT[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1436,6 +1488,31 @@ byte gammaT[] = { 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, 215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 }; +#else +// experimental +// CIE 1931 lookup table (8bit->8bit) that was proposed during discussion of issue #2767 +// https://github.com/Aircoookie/WLED/issues/2767#issuecomment-1310961308 +// unfortunately NepixelsBu has its own internal table, that kills low brightness values similar to the original WLED table. +// see https://github.com/Makuna/NeoPixelBus/blob/master/src/internal/NeoGamma.h +static const byte gammaT[256] = { + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, + 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, + 25, 25, 26, 27, 27, 28, 28, 29, 30, 30, 31, 31, 32, 33, 33, 34, + 35, 35, 36, 37, 38, 38, 39, 40, 41, 41, 42, 43, 44, 44, 45, 46, + 47, 48, 49, 50, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, + 79, 81, 82, 83, 84, 85, 87, 88, 89, 91, 92, 93, 94, 96, 97, 99, + 100, 101, 103, 104, 106, 107, 109, 110, 111, 113, 115, 116, 118, 119, 121, + 122, 124, 126, 127, 129, 130, 132, 134, 135, 137, 139, 141, 142, 144, 146, + 148, 150, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 170, 172, 174, + 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 198, 200, 202, 204, 207, + 209, 211, 213, 216, 218, 220, 223, 225, 227, 230, 232, 235, 237, 240, 242, + 245, 247, 250, 252, 255 }; +#endif uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) { return (int)(pow((float)b / 255.0, gamma) * 255 + 0.5); @@ -1443,9 +1520,11 @@ uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) { void WS2812FX::calcGammaTable(float gamma) { +#if !defined(WLED_USE_CIE_BRIGHTNESS_TABLE) for (uint16_t i = 0; i < 256; i++) { gammaT[i] = gamma8_cal(i, gamma); } +#endif } uint8_t WS2812FX::gamma8(uint8_t b) diff --git a/wled00/audio_reactive.h b/wled00/audio_reactive.h index 0f0892cd85..489d9d8fa9 100644 --- a/wled00/audio_reactive.h +++ b/wled00/audio_reactive.h @@ -21,6 +21,7 @@ static AudioSource *audioSource; static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks. +static unsigned useInputFilter = 0; // if >0 , enables a bandpass filter 80Hz-8Khz to remove noise. Applies before FFT. // ALL AUDIO INPUT PINS DEFINED IN wled.h AND CONFIGURABLE VIA UI @@ -40,9 +41,9 @@ static volatile bool disableSoundProcessing = false; // if true, sound proc #endif // legacy support -#if defined(SR_DEBUG) && !defined(MIC_LOGGER) && !defined(NO_MIC_LOGGER) -#define MIC_LOGGER -#endif +//#if defined(SR_DEBUG) && !defined(MIC_LOGGER) && !defined(NO_MIC_LOGGER) +//#define MIC_LOGGER +//#endif // hackers corner @@ -62,8 +63,8 @@ constexpr int SAMPLE_RATE = 10240; // Base sample rate in Hz - standa #define UDP_SYNC_HEADER "00001" #define UDP_SYNC_HEADER_V2 "00002" -uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger -uint8_t binNum = 8; // Used to select the bin for FFT based beat detection. +uint8_t maxVol = 31; // (was 10) Reasonable value for constant volume for 'peak detector', as it won't always trigger +uint8_t binNum = 14; // (was 8) Used to select the bin for FFT based beat detection. 14 = 280Hz // @@ -110,8 +111,8 @@ double sampleMax = 0; // Max sample over a few seconds uint8_t myVals[32]; // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low. -bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag -bool udpSamplePeak = 0; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData +uint8_t samplePeak = 0; // Flag for peak. 0 = no peak, 1 = possible peak (often), 2=sure peak (every 1-2seconds) +uint8_t udpSamplePeak = 0; // Set at the same tiem as samplePeak, but reset by transmitAudioData constexpr int delayMs = 10; // I don't want to sample too often and overload WLED static int micIn = 0.0; // Current sample starts with negative values and large values, which is why it's 16 bit signed int sampleRaw; // Current sample. Must only be updated ONCE!!! @@ -163,6 +164,12 @@ static int linearNoise[16] = { 34, 28, 26, 25, 20, 12, 9, 6, 4, 4, 3, 2, 2, 2, 2 // Table of multiplication factors so that we can even out the frequency response. static float fftResultPink[16] = {1.70,1.71,1.73,1.78,1.68,1.56,1.55,1.63,1.79,1.62,1.80,2.06,2.47,3.35,6.83,9.55}; +// shared vars for debugging +#ifdef MIC_LOGGER +static volatile float micReal_min = 0.0f; // MicIn data min from last batch of samples +static volatile float micReal_avg = 0.0f; // MicIn data average (from last batch of samples) +static volatile float micReal_max = 0.0f; // MicIn data max from last batch of samples +#endif // default "V1" SR 0.13.x audiosync struct - 83 Bytes struct audioSyncPacket { @@ -189,7 +196,7 @@ struct audioSyncPacket_v2 { float FFT_MajorPeak; // 04 Bytes }; -double mapf(double x, double in_min, double in_max, double out_min, double out_max); +#define UDPSOUND_MAX_PACKET 96 // max packet size for audiosync, with a bit of "headroom" bool isValidUdpSyncVersion(char header[6]) { if (strncmp(header, UDP_SYNC_HEADER, 5) == 0) { @@ -210,6 +217,8 @@ bool isValidUdpSyncVersion2(char header[6]) { /* get current max sample ("published" by the I2S and FFT thread) and perform some sound processing */ void getSample() { const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function + static unsigned long lastSoundTime = 0; // for delaying noise gate + constexpr long MinTimeSilence = 1600; // 1600ms "grace time" before closing noise gate - to avoid chattering #ifdef WLED_DISABLE_SOUND micIn = inoise8(millis(), millis()); // Simulated analog read @@ -220,7 +229,8 @@ void getSample() { // remove remaining DC offset from sound signal micLev = ((micLev * 8191.0) + micDataReal) / 8192.0; // takes a few seconds to "catch up" with the Mic Input - if(micIn < micLev) micLev = ((micLev * 31.0) + micDataReal) / 32.0; // align MicLev to lowest input signal + //if(micIn < micLev) micLev = ((micLev * 31.0) + micDataReal) / 32.0; // align MicLev to lowest input signal + if(micDataReal < (micLev-1.2)) micLev = ((micLev * 31.0) + micDataReal) / 32.0; // align with lowest input, but allow some "overlap" to stabilize the filter micIn -= micLev; // Let's center it to 0 now // Using an exponential filter to smooth out the signal. We'll add controls for this in a future release. @@ -228,8 +238,13 @@ void getSample() { expAdjF = weighting * micInNoDC + ((1.0-weighting) * expAdjF); expAdjF = fabsf(expAdjF); // Now (!) take the absolute value - expAdjF = (expAdjF <= soundSquelch) ? 0: expAdjF; // simple noise gate - if ((soundSquelch == 0) && (expAdjF < 0.25f)) expAdjF = 0; + //expAdjF = (expAdjF <= soundSquelch) ? 0: expAdjF; // super simple noise gate + //if ((soundSquelch == 0) && (expAdjF < 0.25f)) expAdjF = 0; + if ((expAdjF <= soundSquelch) || ((soundSquelch == 0) && (expAdjF < 0.25f))) { // noise gate with "closing delay" + if ((millis() - lastSoundTime) > MinTimeSilence) expAdjF = 0.0; + } else { + lastSoundTime = millis(); + } tmpSample = expAdjF; micIn = abs(micIn); // And get the absolute value of each sample @@ -243,10 +258,11 @@ void getSample() { // keep "peak" sample, but decay value if current sample is below peak if ((sampleMax < sampleReal) && (sampleReal > 0.5)) { sampleMax = sampleMax + 0.5 * (sampleReal - sampleMax); // new peak - with some filtering - if (((maxVol < 6) || (binNum < 9)) && (millis() - timeOfPeak > 80)) { // another simple way to detect samplePeak - samplePeak = 1; + //if (((maxVol < 6) || (binNum < 9)) && (millis() - timeOfPeak > 80) && (sampleAvg > 1)) { // another simple way to detect samplePeak + if ((millis() - timeOfPeak > 80) && (sampleAvg > 1)) { // no iffs-n-butts + samplePeak = 2; timeOfPeak = millis(); - udpSamplePeak = 1; + udpSamplePeak = 2; userVar1 = samplePeak; } } else { @@ -261,7 +277,7 @@ void getSample() { sampleAvg = fabsf(sampleAvg); // make sure we have a positive value // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC - uint16_t MinShowDelay = strip.getMinShowDelay(); + uint16_t MinShowDelay = max((uint16_t)33,strip.getMinShowDelay()); if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. samplePeak = 0; @@ -270,12 +286,12 @@ void getSample() { if (userVar1 == 0) samplePeak = 0; // Poor man's beat detection by seeing if sample > Average + some value. - if ((maxVol > 1) && (binNum > 4) && (fftBin[binNum] > maxVol) && (millis() - timeOfPeak > 100)) { // This goes through ALL of the 255 bins - but ignores stupid settings + if ((maxVol > 1) && (binNum > 6) && (fftBin[binNum] > maxVol) && (millis() - timeOfPeak > 100) && (sampleAvg > 1)) { // This goes through ALL of the 255 bins - but ignores stupid settings // if (sample > (sampleAvg + maxVol) && millis() > (peakTime + 200)) { // Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync. - samplePeak = 1; - timeOfPeak = millis(); - udpSamplePeak = 1; + samplePeak = max(uint8_t(1), samplePeak); // ignore this peak if we already have an active "good peak" + if (samplePeak == 1) timeOfPeak = millis(); + udpSamplePeak = max(uint8_t(1), udpSamplePeak); userVar1 = samplePeak; } } // getSample() @@ -428,11 +444,15 @@ void limitSampleDynamics(void) { // Begin FFT Code // //////////////////// -// using latest AruinoFFT lib, because it supportd float and its much faster! +// using latest AruinoFFT lib, because it supports float and its much faster! // lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2 -#define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc), and an a few other speedups -#define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt -//#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 50% on ESP32 (as alternative to FFT_SQRT_APPROXIMATION) + +// The following optimizations seem to be optimal on ESP32 (~1.5ms per FFT run) +// #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc), and an a few other speedups - WLEDMM not faster on ESP32 +// #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - WLEDMM slower on ESP32 +#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32 (as alternative to FFT_SQRT_APPROXIMATION) +#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 + #include "arduinoFFT.h" void transmitAudioData() { @@ -488,7 +508,7 @@ static void extract_v2_packet(int packetSize, uint8_t *fftBuff) multAgc = 1.0f; // auto-reset sample peak. Need to do it here, because getSample() is not running - uint16_t MinShowDelay = strip.getMinShowDelay(); + uint16_t MinShowDelay = max((uint16_t)33, strip.getMinShowDelay()); if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. samplePeak = 0; udpSamplePeak = 0; @@ -496,9 +516,9 @@ static void extract_v2_packet(int packetSize, uint8_t *fftBuff) if (userVar1 == 0) samplePeak = 0; // Only change samplePeak IF it's currently false. // If it's true already, then the animation still needs to respond. - if (!samplePeak) { + if (samplePeak == 0) { samplePeak = receivedPacket.samplePeak; - if (samplePeak) timeOfPeak = millis(); + if (samplePeak > 0) timeOfPeak = millis(); udpSamplePeak = samplePeak; userVar1 = samplePeak; } @@ -532,6 +552,104 @@ float fftAdd( int from, int to) { return result; } + +// Bandpass filter for PDM microphones +static void runMicFilter(uint16_t numSamples, float *sampleBuffer) { // pre-filtering of raw samples (band-pass) + // band pass filter - can reduce noise floor by a factor of 50 + // downside: frequencies below 60Hz will be ignored + + // low frequency cutoff parameter - see https://dsp.stackexchange.com/questions/40462/exponential-moving-average-cut-off-frequency + //constexpr float alpha = 0.062f; // 100Hz + constexpr float alpha = 0.04883f; // 80Hz + //constexpr float alpha = 0.03662f; // 60Hz + //constexpr float alpha = 0.0225f; // 40Hz + // high frequency cutoff parameter + //constexpr float beta1 = 0.75; // 5Khz + //constexpr float beta1 = 0.82; // 7Khz + constexpr float beta1 = 0.8285; // 8Khz + //constexpr float beta1 = 0.85; // 10Khz + + constexpr float beta2 = (1.0f - beta1) / 2.0; + static float last_vals[2] = { 0.0f }; // FIR high freq cutoff filter + static float lowfilt = 0.0f; // IIR low frequency cutoff filter + + for (int i=0; i < numSamples; i++) { + // FIR lowpass, to remove high frequency noise + float highFilteredSample; + if (i < (numSamples-1)) + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*sampleBuffer[i+1]; // smooth out spikes + else + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // spcial handling for last sample in array + last_vals[1] = last_vals[0]; + last_vals[0] = sampleBuffer[i]; + sampleBuffer[i] = highFilteredSample; + // IIR highpass, to remove low frequency noise + lowfilt += alpha * (sampleBuffer[i] - lowfilt); + sampleBuffer[i] = sampleBuffer[i] - lowfilt; + } +} + +// sample smoothing, by using a sliding average FIR highpass filter (first half of MicFilter from above) +static void runMicSmoothing(uint16_t numSamples, float *sampleBuffer) { + constexpr float beta1 = 0.8285; // ~8Khz + constexpr float beta2 = (1.0f - beta1) / 2.0; // note to self: better use biquad ? + static float last_vals[2] = { 0.0f }; // FIR filter buffer + + for (int i=0; i < numSamples; i++) { + float highFilteredSample; + if (i < (numSamples-1)) + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*sampleBuffer[i+1]; // smooth out spikes + else + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // spcial handling for last sample in array + last_vals[1] = last_vals[0]; + last_vals[0] = sampleBuffer[i]; + sampleBuffer[i] = highFilteredSample; + } +} + +// a variation of above, with higher cut-off frequency +static void runMicSmoothing_v2(uint16_t numSamples, float *sampleBuffer) { + constexpr float beta1 = 0.85; // ~10Khz + constexpr float beta2 = (1.0f - beta1) / 2.0; // note to self: better use biquad ? + static float last_vals[2] = { 0.0f }; // FIR filter buffer + + for (int i=0; i < numSamples; i++) { + float highFilteredSample; + if (i < (numSamples-1)) + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*sampleBuffer[i+1]; // smooth out spikes + else + highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // spcial handling for last sample in array + last_vals[1] = last_vals[0]; + last_vals[0] = sampleBuffer[i]; + sampleBuffer[i] = highFilteredSample; + } +} + +// High-Pass filter, 6db per octave +static void runHighFilter6db(const float filter, uint16_t numSamples, float *sampleBuffer) { + static float lowfilt = 0.0f; // IIR low frequency cutoff filter + for (int i=0; i < numSamples; i++) { + lowfilt += filter * (sampleBuffer[i] - lowfilt); // lowpass + sampleBuffer[i] = sampleBuffer[i] - lowfilt; // lowpass --> highpass + } +} + +// High-Pass filter, 12db per octave +static void runHighFilter12db(const float filter, uint16_t numSamples, float *sampleBuffer) { + static float lowfilt1 = 0.0f; // IIR low frequency cutoff filter - first pass = 6db + static float lowfilt2 = 0.0f; // IIR low frequency cutoff filter - second pass = 12db + for (int i=0; i < numSamples; i++) { + lowfilt1 += filter * (sampleBuffer[i] - lowfilt1); // first lowpass 6db + // lowfilt2 += filter * (lowfilt1 - lowfilt2); // second lowpass +6db + // sampleBuffer[i] = sampleBuffer[i] - lowfilt2; // lowpass --> highpass + // implementation below has better results, compared to the code above + float pass1Out = sampleBuffer[i] - lowfilt1; // output from first stage (lowpass --> highpass) + lowfilt2 += filter * (pass1Out - lowfilt2); // second lowpass +6db + sampleBuffer[i] = pass1Out - lowfilt2; // lowpass --> highpass + } +} + + // FFT main code void FFTcode( void * parameter) { DEBUG_PRINT("FFT running on core: "); DEBUG_PRINTLN(xPortGetCoreID()); @@ -564,7 +682,45 @@ void FFTcode( void * parameter) { //micDataSm = (uint16_t)vReal[samples - 1]; // will do a this a bit later // micDataSm = ((micData * 3) + micData)/4; + #ifdef MIC_LOGGER + float datMin = 0.0f; + float datMax = 0.0f; + double datAvg = 0.0f; + for (int i=0; i < samplesFFT; i++) { + if (i==0) { + datMin = datMax = vReal[i]; + } else { + if (datMin > vReal[i]) datMin = vReal[i]; + if (datMax < vReal[i]) datMax = vReal[i]; + } + datAvg += vReal[i]; + } + #endif + // input filters applied before FFT + if (useInputFilter > 0) { + // filter parameter - we use constexpr as it does not need any RAM (evaluted at compile time) + // value = 1 - exp(-2*PI * FFilter / FSample); // FFilter: filter cutoff frequency; FSample: sampling frequency + constexpr float filter30Hz = 0.01823938f; // rumbling = 10-25hz + constexpr float filter70Hz = 0.04204211f; // mains hum = 50-60hz + constexpr float filter120Hz = 0.07098564f; // bad microphones deliver noise below 120Hz + constexpr float filter185Hz = 0.10730882f; // environmental noise is strongest below 180hz: wind, engine noise, ... + switch(useInputFilter) { + case 1: runMicFilter(samplesFFT, vReal); break; // PDM microphone bandpass + case 2: runHighFilter12db(filter30Hz, samplesFFT, vReal); break; // rejects rumbling noise + case 3: runMicSmoothing_v2(samplesFFT, vReal); // slightly reduce high frequency noise and artefacts + runHighFilter12db(filter70Hz, samplesFFT, vReal); // rejects rumbling + mains hum + break; + case 4: runMicSmoothing_v2(samplesFFT, vReal); // slightly reduce high frequency noise and artefacts + runHighFilter6db(filter120Hz, samplesFFT, vReal); // rejects everything below 110Hz + break; + case 5: runMicSmoothing(samplesFFT, vReal); // reduce high frequency noise and artefacts + runHighFilter6db(filter185Hz, samplesFFT, vReal); // reject low frequency noise + break; + } + } + + // find highest sample in the batch const int halfSamplesFFT = samplesFFT / 2; // samplesFFT divided by 2 float maxSample1 = 0.0; // max sample from first half of FFT batch float maxSample2 = 0.0; // max sample from second half of FFT batch @@ -585,6 +741,11 @@ void FFTcode( void * parameter) { // release first sample to volume reactive effects micDataSm = (uint16_t)maxSample1; micDataReal = maxSample1; + #ifdef MIC_LOGGER + micReal_min = datMin; + micReal_max = datMax; + micReal_avg = datAvg / samplesFFT; + #endif FFT.dcRemoval(); // remove DC offset //FFT.windowing(FFTWindow::Flat_top, FFTDirection::Forward); // Weigh data using "Flat Top" window - better amplitude accuracy @@ -689,20 +850,22 @@ void FFTcode( void * parameter) { void logAudio() { #ifdef MIC_LOGGER // Debugging functions for audio input and sound processing. Comment out the values you want to see - - Serial.print("micReal:"); Serial.print(micDataReal); Serial.print("\t"); + Serial.print("micMin:"); Serial.print(0.5f * micReal_min); Serial.print("\t"); + Serial.print("micMax:"); Serial.print(0.5f * micReal_max); Serial.print("\t"); + Serial.print("micReal:"); Serial.print(micDataReal + 256.0f); Serial.print("\t"); //Serial.print("micData:"); Serial.print(micData); Serial.print("\t"); //Serial.print("micDataSm:"); Serial.print(micDataSm); Serial.print("\t"); //Serial.print("micIn:"); Serial.print(micIn); Serial.print("\t"); - //Serial.print("micLev:"); Serial.print(micLev); Serial.print("\t"); + //Serial.print("micLev:"); Serial.print(micLev + 256.0f); Serial.print("\t"); //Serial.print("sampleReal:"); Serial.print(sampleReal); Serial.print("\t"); //Serial.print("sample:"); Serial.print(sample); Serial.print("\t"); //Serial.print("sampleAvg:"); Serial.print(sampleAvg); Serial.print("\t"); //Serial.print("sampleMax:"); Serial.print(sampleMax); Serial.print("\t"); //Serial.print("samplePeak:"); Serial.print((samplePeak!=0) ? 128:0); Serial.print("\t"); //Serial.print("multAgc:"); Serial.print(multAgc, 4); Serial.print("\t"); - Serial.print("sampleAgc:"); Serial.print(sampleAgc); Serial.print("\t"); + Serial.print("sampleAgc:"); Serial.print(sampleAgc + 256.0f); Serial.print("\t"); Serial.println(" "); + Serial.flush(); #endif diff --git a/wled00/audio_source.h b/wled00/audio_source.h index dbb2dc45e8..e500702ca8 100644 --- a/wled00/audio_source.h +++ b/wled00/audio_source.h @@ -51,16 +51,11 @@ #define I2S_MIC_CHANNEL_TEXT "left channel only." #endif -#ifndef MCLK_PIN - int mclkPin = 0; -#else - int mclkPin = MLCK_PIN; -#endif #ifndef ES7243_ADDR - int addr_ES7243 = 0x13; + static int addr_ES7243 = 0x13; #else - int addr_ES7243 = ES7243_ADDR; + static int addr_ES7243 = ES7243_ADDR; #endif #ifndef ES7243_SDAPIN @@ -70,9 +65,9 @@ #endif #ifndef ES7243_SDAPIN - int pin_ES7243_SCL = 23; + static int pin_ES7243_SCL = 23; #else - int pin_ES7243_SCL = ES7243_SCLPIN; + static int pin_ES7243_SCL = ES7243_SCLPIN; #endif /* Interface class @@ -114,8 +109,11 @@ class AudioSource { protected: // Private constructor, to make sure it is not callable except from derived classes - AudioSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : _sampleRate(sampleRate), _blockSize(blockSize), _sampleNoDCOffset(0), _dcOffset(0.0f), _shift(lshift), _mask(mask), - _initialized(false), _myADCchannel(0x0F), _lastADCsample(0), _broken_samples_counter(0) {}; + AudioSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale) : + _sampleRate(sampleRate), _blockSize(blockSize), _sampleNoDCOffset(0), _dcOffset(0.0f), + _shift(lshift), _mask(mask), _sampleScale(sampleScale), + _initialized(false), _myADCchannel(0x0F), _lastADCsample(0), _broken_samples_counter(0) + {}; int _sampleRate; /* Microphone sampling rate (from uint16_t to int to suppress warning)*/ int _blockSize; /* I2S block size */ @@ -123,6 +121,7 @@ class AudioSource { float _dcOffset; /* Rolling average DC offset */ int16_t _shift; /* Shift obtained samples to the right (positive) or left(negative) by this amount */ uint32_t _mask; /* Bitmask for sample data after shifting. Bitmask 0X0FFF means that we need to convert 12bit ADC samples from unsigned to signed*/ + float _sampleScale; // pre-scaling factor for I2S samples bool _initialized; /* Gets set to true if initialization is successful */ int8_t _myADCchannel; /* current ADC channel, in case of analog input. 0x0F if undefined */ I2S_datatype _lastADCsample; /* last sample from ADC */ @@ -135,8 +134,8 @@ class AudioSource { */ class I2SSource : public AudioSource { public: - I2SSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - AudioSource(sampleRate, blockSize, lshift, mask) { + I2SSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + AudioSource(sampleRate, blockSize, lshift, mask, sampleScale) { _config = { .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = _sampleRate, // "narrowing conversion" warning can be ignored here - our _sampleRate is never bigger that INT32_MAX @@ -153,6 +152,9 @@ class I2SSource : public AudioSource { }; _pinConfig = { + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) + .mck_io_num = I2S_PIN_NO_CHANGE, // needed, otherwise i2s_set_pin() will fail in IDF >=4.4.x + #endif .bck_io_num = i2sckPin, .ws_io_num = i2swsPin, .data_out_num = I2S_PIN_NO_CHANGE, @@ -166,25 +168,33 @@ class I2SSource : public AudioSource { virtual void initialize() { if (!pinManager.allocatePin(i2swsPin, true, PinOwner::DigitalMic) || - !pinManager.allocatePin(i2ssdPin, false, PinOwner::DigitalMic)) { + !pinManager.allocatePin(i2ssdPin, false, PinOwner::DigitalMic) || + (i2ssdPin < 0) || (i2swsPin < 0)) { + if (serialTxAvaileable) Serial.printf("Failed to set I2S GPIO pins: SD=%d WS=%d \n", i2ssdPin, i2swsPin); return; } // i2ssckPin needs special treatment, since it might be unused on PDM mics if (i2sckPin != -1) { - if (!pinManager.allocatePin(i2sckPin, true, PinOwner::DigitalMic)) + if (!pinManager.allocatePin(i2sckPin, true, PinOwner::DigitalMic)) { + if (serialTxAvaileable) Serial.printf("Failed to allocate I2S GPIO pin: SCK=%d \n", i2sckPin); return; + } } + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) + if (ESP.getChipRevision() == 0) _config.use_apll = false; // APLL is broken on ESP32 revision 0, so we disable it on rev0 chips + #endif + esp_err_t err = i2s_driver_install(I2S_NUM_0, &_config, 0, nullptr); if (err != ESP_OK) { - Serial.printf("Failed to install i2s driver: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to install i2s driver: %d\n", err); return; } err = i2s_set_pin(I2S_NUM_0, &_pinConfig); if (err != ESP_OK) { - Serial.printf("Failed to set i2s pin config: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to set i2s pin config: %d\n", err); return; } @@ -196,7 +206,7 @@ class I2SSource : public AudioSource { _initialized = false; esp_err_t err = i2s_driver_uninstall(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to uninstall i2s driver: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to uninstall i2s driver: %d\n", err); return; } } @@ -219,14 +229,14 @@ class I2SSource : public AudioSource { // get fresh samples err = i2s_read(I2S_NUM_0, (void *)newSamples, sizeof(newSamples), &bytes_read, portMAX_DELAY); - if ((err != ESP_OK)){ - Serial.printf("Failed to get samples: %d\n", err); + if ((err != ESP_OK)) { + if (serialTxAvaileable) Serial.printf("Failed to get samples: %d\n", err); return; } // For correct operation, we need to read exactly sizeof(samples) bytes from i2s if(bytes_read != sizeof(newSamples)) { - Serial.printf("Failed to get enough samples: wanted: %d read: %d\n", sizeof(newSamples), bytes_read); + if (serialTxAvaileable) Serial.printf("Failed to get enough samples: wanted: %d read: %d\n", sizeof(newSamples), bytes_read); return; } @@ -238,7 +248,7 @@ class I2SSource : public AudioSource { I2S_datatype sampleNoFilter = decodeADCsample(rawData); if (_broken_samples_counter >= num_samples-1) { // kill-switch: ADC sample correction off when all samples in a batch were "broken" _myADCchannel = 0x0F; - Serial.println("AS: too many broken audio samples from ADC - sample correction switched off."); + if (serialTxAvaileable) Serial.println("AS: too many broken audio samples from ADC - sample correction switched off."); } newSamples[i] = (3 * sampleNoFilter + _lastADCsample) / 4; // apply low-pass filter (2-tap FIR) @@ -264,7 +274,8 @@ class I2SSource : public AudioSource { currSample = (float) newSamples[i]; #endif } - buffer[i] = currSample; + buffer[i] = currSample; // store sample + buffer[i] *= _sampleScale; // scale sample _dcOffset = ((_dcOffset * 31) + currSample) / 32; } @@ -315,13 +326,22 @@ class I2SSource : public AudioSource { */ class I2SSourceWithMasterClock : public I2SSource { public: - I2SSourceWithMasterClock(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - I2SSource(sampleRate, blockSize, lshift, mask) { + I2SSourceWithMasterClock(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + I2SSource(sampleRate, blockSize, lshift, mask, sampleScale) { }; virtual void initialize() { // Reserve the master clock pin if(!pinManager.allocatePin(mclkPin, true, PinOwner::DigitalMic)) { + if (serialTxAvaileable) Serial.printf("Failed to allocate I2S GPIO pin: MCLK=%d \n", mclkPin); + return; + } + if ((mclkPin != GPIO_NUM_0) && (mclkPin != GPIO_NUM_1) && (mclkPin != GPIO_NUM_3)) { + if (serialTxAvaileable) Serial.printf("Failed to set gpio %d as i2s MCLK pin. Only GPIO0, GPIO1 or GPIO3 are possible on ESP32\n", mclkPin); + return; + } + if (i2sckPin < 0) { + if (serialTxAvaileable) Serial.printf("Failed to set gpio %d as i2s SCK pin.\n", i2sckPin); return; } _routeMclk(); @@ -368,7 +388,8 @@ class ES7243 : public I2SSourceWithMasterClock { Wire.beginTransmission(addr_ES7243); Wire.write((uint8_t)reg); Wire.write((uint8_t)val); - Wire.endTransmission(); + uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK + if ((i2cErr != 0) && serialTxAvaileable) Serial.printf("ES7243: I2C write failed with error=%d (reg 0x%X, val 0x%X).\n", i2cErr, reg, val); } void _es7243InitAdc() { @@ -383,14 +404,19 @@ class ES7243 : public I2SSourceWithMasterClock { public: - ES7243(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - I2SSourceWithMasterClock(sampleRate, blockSize, lshift, mask) { + ES7243(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + I2SSourceWithMasterClock(sampleRate, blockSize, lshift, mask, sampleScale) { _config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; }; void initialize() { + if ((pin_ES7243_SDA < 0) || (pin_ES7243_SCL < 0)) { + if (serialTxAvaileable) Serial.printf("ES7243: invalid i2c GPIO pins: SDA=%d SCL=%d \n", pin_ES7243_SDA, pin_ES7243_SCL); + return; + } // Reserve SDA and SCL pins of the I2C interface if (!pinManager.allocatePin(pin_ES7243_SDA, true, PinOwner::DigitalMic) || !pinManager.allocatePin(pin_ES7243_SCL, true, PinOwner::DigitalMic)) { + if (serialTxAvaileable) Serial.printf("ES7243: failed to allocate i2c GPIO pins: SDA=%d SCL=%d \n", pin_ES7243_SDA, pin_ES7243_SCL); return; } @@ -414,8 +440,8 @@ class ES7243 : public I2SSourceWithMasterClock { */ class I2SAdcSource : public I2SSource { public: - I2SAdcSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - I2SSource(sampleRate, blockSize, lshift, mask){ + I2SAdcSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + I2SSource(sampleRate, blockSize, lshift, mask, sampleScale){ _config = { .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .sample_rate = _sampleRate, // "narrowing conversion" warning can be ignored here - our _sampleRate is never bigger that INT32_MAX @@ -441,24 +467,27 @@ class I2SAdcSource : public I2SSource { for (int b=0; b= 0) && (buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && (digitalPinToAnalogChannel(btnPin[b]) < 10)) { if ((btnPin[b] >= 0) && (buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && (digitalPinToAnalogChannel(btnPin[b]) >= 0)) { + if (serialTxAvaileable) { Serial.println("AS: Analog Microphone does not work reliably when analog buttons are configured on ADC1."); Serial.printf( " Button %d GPIO %d\n", b, btnPin[b]); Serial.println(" To recover, please disable any analog button in LED preferences, then restart your device."); Serial.flush(); + } #ifdef I2S_GRAB_ADC1_COMPLETELY - Serial.println("AS: Analog Microphone initialization aborted. Cannot use ADC1 exclusively"); + if (serialTxAvaileable) Serial.println("AS: Analog Microphone initialization aborted. Cannot use ADC1 exclusively"); return; #endif } } if(!pinManager.allocatePin(audioPin, false, PinOwner::AnalogMic)) { + if (serialTxAvaileable) Serial.printf("AS: failed to allocate GPIO pin %d.\n", audioPin); return; } // Determine Analog channel. Only Channels on ADC1 are supported int8_t channel = digitalPinToAnalogChannel(audioPin); if ((channel < 0) || (channel > 9)) { // channel == -1 means "not an ADC pin" - Serial.printf("Incompatible GPIO used for audio in: %d\n", audioPin); + if (serialTxAvaileable) Serial.printf("Incompatible GPIO used for audio in: %d\n", audioPin); return; } else { adc_gpio_init(ADC_UNIT_1, adc_channel_t(channel)); @@ -469,7 +498,7 @@ class I2SAdcSource : public I2SSource { // Install Driver esp_err_t err = i2s_driver_install(I2S_NUM_0, &_config, 0, nullptr); if (err != ESP_OK) { - Serial.printf("Failed to install i2s driver: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to install i2s driver: %d\n", err); return; } @@ -478,7 +507,7 @@ class I2SAdcSource : public I2SSource { // Enable I2S mode of ADC err = i2s_set_adc_mode(ADC_UNIT_1, adc1_channel_t(channel)); if (err != ESP_OK) { - Serial.printf("Failed to set i2s adc mode: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to set i2s adc mode: %d\n", err); return; } @@ -491,14 +520,14 @@ class I2SAdcSource : public I2SSource { // fingers crossed err = i2s_adc_enable(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to enable i2s adc: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to enable i2s adc: %d\n", err); //return; } #else //err = i2s_adc_disable(I2S_NUM_0); // seems that disable without previous enable causes a crash/bootloop on some boards //err = i2s_stop(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to initially disable i2s adc: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to initially disable i2s adc: %d\n", err); } #endif _initialized = true; @@ -514,7 +543,7 @@ class I2SAdcSource : public I2SSource { //esp_err_t err = i2s_start(I2S_NUM_0); esp_err_t err = i2s_adc_enable(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to enable i2s adc: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to enable i2s adc: %d\n", err); return; } #endif @@ -524,7 +553,7 @@ class I2SAdcSource : public I2SSource { err = i2s_adc_disable(I2S_NUM_0); //err = i2s_stop(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to disable i2s adc: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to disable i2s adc: %d\n", err); return; } #endif @@ -541,7 +570,7 @@ class I2SAdcSource : public I2SSource { // fingers crossed err = i2s_adc_disable(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to disable i2s adc: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to disable i2s adc: %d\n", err); //return; } #endif @@ -549,7 +578,7 @@ class I2SAdcSource : public I2SSource { i2s_stop(I2S_NUM_0); err = i2s_driver_uninstall(I2S_NUM_0); if (err != ESP_OK) { - Serial.printf("Failed to uninstall i2s driver: %d\n", err); + if (serialTxAvaileable) Serial.printf("Failed to uninstall i2s driver: %d\n", err); return; } } @@ -565,8 +594,8 @@ class I2SAdcSource : public I2SSource { class SPH0654 : public I2SSource { public: - SPH0654(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - I2SSource(sampleRate, blockSize, lshift, mask){} + SPH0654(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + I2SSource(sampleRate, blockSize, lshift, mask, sampleScale){} void initialize() { I2SSource::initialize(); @@ -584,12 +613,16 @@ class SPH0654 : public I2SSource { class I2SPdmSource : public I2SSource { public: - I2SPdmSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask) : - I2SSource(sampleRate, blockSize, lshift, mask) { + I2SPdmSource(int sampleRate, int blockSize, int16_t lshift, uint32_t mask, float sampleScale = 1.0f) : + I2SSource(sampleRate, blockSize, lshift, mask, sampleScale) { _config.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM); // Change mode to pdm + _config.use_apll = 1; _pinConfig = { + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) + .mck_io_num = I2S_PIN_NO_CHANGE, // needed, otherwise i2s_set_pin() will fail in IDF >=4.4.x + #endif .bck_io_num = I2S_PIN_NO_CHANGE, // bck is unused in PDM mics .ws_io_num = i2swsPin, // clk pin for PDM mic .data_out_num = I2S_PIN_NO_CHANGE, diff --git a/wled00/blynk.cpp b/wled00/blynk.cpp deleted file mode 100644 index b1619d816e..0000000000 --- a/wled00/blynk.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "wled.h" -#include "src/dependencies/blynk/Blynk/BlynkHandlers.h" - -/* - * Remote light control with the free Blynk app - */ - -uint16_t blHue = 0; -byte blSat = 255; - -void initBlynk(const char *auth, const char *host, uint16_t port) -{ - #ifndef WLED_DISABLE_BLYNK - if (!WLED_CONNECTED) return; - blynkEnabled = (auth[0] != 0); - if (blynkEnabled) Blynk.config(auth, host, port); - #endif -} - -void handleBlynk() -{ - #ifndef WLED_DISABLE_BLYNK - if (WLED_CONNECTED && blynkEnabled) - Blynk.run(); - #endif -} - -void updateBlynk() -{ - #ifndef WLED_DISABLE_BLYNK - if (!WLED_CONNECTED) return; - Blynk.virtualWrite(V0, bri); - //we need a RGB -> HSB convert here - Blynk.virtualWrite(V3, bri? 1:0); - Blynk.virtualWrite(V4, effectCurrent); - Blynk.virtualWrite(V5, effectSpeed); - Blynk.virtualWrite(V6, effectIntensity); - Blynk.virtualWrite(V7, nightlightActive); - Blynk.virtualWrite(V8, notifyDirect); - #endif -} - -#ifndef WLED_DISABLE_BLYNK -BLYNK_WRITE(V0) -{ - bri = param.asInt();//bri - stateUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V1) -{ - blHue = param.asInt();//hue - colorHStoRGB(blHue*10,blSat,col); - colorUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V2) -{ - blSat = param.asInt();//sat - colorHStoRGB(blHue*10,blSat,col); - colorUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V3) -{ - bool on = (param.asInt()>0); - if (!on != !bri) {toggleOnOff(); stateUpdated(CALL_MODE_BLYNK);} -} - -BLYNK_WRITE(V4) -{ - effectCurrent = param.asInt()-1;//fx - colorUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V5) -{ - effectSpeed = param.asInt();//sx - colorUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V6) -{ - effectIntensity = param.asInt();//ix - colorUpdated(CALL_MODE_BLYNK); -} - -BLYNK_WRITE(V7) -{ - nightlightActive = (param.asInt()>0); -} - -BLYNK_WRITE(V8) -{ - notifyDirect = (param.asInt()>0); //send notifications -} -#endif diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 5131f589d2..a2b990700e 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -51,7 +51,7 @@ #define I_32_RN_TM1_4 26 #define I_32_I0_TM1_4 27 #define I_32_I1_TM1_4 28 -//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) +//Bit Bang theoretically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) //APA102 #define I_HS_DOT_3 29 //hardware SPI @@ -132,12 +132,17 @@ #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #define B_32_I1_TM1_4 NeoPixelBrightnessBus #endif -//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) +//Bit Bang theoretically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) #endif //APA102 -#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware SPI +#ifdef WLED_USE_ETHERNET +// fix for upstream #2542 (by @BlackBird77) +#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware HSPI with DMA (ESP32 only) +#else +#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware HSPI +#endif #define B_SS_DOT_3 NeoPixelBrightnessBus //soft SPI //LPD8806 @@ -767,8 +772,15 @@ class PolyBus { #else //ESP32 uint8_t offset = 0; //0 = RMT (num 0-7) 8 = I2S0 9 = I2S1 #ifndef CONFIG_IDF_TARGET_ESP32S2 - if (num > 9) return I_NONE; - if (num > 7) offset = num -7; + + #if 1 // 0..7 = RMT, 8 = I2S#1 + if (num > 8) return I_NONE; // WLEDSR 9 instead of 10, as I2S#0 cannot be used for LEDs + if (num > 7) offset = 2; // WLEDSR skip I2S0, use I2S1 + #else // WLEDSR experimental: use I2S#1 for first bus --> less glitches, 10% faster + if (num > 8) return I_NONE; // 0 = I2S#1, 1..8 = RMT + if (num == 0) offset = 2; + #endif + #else //ESP32 S2 only has 4 RMT channels if (num > 5) return I_NONE; if (num > 4) offset = num -4; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index e20a67b1aa..4111534602 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -286,6 +286,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { // i2sckPin = i2sckPin; // } + CJSON(mclkPin, hw_dmic_pins[F("i2smclk")]); + //int hw_status_pin = hw[F("status")]["pin"]; // -1 JsonObject light = doc[F("light")]; @@ -376,16 +378,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(macroAlexaOn, interfaces["va"]["macros"][0]); CJSON(macroAlexaOff, interfaces["va"]["macros"][1]); -#ifndef WLED_DISABLE_BLYNK - const char* apikey = interfaces["blynk"][F("token")] | "Hidden"; - tdd = strnlen(apikey, 36); - if (tdd > 20 || tdd == 0) - getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security - - JsonObject if_blynk = interfaces["blynk"]; - getStringFromJson(blynkHost, if_blynk[F("host")], 33); - CJSON(blynkPort, if_blynk["port"]); -#endif #ifdef WLED_ENABLE_MQTT JsonObject if_mqtt = interfaces["mqtt"]; @@ -760,6 +752,7 @@ void serializeConfig() { hw_dmic_pins[F("i2ssd")] = i2ssdPin; hw_dmic_pins[F("i2sws")] = i2swsPin; hw_dmic_pins[F("i2sck")] = i2sckPin; + hw_dmic_pins[F("i2smclk")] = mclkPin; JsonObject light = doc.createNestedObject(F("light")); light[F("scale-bri")] = briMultiplier; @@ -837,13 +830,6 @@ void serializeConfig() { if_va_macros.add(macroAlexaOn); if_va_macros.add(macroAlexaOff); -#ifndef WLED_DISABLE_BLYNK - JsonObject if_blynk = interfaces.createNestedObject("blynk"); - if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":""; - if_blynk[F("host")] = blynkHost; - if_blynk["port"] = blynkPort; -#endif - #ifdef WLED_ENABLE_MQTT JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); if_mqtt["en"] = mqttEnabled; @@ -993,13 +979,6 @@ bool deserializeConfigSec() { JsonObject interfaces = doc["if"]; -#ifndef WLED_DISABLE_BLYNK - const char* apikey = interfaces["blynk"][F("token")] | "Hidden"; - int tdd = strnlen(apikey, 36); - if (tdd > 20 || tdd == 0) - getStringFromJson(blynkApiKey, apikey, 36); -#endif - #ifdef WLED_ENABLE_MQTT JsonObject if_mqtt = interfaces["mqtt"]; getStringFromJson(mqttPass, if_mqtt["psk"], 65); @@ -1039,10 +1018,6 @@ void serializeConfigSec() { ap["psk"] = apPass; JsonObject interfaces = doc.createNestedObject("if"); -#ifndef WLED_DISABLE_BLYNK - JsonObject if_blynk = interfaces.createNestedObject("blynk"); - if_blynk[F("token")] = blynkApiKey; -#endif #ifdef WLED_ENABLE_MQTT JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); if_mqtt["psk"] = mqttPass; diff --git a/wled00/const.h b/wled00/const.h index e6fd232b59..81889fdaa6 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -26,7 +26,7 @@ #ifdef CONFIG_IDF_TARGET_ESP32S2 #define WLED_MAX_BUSSES 5 #else - #define WLED_MAX_BUSSES 10 + #define WLED_MAX_BUSSES 9 // WLEDSR I2S#0 is reserved for audio (needed both for analog _and_ digital) #endif #endif #endif @@ -77,6 +77,8 @@ #define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h" #define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h" #define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h +//WLEDMM +#define USERMOD_ID_ARTIFX 31 //Usermod "usermod_v2_artifx.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot @@ -308,7 +310,7 @@ #endif #ifndef ABL_MILLIAMPS_DEFAULT - #define ABL_MILLIAMPS_DEFAULT 850 // auto lower brightness to stay close to milliampere limit + #define ABL_MILLIAMPS_DEFAULT 1500 // auto lower brightness to stay close to milliampere limit WLEDSR: 1500 minmal for 1024 leds / 2D #else #if ABL_MILLIAMPS_DEFAULT < 250 // make sure value is at least 250 #define ABL_MILLIAMPS_DEFAULT 250 @@ -369,4 +371,59 @@ #define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates + +// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves +// which GPIO pins are actually used in a hardwarea layout (controller board) +#if defined(I2CSCLPIN) && !defined(HW_PIN_SCL) + #define HW_PIN_SCL I2CSCLPIN +#endif +#if defined(I2CSDAPIN) && !defined(HW_PIN_SDA) + #define HW_PIN_SDA I2CSDAPIN +#endif +// you cannot change HW I2C pins on 8266 +#if defined(ESP8266) && defined(HW_PIN_SCL) + #undef HW_PIN_SCL +#endif +#if defined(ESP8266) && defined(HW_PIN_SDA) + #undef HW_PIN_SDA +#endif +// defaults for 1st I2C on ESP32 (Wire global) +#ifndef HW_PIN_SCL + #define HW_PIN_SCL SCL +#endif +#ifndef HW_PIN_SDA + #define HW_PIN_SDA SDA +#endif + +// HW_PIN_SCLKSPI & HW_PIN_MOSISPI & HW_PIN_MISOSPI are used for information in usermods settings page and usermods themselves +// which GPIO pins are actually used in a hardwarea layout (controller board) +#if defined(SPISCLKPIN) && !defined(HW_PIN_CLOCKSPI) + #define HW_PIN_CLOCKSPI SPISCLKPIN +#endif +#if defined(SPIMOSIPIN) && !defined(HW_PIN_MOSISPI) + #define HW_PIN_MOSISPI SPIMOSIPIN +#endif +#if defined(SPIMISOPIN) && !defined(HW_PIN_MISOSPI) + #define HW_PIN_MISOSPI SPIMISOPIN +#endif +// you cannot change HW SPI pins on 8266 +#if defined(ESP8266) && defined(HW_PIN_CLOCKSPI) + #undef HW_PIN_CLOCKSPI +#endif +#if defined(ESP8266) && defined(HW_PIN_DATASPI) + #undef HW_PIN_DATASPI +#endif +#if defined(ESP8266) && defined(HW_PIN_MISOSPI) + #undef HW_PIN_MISOSPI +#endif +// defaults for VSPI on ESP32 (SPI global, SPI.cpp) as HSPI is used by WLED (bus_wrapper.h) +#ifndef HW_PIN_CLOCKSPI + #define HW_PIN_CLOCKSPI SCK +#endif +#ifndef HW_PIN_DATASPI + #define HW_PIN_DATASPI MOSI +#endif +#ifndef HW_PIN_MISOSPI + #define HW_PIN_MISOSPI MISO +#endif #endif diff --git a/wled00/data/index.css b/wled00/data/index.css index c4f9d74a94..f1b9f24083 100755 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -121,6 +121,12 @@ button { font-size: 42px; } +/* WLEDSR */ +.tiny { + font-size: 14px; + color: #aaa; +} + .infot { table-layout: fixed; width: 100%; @@ -386,7 +392,7 @@ Effect Speed */ transform: translateY(100%); transition: transform 0.4s; padding: 8px; - font-size: 20px; + font-size: 17px; /* WLEDSR: smaller is better */ overflow: auto; } @@ -433,8 +439,7 @@ Effect Speed */ margin: 8px; } -/* WLEDSR Custom Effects: add kceEditor */ -#kv, #kn, #kceEditor { +#kv, #kn { max-width: 490px; display: inline-block; } @@ -729,14 +734,6 @@ input[type=number], input[type=text] { appearance: textfield; } -/* WLEDSR Custom Effects */ -.ceTextarea { - width: 90%; - height: 300px; - resize: none; - white-space: pre; -} - textarea { background: var(--c-2); color: var(--c-f); diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 33b71e7dbf..ef3ea166c8 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -9,6 +9,7 @@ WLED + @@ -251,7 +252,7 @@
- + @@ -274,5 +275,6 @@ + diff --git a/wled00/data/index.js b/wled00/data/index.js index a4e0dc0946..8f6b2679fe 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1,7 +1,7 @@ //page js var loc = false, locip; var noNewSegs = false; -var isOn = false, nlA = false, isLv = false, isInfo = false, isCEEditor = false, isNodes = false, syncSend = false, syncTglRecv = true; +var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true; var hasWhite = false, hasRGB = false, hasCCT = false; var whites = [0,0,0]; var colors = [[0,0,0],[0,0,0],[0,0,0]]; @@ -599,8 +599,9 @@ function populateInfo(i) if (i.ver.startsWith("0.13.")) vcn = "Toki+SR"; if (i.cn) vcn = i.cn; - cn += `v${i.ver} "${vcn}"

- ${inforow("SR Build",i.vid)} + // cn += `v${i.ver} "${vcn}"

+ cn += `v${i.ver}  "${vcn}"

(WLEDSR_${i.ver} ${i.rel}.bin)

build ${i.vid}


+
${inforow("Audio Source",i.audioType,i.audioStatus)} ${i.audioWarning?inforow1("Please "+i.audioWarning+"(s) !"):""} @@ -721,9 +722,9 @@ function populateSegments(s) `; - // WLEDSR Custom Effects + // WLEDSR ARTI-FX if (inst.fx == 187) - cn += `
+ cn += `

`; else @@ -1665,7 +1666,6 @@ function toggleLiveview() { function toggleInfo() { if (isNodes) toggleNodes(); - if (isCEEditor) toggleCEEditor();// WLEDSR Custom Effects if (isLv) toggleLiveview(); isInfo = !isInfo; if (isInfo) populateInfo(lastinfo); @@ -1675,7 +1675,6 @@ function toggleInfo() { function toggleNodes() { if (isInfo) toggleInfo(); - if (isCEEditor) toggleCEEditor();// WLEDSR Custom Effects if (isLv) toggleLiveview(); isNodes = !isNodes; d.getElementById('nodes').style.transform = (isNodes) ? "translateY(0px)":"translateY(100%)"; @@ -1683,15 +1682,6 @@ function toggleNodes() { if (isNodes) loadNodes(); } -// WLEDSR Custom Effects -function toggleCEEditor(name, segID) { - if (isInfo) toggleInfo(); - if (isNodes) toggleNodes(); - isCEEditor = !isCEEditor; - if (isCEEditor) populateCEEditor(name, segID); - d.getElementById('ceEditor').style.transform = (isCEEditor) ? "translateY(0px)":"translateY(100%)"; -} - function makeSeg() { var ns = 0; if (lowestUnused > 0) { @@ -2213,159 +2203,6 @@ function saveP(i,pl) { resetPUtil(); } -// WLEDSR Custom Effects -function fetchAndExecute(name, callback) -{ - var url = (loc?`http://${locip}`:'.') + "/" + name; - - fetch - (url, { - method: 'get' - }) - .then(res => { - if (!res.ok) { - showToast("File " + name + " not found"); - return ""; - } - return res.text(); - }) - .then(text => { - callback(text); - }) - .catch(function (error) { - showToast(error, true); - console.log(error); - presetError(false); - }) - .finally(() => { - // if (callback) setTimeout(callback,99); - }); -} - -// WLEDSR Custom Effects -function populateCEEditor(name, segID) -{ - - fetchAndExecute(name + ".wled", function(text) - { - var cn=`
- Custom Effects Editor
- ${name}.wled
- -
- -
- -
- -
- Custom Effects Library
- Custom Effects Help
-
Compile and Run Log
-
- Run log > 3 seconds is send to Serial Ouput.`; - - d.getElementById('kceEditor').innerHTML = cn; - - var ceLogArea = d.getElementById("ceLogArea"); - ceLogArea.value = "."; - loadLogFile(name + ".wled.log", 1); - - }); -} - -//WLEDSR Custom Effects -function uploadFileWithText(name, text) -{ - var req = new XMLHttpRequest(); - req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); - req.addEventListener('error', function(e){showToast(e.stack,true);}); - req.open("POST", "/upload"); - var formData = new FormData(); - - var blob = new Blob([text], {type : 'application/text'}); - var fileOfBlob = new File([blob], name); - formData.append("upload", fileOfBlob); - - req.send(formData); -} - -//WLEDSR Custom Effects -function saveCE(name, segID) { - showToast("Saving " + name); - - var ceProgramArea = d.getElementById("ceProgramArea"); - - uploadFileWithText("/" + name, ceProgramArea.value); - - var obj = {"seg": {"id": segID, "reset": true}}; - requestJson(obj); - - var ceLogArea = d.getElementById("ceLogArea"); - ceLogArea.value = "."; - setTimeout(() => - { - loadLogFile(name + ".log", 1); - }, 1000); -} - -function loadLogFile(name, attempt) { - var ceLogArea = d.getElementById("ceLogArea"); - fetchAndExecute(name , function(logtext) - { - if (logtext == "") { - if (attempt < 10) { - ceLogArea.value = ("...........").substring(0, attempt + 1); - setTimeout(() => - { - loadLogFile(name, attempt + 1); - }, 1000); - } - else - ceLogArea.value = "log not found after 10 seconds"; - } - else - ceLogArea.value = logtext; - }); -} - -//WLEDSR Custom Effects -function downloadCEFile(name) { - var url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/CustomEffects/wled/" + name; - - var request = new XMLHttpRequest(); - request.onload = function() { - if (name == "wled.json" || name == "presets.json") { - if (!confirm('Are you sure to download ' + name + '?')) - return; - uploadFileWithText("/" + name, request.response); - } - else - { - var ceProgramArea = d.getElementById("ceProgramArea"); - ceProgramArea.value = request.response; - } - } - request.open("GET", url); - request.send(); -} - -//WLEDSR Custom Effects -function loadCETemplate(name) { - var ceProgramArea = d.getElementById("ceProgramArea"); - ceProgramArea.value = `/* - Custom Effects Template -*/ -program ${name} -{ - function renderFrame() - { - leds[counter] = colorFromPalette(counter, counter) - } -}`; - -} - function testPl(i,bt) { if (bt.dataset.test == 1) { bt.dataset.test = 0; diff --git a/wled00/data/liveviewws.htm b/wled00/data/liveviewws.htm index be16a86e41..4ae60d25f9 100644 --- a/wled00/data/liveviewws.htm +++ b/wled00/data/liveviewws.htm @@ -24,7 +24,7 @@ function updatePreview(leds) { var str = "linear-gradient(90deg,"; var len = leds.length; - for (i = 6; i < len; i+=3) { + for (i = 8; i < len; i+=3) { str += `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`; if (i < len -3) str += "," } diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index dac468fd36..1b4b3c3cdc 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -11,6 +11,7 @@ function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");} function B(){window.open("/settings","_self");} function gId(n){return d.getElementById(n);} + function hideNoIR(){gId("irOnOff2").style.display="none";} function off(n){d.getElementsByName(n)[0].value = -1;} var timeout; function showToast(text, error = false) @@ -121,6 +122,11 @@ gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none'; + gId('fpswarning').style.display = (d.Sf.FR.value > 79) ? 'block':'none'; // WLEDSR + gId('fpshelp1').style.display = ((d.Sf.FR.value > 80) && (d.Sf.FR.value < 132)) ? 'block':'none'; // WLEDSR + gId('fpshelp2').style.display = ((d.Sf.FR.value > 132) && (d.Sf.FR.value < 196)) ? 'block':'none'; // WLEDSR + gId('fpshelp3').style.display = (d.Sf.FR.value > 196) ? 'block':'none'; // WLEDSR + if (d.Sf.LA.value == 255) laprev = 12; else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value; @@ -546,8 +552,8 @@

LED & Hardware setup


2D Matrix

- Width x - Height
+ Width x + Height
⚠ width x height should match LED count!
@@ -624,6 +630,9 @@

Hardware setup


Touch threshold:
+
+ This firmware build does not include IR Remote support.
+
IR GPIO:
- Target refresh rate: FPS + Target refresh rate: FPS + + + +
Config template:

diff --git a/wled00/data/settings_sound.htm b/wled00/data/settings_sound.htm index 65fdb6270f..5cd0ef9b92 100644 --- a/wled00/data/settings_sound.htm +++ b/wled00/data/settings_sound.htm @@ -8,7 +8,7 @@ var d=document; function H() { - window.open("https://github.com/atuline/WLED/wiki/Squelch-and-Gain"); + window.open("https://github.com/atuline/WLED/wiki/Sound-Settings"); } function B() { @@ -19,6 +19,12 @@ { var en = parseInt(d.getElementById('dme').value); d.getElementById('dm').style.display = (en >= 1) ? 'inline':'none'; + d.getElementById('dm_mclk').style.display = ((en == 2) || (en == 4)) ? 'inline':'none'; + d.getElementById('dm_sck').style.display = ((en != 5) && (en >= 1)) ? 'inline':'none'; + d.getElementById('dm_pdmdat').style.display = (en == 5) ? 'inline':'none'; + d.getElementById('dm_pdmclk').style.display = (en == 5) ? 'inline':'none'; + d.getElementById('dm_xdat').style.display = ((en != 5) && (en >= 1)) ? 'inline':'none'; + d.getElementById('dm_xws').style.display = ((en != 5) && (en >= 1)) ? 'inline':'none'; d.getElementById('am').style.display = (en == 0) ? 'inline':'none'; } function GetV() @@ -37,9 +43,10 @@

Sound Input Settings

Squelch:
- Gain:
- Gain=40 means an amplification of 1; 1 is about 1/12, 255 is about 6.5
- To tune, set input level slider to middle/128, start with Squelch=5..10 and Gain=40 and modify according to your setup
+ Gain:

+ How to tune Squelch and Gain
+ Gain=40 means an amplification of 1; 1 is about 1/12, 255 is about 6.5. + To tune, set input level slider to middle/128, start with Squelch=5..10 and Gain=40 and modify according to your setup.

Automatic Gain Control (AGC):
- If AGC is enabled, the input slider (🎚) will automatically be adjusted

+
+ If AGC is enabled, the input slider (🎚) will automatically be adjusted

Sound Input Pin Manager

Microphone type:
- I2S SD pin:
- I2S WS pin:
- I2S SCK pin:
+ I2S SD pin:   + SD / DATA / DOUTDATA
+ I2S WS pin:   + WS / CLK / LRCK  CLK  
+
+ I2S SCK pin:   + SCK / BCLK        
+
+
+ I2S MCLK pin:   + MCK / MCLK      
+
- Changing the microphone type or pins requires a hard reset/power cycle
+ Changing the microphone type or pins requires a hard reset/power cycle
Analog Input pin:
+

+ about I2S Digital Input   + about Analog Input
+

diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 02988b608a..130c304ed6 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -8,6 +8,7 @@ function doHide(s){gId(s).style.display="none";} function doShow(s){gId(s).style.display="block";} +function hideNoDMX(){gId("dmxOnOff2").style.display="none";} function hideALEXA(){gId("aleOnOff").style.display="none";} function hideNoALEXA(){gId("aleOnOff2").style.display="none";} function hideBLYNK(){gId("blyOnOff").style.display="none";} @@ -16,6 +17,8 @@ function hideNoMQTT(){gId("mqtOnOff2").style.display="none";} function hideHUE(){gId("hueOnOff").style.display="none";} function hideNoHUE(){gId("hueOnOff2").style.display="none";} +function hideNoADA(){gId("adaOnOff2").style.display="none";} +function hideNoLOX(){gId("loxOnOff2").style.display="none";} function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");} function B(){window.open("/settings","_self");} @@ -137,6 +140,9 @@

Realtime

Force max brightness:
Disable realtime gamma correction:
Realtime LED offset: +
+
This firmware build does not include DMX output support.
+

Alexa Voice Assistant

This firmware build does not include Alexa support.
@@ -145,15 +151,16 @@

Alexa Voice Assistant

Emulate Alexa device:
Alexa invocation name:
-

Blynk

+
This firmware build does not include Blynk support.
-Blynk, MQTT and Hue sync all connect to external hosts!
+Network protocols like MQTT and Hue sync all connect to external hosts!
This may impact the responsiveness of the ESP microcontroller.

For best results, only use one of these services at a time.
(alternatively, connect a second ESP to them and use the UDP sync)

+

Blynk

Host: Port:
Device Auth token:
@@ -194,6 +201,12 @@

Philips Hue

(when first connecting)
Hue status: Disabled in this build +
+
This firmware build does not include Loxone Lighting support.
+
+
+
This firmware build does not include AdaLight support.
+

Serial

Baud rate:
UTC offset: seconds (max. 18 hours)
diff --git a/wled00/data/style.css b/wled00/data/style.css index 27b07c1213..5bbf11fb6c 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -18,14 +18,23 @@ button, .btn { color: #fff; font-family: Verdana, sans-serif; border: 0.3ch solid #333; + border-radius: 24px; display: inline-block; font-size: 20px; margin: 12px 8px 8px; - padding: 1px 6px; + padding: 8px 12px; + min-width: 48px; cursor: pointer; text-decoration: none; -} -.lnk { + } + button.sml { + padding: 8px; + border-radius: 20px; + font-size: 15px; + min-width: 40px; + margin: 0 0 0 10px; + } + .lnk { border: 0; } button.disabled, button[disabled] { @@ -82,6 +91,17 @@ td { .d5 { width: 4.5em !important; } + +/* WLEDSR */ +.tiny { + font-size: 14px; + color: #bbb; +} + +#msg { + display: none; +} + #toast { opacity: 0; background-color: #444; diff --git a/wled00/data/update.htm b/wled00/data/update.htm index 93ef0548ae..4420054327 100644 --- a/wled00/data/update.htm +++ b/wled00/data/update.htm @@ -6,46 +6,22 @@ WLED Update - - +

Sound Reactive WLED Software Update

- Installed version: SR ##VERSION##
- Download the latest binary: + ##VERSION##
+ Download the latest release:

-
-
-
+
+
+ +
Updating...
Please do not close or refresh the page :)
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 5ab669a92c..cdfcbe8c07 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -14,13 +14,6 @@ void alexaInit(); void handleAlexa(); void onAlexaChange(EspalexaDevice* dev); -//blynk.cpp -#ifndef WLED_DISABLE_BLYNK -void initBlynk(const char* auth, const char* host, uint16_t port); -void handleBlynk(); -void updateBlynk(); -#endif - //button.cpp void shortPressAction(uint8_t b=0); void longPressAction(uint8_t b=0); @@ -307,3 +300,5 @@ void sappends(char stype, const char* key, char* val); void getSettingsJS(byte subPage, char* dest); #endif + +CRGB getCRGBForBand(int x, int pal); //WLEDMM netmindz ar palette \ No newline at end of file diff --git a/wled00/file.cpp b/wled00/file.cpp index 55ebf081ac..e758ee4162 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -27,9 +27,10 @@ // There are no consecutive spaces longer than this in the file, so if more space is required, findSpace() can return false immediately // Actual space may be lower -uint16_t knownLargestSpace = UINT16_MAX; +constexpr size_t MAX_SPACE = UINT16_MAX * 2U; // WLEDSR smallest supported config has 128Kb LittleFS +static volatile size_t knownLargestSpace = MAX_SPACE; -File f; +static File f; //wrapper to find out how long closing takes void closeFile() { @@ -44,7 +45,7 @@ void closeFile() { //find() that reads and buffers data from file stream in 256-byte blocks. //Significantly faster, f.find(key) can take SECONDS for multi-kB files -bool bufferedFind(const char *target, bool fromStart = true) { +static bool bufferedFind(const char *target, bool fromStart = true) { #ifdef WLED_DEBUG_FS DEBUGFS_PRINT("Find "); DEBUGFS_PRINTLN(target); @@ -59,8 +60,8 @@ bool bufferedFind(const char *target, bool fromStart = true) { if (fromStart) f.seek(0); while (f.position() < f.size() -1) { - uint16_t bufsize = f.read(buf, FS_BUFSIZE); - uint16_t count = 0; + size_t bufsize = f.read(buf, FS_BUFSIZE); // WLEDSR size_t instead if uint16_t + size_t count = 0; // WLEDSR while (count < bufsize) { if(buf[count] != target[index]) index = 0; // reset index if any char does not match @@ -80,7 +81,7 @@ bool bufferedFind(const char *target, bool fromStart = true) { } //find empty spots in file stream in 256-byte blocks. -bool bufferedFindSpace(uint16_t targetLen, bool fromStart = true) { +static bool bufferedFindSpace(size_t targetLen, bool fromStart = true) { #ifdef WLED_DEBUG_FS DEBUGFS_PRINTF("Find %d spaces\n", targetLen); @@ -95,20 +96,20 @@ bool bufferedFindSpace(uint16_t targetLen, bool fromStart = true) { if (!f || !f.size()) return false; - uint16_t index = 0; + size_t index = 0; // WLEDSR size_t instead if uint16_t byte buf[FS_BUFSIZE]; if (fromStart) f.seek(0); while (f.position() < f.size() -1) { - uint16_t bufsize = f.read(buf, FS_BUFSIZE); - uint16_t count = 0; - + size_t bufsize = f.read(buf, FS_BUFSIZE); // WLEDSR + size_t count = 0; // WLEDSR + while (count < bufsize) { if(buf[count] == ' ') { if(++index >= targetLen) { // return true if space long enough if (fromStart) { f.seek((f.position() - bufsize) + count +1 - targetLen); - knownLargestSpace = UINT16_MAX; //there may be larger spaces after, so we don't know + knownLargestSpace = MAX_SPACE; //there may be larger spaces after, so we don't know // WLEDSR smallest supported config has 128Kb flash size } DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s); return true; @@ -116,7 +117,7 @@ bool bufferedFindSpace(uint16_t targetLen, bool fromStart = true) { } else { if (!fromStart) return false; if (index) { - if (knownLargestSpace < index || knownLargestSpace == UINT16_MAX) knownLargestSpace = index; + if (knownLargestSpace < index || (knownLargestSpace == MAX_SPACE)) knownLargestSpace = index; // WLEDSR index = 0; // reset index if not space } } @@ -129,7 +130,7 @@ bool bufferedFindSpace(uint16_t targetLen, bool fromStart = true) { } //find the closing bracket corresponding to the opening bracket at the file pos when calling this function -bool bufferedFindObjectEnd() { +static bool bufferedFindObjectEnd() { #ifdef WLED_DEBUG_FS DEBUGFS_PRINTLN(F("Find obj end")); uint32_t s = millis(); @@ -142,9 +143,9 @@ bool bufferedFindObjectEnd() { byte buf[FS_BUFSIZE]; while (f.position() < f.size() -1) { - uint16_t bufsize = f.read(buf, FS_BUFSIZE); - uint16_t count = 0; - + size_t bufsize = f.read(buf, FS_BUFSIZE); // WLEDSR size_t instead of uint16_t + size_t count = 0; // WLEDSR + while (count < bufsize) { if (buf[count] == '{') objDepth++; if (buf[count] == '}') objDepth--; @@ -161,13 +162,13 @@ bool bufferedFindObjectEnd() { } //fills n bytes from current file pos with ' ' characters -void writeSpace(uint16_t l) +static void writeSpace(size_t l) { byte buf[FS_BUFSIZE]; memset(buf, ' ', FS_BUFSIZE); while (l > 0) { - uint16_t block = (l>FS_BUFSIZE) ? FS_BUFSIZE : l; + size_t block = (l>FS_BUFSIZE) ? FS_BUFSIZE : l; // WLEDSR size_t instead of uint16_t f.write(buf, block); l -= block; } @@ -194,7 +195,7 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint doCloseFile = true; return true; //nothing to append } - + //if there is enough empty space in file, insert there instead of appending if (!contentLen) contentLen = measureJson(*content); DEBUGFS_PRINTF("CLen %d\n", contentLen); @@ -211,18 +212,18 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint //permitted space for presets exceeded updateFSInfo(); - + if (f.size() + 9000 > (fsBytesTotal - fsBytesUsed)) { //make sure there is enough space to at least copy the file once errorFlag = ERR_FS_QUOTA; doCloseFile = true; return false; } - + //check if last character in file is '}' (typical) uint32_t eof = f.size() -1; f.seek(eof, SeekSet); if (f.read() == '}') pos = eof; - + if (pos == 0) //not found { DEBUGFS_PRINTLN("not }"); @@ -256,8 +257,8 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content) { - char objKey[10]; - sprintf(objKey, "\"%d\":", id); + char objKey[12]={'\0'}; + snprintf(objKey, sizeof(objKey), "\"%d\":", id); // WLEDSR return writeObjectToFile(file, objKey, content); } @@ -270,24 +271,24 @@ bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) s = millis(); #endif - uint32_t pos = 0; + size_t pos = 0; f = WLED_FS.open(file, "r+"); if (!f && !WLED_FS.exists(file)) f = WLED_FS.open(file, "w+"); if (!f) { DEBUGFS_PRINTLN(F("Failed to open!")); return false; } - + if (!bufferedFind(key)) //key does not exist in file { return appendObjectToFile(key, content, s); - } - + } + //an object with this key already exists, replace or delete it pos = f.position(); //measure out end of old object bufferedFindObjectEnd(); - uint32_t pos2 = f.position(); + size_t pos2 = f.position(); // WLEDSR uint32_t oldLen = pos2 - pos; DEBUGFS_PRINTF("Old obj len %d\n", oldLen); @@ -297,8 +298,8 @@ bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) //2. The new content is smaller than the old, overwrite and fill diff with spaces //3. The new content is larger than the old, but smaller than old + trailing spaces, overwrite with new //4. The new content is larger than old + trailing spaces, delete old and append - - uint32_t contentLen = 0; + + size_t contentLen = 0; // WLEDSR if (!content->isNull()) contentLen = measureJson(*content); if (contentLen && contentLen <= oldLen) { //replace and fill diff with spaces @@ -326,8 +327,8 @@ bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest) { - char objKey[10]; - sprintf(objKey, "\"%d\":", id); + char objKey[12]={'\0'}; + snprintf(objKey, sizeof(objKey), "\"%d\":", id); return readObjectFromFile(file, objKey, dest); } @@ -375,7 +376,7 @@ void updateFSInfo() { //Un-comment any file types you need -String getContentType(AsyncWebServerRequest* request, String filename){ +static String getContentType(AsyncWebServerRequest* request, String filename){ if(request->hasArg("download")) return "application/octet-stream"; else if(filename.endsWith(".htm")) return "text/html"; else if(filename.endsWith(".html")) return "text/html"; @@ -394,7 +395,7 @@ String getContentType(AsyncWebServerRequest* request, String filename){ } bool handleFileRead(AsyncWebServerRequest* request, String path){ - DEBUG_PRINTLN("FileRead: " + path); + DEBUG_PRINTLN("WS FileRead: " + path); if(path.endsWith("/")) path += "index.htm"; if(path.indexOf("sec") > -1) return false; String contentType = getContentType(request, path); diff --git a/wled00/html_other.h b/wled00/html_other.h index cb1d58c15f..4e01be7bf6 100644 --- a/wled00/html_other.h +++ b/wled00/html_other.h @@ -37,18 +37,17 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()====="; // Autogenerated from wled00/data/update.htm, do not edit!! const char PAGE_update[] PROGMEM = R"=====( WLED Update

Sound Reactive WLED Software Update

Installed version: SR 0.13.3
Download the latest binary: +

Sound Reactive WLED Software Update

0.13.4-beta
Download the latest release:
-


Updating...
-Please do not close or refresh the page :)
)====="; +


Updating...
Please do not close or refresh the page :)
+)====="; // Autogenerated from wled00/data/welcome.htm, do not edit!! @@ -85,7 +84,7 @@ charset="utf-8"> WLED Live Preview
)====="; diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 6fb2122088..d62dcbbfc0 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -6,7 +6,7 @@ */ // Autogenerated from wled00/data/style.css, do not edit!! -const char PAGE_settingsCss[] PROGMEM = R"=====()====="; +const char PAGE_settingsCss[] PROGMEM = R"=====()====="; // Autogenerated from wled00/data/settings.htm, do not edit!! @@ -77,7 +77,7 @@ const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings")); }