Configuration item for harmonic palettes

Comment cleanup
This commit is contained in:
Blaz Kristan 2024-02-06 11:06:23 +01:00
parent 66d9e8c038
commit 41e51bbeb5
8 changed files with 52 additions and 54 deletions

View File

@ -77,8 +77,8 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
uint16_t Segment::maxHeight = 1; uint16_t Segment::maxHeight = 1;
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment
uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only)
@ -221,9 +221,9 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint
switch (pal) { switch (pal) {
case 0: //default palette. Exceptions for specific effects above case 0: //default palette. Exceptions for specific effects above
targetPalette = PartyColors_p; break; 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() targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette()
break;} break;
case 2: {//primary color only case 2: {//primary color only
CRGB prim = gamma32(colors[0]); CRGB prim = gamma32(colors[0]);
targetPalette = CRGBPalette16(prim); break;} targetPalette = CRGBPalette16(prim); break;}
@ -452,23 +452,20 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u
return targetPalette; 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() { void Segment::handleRandomPalette() {
// just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) // is it time to generate a new palette?
// 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)
if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) {
_newRandomPalette = generateHarmonicRandomPalette(_randomPalette); _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
_lastPaletteChange = millis()/1000U; _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 palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls)
{ 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) // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
return; //not time to fade yet, delay the update // 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(); _lastPaletteBlend = millis();
} }
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);

View File

@ -395,6 +395,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
strip.setTransition(fadeTransition ? transitionDelayDefault : 0); strip.setTransition(fadeTransition ? transitionDelayDefault : 0);
CJSON(strip.paletteFade, light_tr["pal"]); CJSON(strip.paletteFade, light_tr["pal"]);
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]);
JsonObject light_nl = light["nl"]; JsonObject light_nl = light["nl"];
CJSON(nightlightMode, light_nl["mode"]); CJSON(nightlightMode, light_nl["mode"]);
@ -872,6 +873,7 @@ void serializeConfig() {
light_tr["dur"] = transitionDelayDefault / 100; light_tr["dur"] = transitionDelayDefault / 100;
light_tr["pal"] = strip.paletteFade; light_tr["pal"] = strip.paletteFade;
light_tr[F("rpc")] = randomPaletteChangeTime; light_tr[F("rpc")] = randomPaletteChangeTime;
light_tr[F("hrp")] = useHarmonicRandomPalette;
JsonObject light_nl = light.createNestedObject("nl"); JsonObject light_nl = light.createNestedObject("nl");
light_nl["mode"] = nightlightMode; light_nl["mode"] = nightlightMode;

View File

@ -92,10 +92,9 @@ void setRandomColor(byte* rgb)
} }
/* /*
*generates a random palette based on harmonic color theory * 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 * 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 CHSV palettecolors[4]; //array of colors for the new palette
@ -114,7 +113,6 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
palettecolors[3].saturation = random8(20,255); palettecolors[3].saturation = random8(20,255);
palettecolors[3].value = random8(80,255); palettecolors[3].value = random8(80,255);
//shuffle the arrays //shuffle the arrays
for (int i = 3; i > 0; i--) { for (int i = 3; i > 0; i--) {
std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation);
@ -158,10 +156,8 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
break; break;
} }
if (random8() < 128) {
if (random8() < 128) //50:50 chance of shuffeling hues or keep the color order //50:50 chance of shuffling hues or keep the color order
{
//shuffle the hues:
for (int i = 2; i > 0; i--) { for (int i = 2; i > 0; i--) {
std::swap(harmonics[i], harmonics[random8(i + 1)]); std::swap(harmonics[i], harmonics[random8(i + 1)]);
} }
@ -170,27 +166,27 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
//now set the hues //now set the hues
int j = 0; int j = 0;
for (int i = 0; i < 4; i++) { 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]; palettecolors[i].hue = harmonics[j];
j++; j++;
} }
bool makepastelpalette = false; bool makepastelpalette = false;
if (random8() < 25) {//~10% chance of desaturated 'pastel' colors if (random8() < 25) { //~10% chance of desaturated 'pastel' colors
makepastelpalette = true; makepastelpalette = true;
} }
//apply saturation & gamma correction //apply saturation & gamma correction
CRGB RGBpalettecolors[4]; CRGB RGBpalettecolors[4];
for (int i = 0; i < 4; i++) { 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 palettecolors[i].saturation -= 160; //desaturate all four colors
} }
RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB 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], return CRGBPalette16(RGBpalettecolors[0],
RGBpalettecolors[1], RGBpalettecolors[1],
RGBpalettecolors[2], RGBpalettecolors[2],
RGBpalettecolors[3]); RGBpalettecolors[3]);
@ -198,8 +194,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
CRGBPalette16 generateRandomPalette(void) //generate fully random palette CRGBPalette16 generateRandomPalette(void) //generate fully random palette
{ {
return CRGBPalette16( 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)),
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)));

View File

@ -848,6 +848,7 @@ Swap: <select id="xw${i}" name="XW${i}">
Palette transitions: <input type="checkbox" name="PF"><br> Palette transitions: <input type="checkbox" name="PF"><br>
</span> </span>
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br> <i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
<h3>Timed light</h3> <h3>Timed light</h3>
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br> Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br> Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>

View File

@ -302,6 +302,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
strip.paletteFade = request->hasArg(F("PF")); strip.paletteFade = request->hasArg(F("PF"));
t = request->arg(F("TP")).toInt(); t = request->arg(F("TP")).toInt();
randomPaletteChangeTime = MIN(255,MAX(1,t)); randomPaletteChangeTime = MIN(255,MAX(1,t));
useHarmonicRandomPalette = request->hasArg(F("TH"));
nightlightTargetBri = request->arg(F("TB")).toInt(); nightlightTargetBri = request->arg(F("TB")).toInt();
t = request->arg(F("TL")).toInt(); t = request->arg(F("TL")).toInt();

View File

@ -551,6 +551,7 @@ WLED_GLOBAL unsigned long transitionStartTime;
WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f 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 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 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 // nightlight
WLED_GLOBAL bool nightlightActive _INIT(false); WLED_GLOBAL bool nightlightActive _INIT(false);

View File

@ -453,6 +453,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("TD"),transitionDelayDefault); sappend('v',SET_F("TD"),transitionDelayDefault);
sappend('c',SET_F("PF"),strip.paletteFade); sappend('c',SET_F("PF"),strip.paletteFade);
sappend('v',SET_F("TP"),randomPaletteChangeTime); sappend('v',SET_F("TP"),randomPaletteChangeTime);
sappend('c',SET_F("TH"),useHarmonicRandomPalette);
sappend('v',SET_F("BF"),briMultiplier); sappend('v',SET_F("BF"),briMultiplier);
sappend('v',SET_F("TB"),nightlightTargetBri); sappend('v',SET_F("TB"),nightlightTargetBri);
sappend('v',SET_F("TL"),nightlightDelayMinsDefault); sappend('v',SET_F("TL"),nightlightDelayMinsDefault);