diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp index 333ad0a94..56fbc1182 100644 --- a/wled00/WS2812FX.cpp +++ b/wled00/WS2812FX.cpp @@ -1552,7 +1552,7 @@ uint16_t WS2812FX::mode_pride_2015(void) bri8 += (255 - brightdepth); CRGB newcolor = CHSV( hue8, sat8, bri8); - fastled_col = fastled_from_col(getPixelColor(i)); + fastled_col = col_to_crgb(getPixelColor(i)); nblend( fastled_col, newcolor, 64); setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -1570,7 +1570,7 @@ uint16_t WS2812FX::mode_juggle(void){ byte dothue = 0; for ( byte i = 0; i < 8; i++) { uint16_t index = SEGMENT.start + beatsin16(i + 7, 0, SEGLEN -1); - fastled_col = fastled_from_col(getPixelColor(index)); + fastled_col = col_to_crgb(getPixelColor(index)); fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(currentPalette, dothue, 255); setPixelColor(index, fastled_col.red, fastled_col.green, fastled_col.blue); dothue += 32; @@ -1696,7 +1696,7 @@ uint16_t WS2812FX::mode_colorwaves(void) bri8 += (255 - brightdepth); CRGB newcolor = ColorFromPalette(currentPalette, hue8, bri8); - fastled_col = fastled_from_col(getPixelColor(i)); + fastled_col = col_to_crgb(getPixelColor(i)); nblend(fastled_col, newcolor, 128); setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -1836,7 +1836,7 @@ uint16_t WS2812FX::mode_colortwinkle() CRGB fastled_col, prev; fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7); for( uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) { - fastled_col = fastled_from_col(getPixelColor(i)); + fastled_col = col_to_crgb(getPixelColor(i)); prev = fastled_col; if(_locked[i]) { CRGB incrementalColor = fastled_col; @@ -1848,7 +1848,7 @@ uint16_t WS2812FX::mode_colortwinkle() } setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); - if (fastled_from_col(getPixelColor(i)) == prev) //fix "stuck" pixels + if (col_to_crgb(getPixelColor(i)) == prev) //fix "stuck" pixels { fastled_col += fastled_col; setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2050,3 +2050,130 @@ uint16_t WS2812FX::mode_ripple() } return 20; } + + +// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a +// +// TwinkleFOX: Twinkling 'holiday' lights that fade in and out. +// Colors are chosen from a palette. Read more about this effect using the link above! + +// If COOL_LIKE_INCANDESCENT is set to 1, colors will +// fade out slighted 'reddened', similar to how +// incandescent bulbs change color as they get dim down. +#define COOL_LIKE_INCANDESCENT 1 + +CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt) +{ + // Overall twinkle speed (changed) + uint16_t ticks = ms / (32 - (SEGMENT.speed >> 3)); + uint8_t fastcycle8 = ticks; + uint16_t slowcycle16 = (ticks >> 8) + salt; + slowcycle16 += sin8(slowcycle16); + slowcycle16 = (slowcycle16 * 2053) + 1384; + uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); + + // Overall twinkle density. + // 0 (NONE lit) to 8 (ALL lit at once). + // Default is 5. + uint8_t twinkleDensity = (SEGMENT.intensity >> 5) +1; + + uint8_t bright = 0; + if (((slowcycle8 & 0x0E)/2) < twinkleDensity) { + uint8_t ph = fastcycle8; + // This is like 'triwave8', which produces a + // symmetrical up-and-down triangle sawtooth waveform, except that this + // function produces a triangle wave with a faster attack and a slower decay + if (ph < 86) { + bright = ph * 3; + } else { + ph -= 86; + bright = 255 - (ph + (ph/2)); + } + } + + uint8_t hue = slowcycle8 - salt; + CRGB c; + if (bright > 0) { + c = ColorFromPalette(currentPalette, hue, bright, NOBLEND); + if(COOL_LIKE_INCANDESCENT == 1) { + // This code takes a pixel, and if its in the 'fading down' + // part of the cycle, it adjusts the color a little bit like the + // way that incandescent bulbs fade toward 'red' as they dim. + if (fastcycle8 >= 128) + { + uint8_t cooling = (fastcycle8 - 128) >> 4; + c.g = qsub8(c.g, cooling); + c.b = qsub8(c.b, cooling * 2); + } + } + } else { + c = CRGB::Black; + } + return c; +} + +// This function loops over each pixel, calculates the +// adjusted 'clock' that this pixel should use, and calls +// "CalculateOneTwinkle" on each pixel. It then displays +// either the twinkle color of the background color, +// whichever is brighter. +uint16_t WS2812FX::mode_twinklefox() +{ + // "PRNG16" is the pseudorandom number generator + // It MUST be reset to the same starting value each time + // this function is called, so that the sequence of 'random' + // numbers that it generates is (paradoxically) stable. + uint16_t PRNG16 = 11337; + + uint32_t clock32 = millis(); + + // Set up the background color, "bg". + // if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of + // the current palette are identical, then a deeply faded version of + // that color is used for the background color + CRGB bg; + bg = col_to_crgb(SEGCOLOR(1)); + uint8_t bglight = bg.getAverageLight(); + if (bglight > 64) { + bg.nscale8_video(16); // very bright, so scale to 1/16th + } else if (bglight > 16) { + bg.nscale8_video(64); // not that bright, so scale to 1/4th + } else { + bg.nscale8_video(86); // dim, scale to 1/3rd. + } + + uint8_t backgroundBrightness = bg.getAverageLight(); + + for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) { + + PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number + uint16_t myclockoffset16= PRNG16; // use that number as clock offset + PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number + // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths) + uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08; + uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16; + uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel + + // We now have the adjusted 'clock' for this pixel, now we call + // the function that computes what color the pixel should be based + // on the "brightness = f( time )" idea. + CRGB c = twinklefox_one_twinkle(myclock30, myunique8); + + uint8_t cbright = c.getAverageLight(); + int16_t deltabright = cbright - backgroundBrightness; + if (deltabright >= 32 || (!bg)) { + // If the new pixel is significantly brighter than the background color, + // use the new color. + setPixelColor(i, c); + } else if (deltabright > 0) { + // If the new pixel is just slightly brighter than the background color, + // mix a blend of the new color and the background color + setPixelColor(i, color_blend(crgb_to_col(bg), crgb_to_col(c), deltabright * 8)); + } else { + // if the new pixel is not at all brighter than the background color, + // just use the background color. + setPixelColor(i, bg); + } + } + return 20; +} diff --git a/wled00/WS2812FX.h b/wled00/WS2812FX.h index 65c14e966..a1686fa8e 100644 --- a/wled00/WS2812FX.h +++ b/wled00/WS2812FX.h @@ -79,7 +79,7 @@ #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED ) -#define MODE_COUNT 80 +#define MODE_COUNT 81 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -162,6 +162,7 @@ #define FX_MODE_METEOR_SMOOTH 77 #define FX_MODE_RAILWAY 78 #define FX_MODE_RIPPLE 79 +#define FX_MODE_TWINKLEFOX 80 class WS2812FX { @@ -216,6 +217,7 @@ class WS2812FX { } segment_runtime; WS2812FX() { + //assign each member of the _mode[] array to its respective function reference _mode[FX_MODE_STATIC] = &WS2812FX::mode_static; _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; _mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe; @@ -296,6 +298,7 @@ class WS2812FX { _mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth; _mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway; _mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple; + _mode[FX_MODE_TWINKLEFOX] = &WS2812FX::mode_twinklefox; _brightness = DEFAULT_BRIGHTNESS; currentPalette = CRGBPalette16(CRGB::Black); @@ -335,6 +338,7 @@ class WS2812FX { trigger(void), setSegment(uint8_t n, uint16_t start, uint16_t stop), resetSegments(), + setPixelColor(uint16_t n, CRGB fastled), setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), show(void); @@ -361,6 +365,10 @@ class WS2812FX { gamma8(uint8_t), get_random_wheel_index(uint8_t); + uint16_t + ablMilliampsMax, + currentMilliamps; + uint32_t color_wheel(uint8_t), color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255), @@ -378,21 +386,6 @@ class WS2812FX { WS2812FX::Segment* getSegments(void); - // mode helper functions - uint16_t - ablMilliampsMax, - currentMilliamps, - blink(uint32_t, uint32_t, bool strobe, bool), - color_wipe(uint32_t, uint32_t, bool , bool), - scan(bool), - theater_chase(uint32_t, uint32_t, bool), - running_base(bool), - dissolve(uint32_t), - chase(uint32_t, uint32_t, uint32_t, bool), - gradient_base(bool), - running(uint32_t, uint32_t), - tricolor_chase(uint32_t, uint32_t); - // builtin modes uint16_t mode_static(void), @@ -475,12 +468,14 @@ class WS2812FX { mode_meteor(void), mode_meteor_smooth(void), mode_railway(void), - mode_ripple(void); + mode_ripple(void), + mode_twinklefox(void); private: NeoPixelWrapper *bus; - CRGB fastled_from_col(uint32_t); + uint32_t crgb_to_col(CRGB fastled); + CRGB col_to_crgb(uint32_t); CRGBPalette16 currentPalette; CRGBPalette16 targetPalette; @@ -505,6 +500,20 @@ class WS2812FX { mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element + // mode helper functions + uint16_t + blink(uint32_t, uint32_t, bool strobe, bool), + color_wipe(uint32_t, uint32_t, bool , bool), + scan(bool), + theater_chase(uint32_t, uint32_t, bool), + running_base(bool), + dissolve(uint32_t), + chase(uint32_t, uint32_t, uint32_t, bool), + gradient_base(bool), + running(uint32_t, uint32_t), + tricolor_chase(uint32_t, uint32_t); + + CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt); uint32_t _lastPaletteChange = 0; uint32_t _lastShow = 0; @@ -528,7 +537,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","In Out","In In", "Out Out","Out In","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", "Dual Scanner","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","BPM","Fill Noise","Noise 1", -"Noise 2","Noise 3","Noise 4","Colortwinkle","Lake","Meteor","Smooth Meteor","Railway","Ripple" +"Noise 2","Noise 3","Noise 4","Colortwinkle","Lake","Meteor","Smooth Meteor","Railway","Ripple","Twinklefox" ])====="; @@ -537,7 +546,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([ "Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash", "Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64", "Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn", -"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night" +"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery" ])====="; #endif diff --git a/wled00/WS2812FX_fcn.cpp b/wled00/WS2812FX_fcn.cpp index 4f93a25de..debbd3830 100644 --- a/wled00/WS2812FX_fcn.cpp +++ b/wled00/WS2812FX_fcn.cpp @@ -89,6 +89,10 @@ bool WS2812FX::modeUsesLock(uint8_t m) return false; } +void WS2812FX::setPixelColor(uint16_t n, CRGB fastled) { + setPixelColor(n, fastled.red, fastled.green, fastled.blue, 0); +} + void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { uint8_t w = (c >> 24) & 0xFF; uint8_t r = (c >> 16) & 0xFF; @@ -616,7 +620,7 @@ void WS2812FX::blur(uint8_t blur_amount) CRGB carryover = CRGB::Black; for(uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) { - CRGB cur = fastled_from_col(getPixelColor(i)); + CRGB cur = col_to_crgb(getPixelColor(i)); CRGB part = cur; part.nscale8(seep); cur.nscale8(keep); @@ -668,7 +672,13 @@ uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) { } -CRGB WS2812FX::fastled_from_col(uint32_t color) +uint32_t WS2812FX::crgb_to_col(CRGB fastled) +{ + return (((uint32_t)fastled.red << 16) | ((uint32_t)fastled.green << 8) | fastled.blue); +} + + +CRGB WS2812FX::col_to_crgb(uint32_t color) { CRGB fastled_col; fastled_col.red = (color >> 16 & 0xFF); @@ -720,11 +730,11 @@ void WS2812FX::handle_palette(void) _lastPaletteChange = millis(); } break;} case 2: {//primary color only - CRGB prim = fastled_from_col(SEGCOLOR(0)); + CRGB prim = col_to_crgb(SEGCOLOR(0)); targetPalette = CRGBPalette16(prim); break;} case 3: {//based on primary //considering performance implications - CRGB prim = fastled_from_col(SEGCOLOR(0)); + CRGB prim = col_to_crgb(SEGCOLOR(0)); CHSV prim_hsv = rgb2hsv_approximate(prim); targetPalette = CRGBPalette16( CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself @@ -733,12 +743,12 @@ void WS2812FX::handle_palette(void) CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself break;} case 4: {//primary + secondary - CRGB prim = fastled_from_col(SEGCOLOR(0)); - CRGB sec = fastled_from_col(SEGCOLOR(1)); + CRGB prim = col_to_crgb(SEGCOLOR(0)); + CRGB sec = col_to_crgb(SEGCOLOR(1)); targetPalette = CRGBPalette16(sec,prim); break;} case 5: {//based on primary + secondary - CRGB prim = fastled_from_col(SEGCOLOR(0)); - CRGB sec = fastled_from_col(SEGCOLOR(1)); + CRGB prim = col_to_crgb(SEGCOLOR(0)); + CRGB sec = col_to_crgb(SEGCOLOR(1)); targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;} case 6: //Party colors targetPalette = PartyColors_p; break; diff --git a/wled00/palettes.h b/wled00/palettes.h index 881acd08f..f2f66557d 100644 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -535,6 +535,16 @@ DEFINE_GRADIENT_PALETTE( April_Night_gp ) { 229, 223, 45, 72, //pink 244, 1, 5, 45, 255, 1, 5, 45}; + +DEFINE_GRADIENT_PALETTE( Orangery_gp ) { + 0, 255, 173, 23, + 35, 255, 82, 0, + 70, 196, 19, 10, + 105, 255, 140, 45, + 140, 255, 69, 0, + 175, 158, 13, 11, + 210, 241, 95, 17, + 255, 213, 37, 4}; // Single array of defined cpt-city color palettes. @@ -581,7 +591,8 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = { Blue_Cyan_Yellow_gp, //43-30 Yelblu Orange_Teal_gp, //44-31 Orange & Teal Tiamat_gp, //45-32 Tiamat - April_Night_gp //46-33 April Night + April_Night_gp, //46-33 April Night + Orangery_gp //47-34 Orangery }; diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 6aa5092fd..d0db6536c 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -98,7 +98,7 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1908251 +#define VERSION 1908301 char versionString[] = "0.8.5-dev";