diff --git a/wled00/FX.h b/wled00/FX.h index b29a8008e..703191ea9 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,8 +420,8 @@ typedef struct Segment { // perhaps this should be per segment, not static static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette - static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000 - static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF + static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000 + static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF #ifndef WLED_DISABLE_MODE_BLEND static bool _modeBlend; // mode/effect blending semaphore #endif diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index bb260bf2e..617558ffa 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,10 +77,10 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); -CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); -uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment -uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); +uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment +uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -221,9 +221,9 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint switch (pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; - case 1: {//periodically replace palette with a random one + case 1: //randomly generated palette targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() - break;} + break; case 2: {//primary color only CRGB prim = gamma32(colors[0]); targetPalette = CRGBPalette16(prim); break;} @@ -452,24 +452,21 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u return targetPalette; } -// relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY) +// relies on WS2812FX::service() to call it for each frame void Segment::handleRandomPalette() { - // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) - // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY) - // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) - + // is it time to generate a new palette? if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { - _newRandomPalette = generateHarmonicRandomPalette(_randomPalette); + _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); _lastPaletteChange = millis()/1000U; - _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately + _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately } - if (strip.paletteFade) - { - if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) {//assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) - return; //not time to fade yet, delay the update - } - _lastPaletteBlend = millis(); + // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) + if (strip.paletteFade) { + // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) + // in reality there need to be 255 blends to fully blend two entirely different palettes + if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update + _lastPaletteBlend = millis(); } nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 53c0d5290..89b0d10b0 100755 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -395,6 +395,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { strip.setTransition(fadeTransition ? transitionDelayDefault : 0); CJSON(strip.paletteFade, light_tr["pal"]); CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); + CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]); JsonObject light_nl = light["nl"]; CJSON(nightlightMode, light_nl["mode"]); @@ -872,6 +873,7 @@ void serializeConfig() { light_tr["dur"] = transitionDelayDefault / 100; light_tr["pal"] = strip.paletteFade; light_tr[F("rpc")] = randomPaletteChangeTime; + light_tr[F("hrp")] = useHarmonicRandomPalette; JsonObject light_nl = light.createNestedObject("nl"); light_nl["mode"] = nightlightMode; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 2b24c718d..3ed54d959 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -91,12 +91,11 @@ void setRandomColor(byte* rgb) colorHStoRGB(lastRandomIndex*256,255,rgb); } -/* - *generates a random palette based on harmonic color theory - *takes a base palette as the input, it will choose one color of the base palette and keep it +/* + * generates a random palette based on harmonic color theory + * takes a base palette as the input, it will choose one color of the base palette and keep it */ - -CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) +CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep @@ -104,7 +103,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors - //only one brightness value number is allowed below 200, creating mostly bright palettes + //only one brightness value number is allowed below 200, creating mostly bright palettes for (int i = 0; i < 3; i++) { //generate three high values palettecolors[i].saturation = random8(200,255); @@ -114,8 +113,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) palettecolors[3].saturation = random8(20,255); palettecolors[3].value = random8(80,255); - - //shuffle the arrays + //shuffle the arrays for (int i = 3; i > 0; i--) { std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); @@ -151,17 +149,15 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) harmonics[2] = basehue + 265 + random8(10); break; - case 4: // tetradic + case 4: // tetradic harmonics[0] = basehue + 80 + random8(20); harmonics[1] = basehue + 170 + random8(20); harmonics[2] = basehue + random8(30)-15; break; } - - if (random8() < 128) //50:50 chance of shuffeling hues or keep the color order - { - //shuffle the hues: + if (random8() < 128) { + //50:50 chance of shuffling hues or keep the color order for (int i = 2; i > 0; i--) { std::swap(harmonics[i], harmonics[random8(i + 1)]); } @@ -170,36 +166,35 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) //now set the hues int j = 0; for (int i = 0; i < 4; i++) { - if(i==keepcolorposition) continue; //skip the base color + if (i==keepcolorposition) continue; //skip the base color palettecolors[i].hue = harmonics[j]; j++; - } + } bool makepastelpalette = false; - if (random8() < 25) {//~10% chance of desaturated 'pastel' colors - makepastelpalette = true; + if (random8() < 25) { //~10% chance of desaturated 'pastel' colors + makepastelpalette = true; } //apply saturation & gamma correction CRGB RGBpalettecolors[4]; for (int i = 0; i < 4; i++) { - if(makepastelpalette && palettecolors[i].saturation > 180) { + if (makepastelpalette && palettecolors[i].saturation > 180) { palettecolors[i].saturation -= 160; //desaturate all four colors } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB - RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]); + RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB } - return CRGBPalette16( RGBpalettecolors[0], - RGBpalettecolors[1], - RGBpalettecolors[2], - RGBpalettecolors[3]); + return CRGBPalette16(RGBpalettecolors[0], + RGBpalettecolors[1], + RGBpalettecolors[2], + RGBpalettecolors[3]); } CRGBPalette16 generateRandomPalette(void) //generate fully random palette { - return CRGBPalette16( - CHSV(random8(), random8(160, 255), random8(128, 255)), + return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255))); diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index e80cad741..b7992660e 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -848,6 +848,7 @@ Swap:
Random Cycle Palette Time: s
+ Use harmonic Random Cycle Palette:

Timed light

Default Duration: min
Default Target brightness:
diff --git a/wled00/set.cpp b/wled00/set.cpp index 49a54ab25..3be2fc38f 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -302,6 +302,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strip.paletteFade = request->hasArg(F("PF")); t = request->arg(F("TP")).toInt(); randomPaletteChangeTime = MIN(255,MAX(1,t)); + useHarmonicRandomPalette = request->hasArg(F("TH")); nightlightTargetBri = request->arg(F("TB")).toInt(); t = request->arg(F("TL")).toInt(); diff --git a/wled00/wled.h b/wled00/wled.h index b2f20c15f..3af970e0c 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -542,15 +542,16 @@ WLED_GLOBAL bool wasConnected _INIT(false); WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same // transitions -WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color -WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending -WLED_GLOBAL bool transitionActive _INIT(false); -WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration -WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) +WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color +WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending +WLED_GLOBAL bool transitionActive _INIT(false); +WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration +WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f -WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") -WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f +WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") +WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 3c7ebd2c3..a24d76fb2 100755 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -453,6 +453,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('v',SET_F("TD"),transitionDelayDefault); sappend('c',SET_F("PF"),strip.paletteFade); sappend('v',SET_F("TP"),randomPaletteChangeTime); + sappend('c',SET_F("TH"),useHarmonicRandomPalette); sappend('v',SET_F("BF"),briMultiplier); sappend('v',SET_F("TB"),nightlightTargetBri); sappend('v',SET_F("TL"),nightlightDelayMinsDefault);