From 4b1b0fe04535e4762d253755769de6e6937201ec Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 22 Sep 2025 20:01:54 +0200 Subject: [PATCH 1/2] Adding center bin selection to 2D GEQ (#4764) * adding center bin selection to 2D GEQ: this makes it possible to use subsets of the GEQ on distributed strips setting custom3 to 0 gives the "old" behaviour, this is the default. existing presets will have the custom3 slider at the center, changing presets that do not use the full width so this is a breaking change for those but I assume theser are rare. --- wled00/FX.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f6bf54c0..b0aa1875 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7275,6 +7275,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); + const int CENTER_BIN = map(SEGMENT.custom3, 0, 31, 0, 15); const int cols = SEG_W; const int rows = SEG_H; @@ -7296,8 +7297,14 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); for (int x=0; x < cols; x++) { - uint8_t band = map(x, 0, cols, 0, NUM_BANDS); - if (NUM_BANDS < 16) band = map(band, 0, NUM_BANDS - 1, 0, 15); // always use full range. comment out this line to get the previous behaviour. + int band = map(x, 0, cols, 0, NUM_BANDS); + if (NUM_BANDS < 16) { + int startBin = constrain(CENTER_BIN - NUM_BANDS/2, 0, 15 - NUM_BANDS + 1); + if(NUM_BANDS <= 1) + band = CENTER_BIN; // map() does not work for single band + else + band = map(band, 0, NUM_BANDS - 1, startBin, startBin + NUM_BANDS - 1); + } band = constrain(band, 0, 15); unsigned colorIndex = band * 17; int barHeight = map(fftResult[band], 0, 255, 0, rows); // do not subtract -1 from rows here @@ -7319,7 +7326,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. return FRAMETIME; } // mode_2DGEQ() -static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# of bands,,,Color bars;!,,Peaks;!;2f;c1=255,c2=64,pal=11,si=0"; // Beatsin +static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# of bands,,Bin,Color bars;!,,Peaks;!;2f;c1=255,c2=64,pal=11,si=0,c3=0"; ///////////////////////// From 529edfc39bc20898440e16b9aaccd93eaf13ddcd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 22 Sep 2025 20:09:54 +0200 Subject: [PATCH 2/2] "unrestricted" number of custom palettes (#4932) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - allow more than 10 custom palettes - move palettes into CPP file - Fix for minimizing cpal.htm (saves 2k of flash) - shortened names in cpal, saves about 400 bytes of Flash after packing - removed async from common.js loading to prevent errors on page loads if the file is not cached - restricted nubmer of user palettes on ESP8266 to 10 - unrestricted number of user palettes on all other platforms (total max palettes: 256) - added a warning when adding more than 10 palettes to let the user decide to risk it - Bugfixes in palette enumeration, fixed AR palette adding - AR palettes are now also added if there are more than 10 custom palettes Co-authored-by: Blaž Kristan --- tools/cdata.js | 17 +- usermods/audioreactive/audio_reactive.cpp | 2 +- wled00/FX_2Dfcn.cpp | 1 - wled00/FX_fcn.cpp | 20 +- wled00/colors.cpp | 2 +- wled00/colors.h | 6 +- wled00/const.h | 10 +- wled00/data/cpal/cpal.htm | 726 ++++++++++------------ wled00/data/index.js | 14 +- wled00/data/settings.htm | 2 +- wled00/data/settings_2D.htm | 2 +- wled00/data/settings_dmx.htm | 2 +- wled00/data/settings_leds.htm | 2 +- wled00/data/settings_sec.htm | 2 +- wled00/data/settings_sync.htm | 2 +- wled00/data/settings_time.htm | 2 +- wled00/data/settings_ui.htm | 2 +- wled00/data/settings_um.htm | 2 +- wled00/data/settings_wifi.htm | 2 +- wled00/data/update.htm | 2 +- wled00/json.cpp | 15 +- wled00/{palettes.h => palettes.cpp} | 5 +- wled00/util.cpp | 2 +- wled00/wled_server.cpp | 16 +- 24 files changed, 389 insertions(+), 469 deletions(-) rename wled00/{palettes.h => palettes.cpp} (99%) mode change 100755 => 100644 diff --git a/tools/cdata.js b/tools/cdata.js index e02047e8..c05b28e5 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -143,7 +143,7 @@ async function writeHtmlGzipped(sourceFile, resultFile, page) { console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes"); const array = hexdump(result); let src = singleHeader; - src += `const uint16_t PAGE_${page}_L = ${result.length};\n`; + src += `const uint16_t PAGE_${page}_length = ${result.length};\n`; src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`; console.info("Writing " + resultFile); fs.writeFileSync(resultFile, src); @@ -244,9 +244,22 @@ if (isAlreadyBuilt("wled00/data") && process.argv[2] !== '--force' && process.ar writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index'); writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart'); -writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal'); +//writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal'); writeHtmlGzipped("wled00/data/pxmagic/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic'); +writeChunks( + "wled00/data/cpal", + [ + { + file: "cpal.htm", + name: "PAGE_cpal", + method: "gzip", + filter: "html-minify" + } + ], + "wled00/html_cpal.h" +); + writeChunks( "wled00/data", [ diff --git a/usermods/audioreactive/audio_reactive.cpp b/usermods/audioreactive/audio_reactive.cpp index 25b81352..b4151725 100644 --- a/usermods/audioreactive/audio_reactive.cpp +++ b/usermods/audioreactive/audio_reactive.cpp @@ -1981,7 +1981,7 @@ void AudioReactive::createAudioPalettes(void) { if (palettes) return; DEBUG_PRINTLN(F("Adding audio palettes.")); for (int i=0; i GRADIENT_PALETTE_COUNT+13) pal = 0; - if (pal > 245 && (customPalettes.size() == 0 || 255U-pal > customPalettes.size()-1)) pal = 0; + // there is one randomy generated palette (1) followed by 4 palettes created from segment colors (2-5) + // those are followed by 7 fastled palettes (6-12) and 59 gradient palettes (13-71) + // then come the custom palettes (255,254,...) growing downwards from 255 (255 being 1st custom palette) + // palette 0 is a varying palette depending on effect and may be replaced by segment's color if so + // instructed in color_from_palette() + if (pal > FIXED_PALETTE_COUNT && pal <= 255-customPalettes.size()) pal = 0; // out of bounds palette //default palette. Differs depending on effect if (pal == 0) pal = _default_palette; // _default_palette is set in setMode() switch (pal) { @@ -263,13 +266,13 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { } break;} default: //progmem palettes - if (pal>245) { + if (pal > 255 - customPalettes.size()) { targetPalette = customPalettes[255-pal]; // we checked bounds above - } else if (pal < 13) { // palette 6 - 12, fastled palettes - targetPalette = *fastledPalettes[pal-6]; + } else if (pal < DYNAMIC_PALETTE_COUNT+FASTLED_PALETTE_COUNT+1) { // palette 6 - 12, fastled palettes + targetPalette = *fastledPalettes[pal-DYNAMIC_PALETTE_COUNT-1]; } else { byte tcp[72]; - memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72); + memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-(DYNAMIC_PALETTE_COUNT+FASTLED_PALETTE_COUNT)-1])), 72); targetPalette.loadDynamicGradientPalette(tcp); } break; @@ -573,8 +576,7 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) { } Segment &Segment::setPalette(uint8_t pal) { - if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes - if (pal > 245 && (customPalettes.size() == 0 || 255U-pal > customPalettes.size()-1)) pal = 0; // custom palettes + if (pal <= 255-customPalettes.size() && pal > FIXED_PALETTE_COUNT) pal = 0; // not built in palette or custom palette if (pal != palette) { //DEBUG_PRINTF_P(PSTR("- Starting palette transition: %d\n"), pal); startTransition(strip.getTransition(), blendingStyle != BLEND_STYLE_FADE); // start transition prior to change (no need to copy segment) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index bf2b69d7..f848787f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -252,7 +252,7 @@ void loadCustomPalettes() { byte tcp[72]; //support gradient palettes with up to 18 entries CRGBPalette16 targetPalette; customPalettes.clear(); // start fresh - for (int index = 0; index<10; index++) { + for (int index = 0; index < WLED_MAX_CUSTOM_PALETTES; index++) { char fileName[32]; sprintf_P(fileName, PSTR("/palette%d.json"), index); diff --git a/wled00/colors.h b/wled00/colors.h index 376959fd..8ee1cf4f 100644 --- a/wled00/colors.h +++ b/wled00/colors.h @@ -123,7 +123,7 @@ CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); void loadCustomPalettes(); extern std::vector customPalettes; -inline size_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); } +inline size_t getPaletteCount() { return FIXED_PALETTE_COUNT + customPalettes.size(); } inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); @@ -141,4 +141,8 @@ void setRandomColor(byte* rgb); [[gnu::hot, gnu::pure]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video = false); +// palettes +extern const TProgmemRGBPalette16* const fastledPalettes[]; +extern const uint8_t* const gGradientPalettes[]; #endif + diff --git a/wled00/const.h b/wled00/const.h index c95c19b7..b9379911 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -6,7 +6,15 @@ * Readability defines and their associated numerical values + compile-time constants */ -#define GRADIENT_PALETTE_COUNT 59 +constexpr size_t FASTLED_PALETTE_COUNT = 7; // = sizeof(fastledPalettes) / sizeof(fastledPalettes[0]); +constexpr size_t GRADIENT_PALETTE_COUNT = 59; // = sizeof(gGradientPalettes) / sizeof(gGradientPalettes[0]); +constexpr size_t DYNAMIC_PALETTE_COUNT = 5; // 1-5 are dynamic palettes (1=random,2=primary,3=primary+secondary,4=primary+secondary+tertiary,5=primary+secondary(+tertiary if not black) +constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_COUNT + GRADIENT_PALETTE_COUNT; // total number of fixed palettes +#ifndef ESP8266 + #define WLED_MAX_CUSTOM_PALETTES (255 - FIXED_PALETTE_COUNT) // allow up to 255 total palettes, user is warned about stability issues when adding more than 10 +#else + #define WLED_MAX_CUSTOM_PALETTES 10 // ESP8266: limit custom palettes to 10 +#endif // You can define custom product info from build flags. // This is useful to allow API consumer to identify what type of WLED version diff --git a/wled00/data/cpal/cpal.htm b/wled00/data/cpal/cpal.htm index 8fa715bc..2c09029b 100644 --- a/wled00/data/cpal/cpal.htm +++ b/wled00/data/cpal/cpal.htm @@ -11,7 +11,8 @@ function gId(e) {return d.getElementById(e);} function cE(e) {return d.createElement(e);} - + +

- - - - - + + + + + - WLED Custom Palette Editor + WLED Palette Editor

-
-
-
+
-
-
-
- Currently in use custom palettes -
+
+
+ +
Custom palettes
-
- Click on the gradient editor to add new color slider, then the colored box below the slider to change its color. - Click the red box below indicator (and confirm) to delete. - Once finished, click the arrow icon to upload into the desired slot. - To edit existing palette, click the pencil icon. -
+
Click gradient to add. Box = color. Red = delete. Arrow = upload. Pencil = edit.
-
-
- Available static palettes -
+
+
Static palettes
- + + + + + + + + + + +