From 70c73d2e0ece722ff0c6b1af9d5b1e817b224999 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sat, 6 Jun 2020 00:57:34 +0200 Subject: [PATCH] Lots of new effects! --- CHANGELOG.md | 7 ++ wled00/FX.cpp | 206 +++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 32 ++++++- wled00/FX_fcn.cpp | 36 +++---- wled00/usermod.cpp | 6 +- wled00/wled.h | 2 +- wled00/wled_eeprom.cpp | 6 +- 7 files changed, 268 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 475f81e2..c79a0805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ### Development versions after 0.10.0 release +#### Build 2006060 + +- Added five effects by Andrew Tuline (Phased, Phased Noise, Sine, Noise Pal and Twinkleup) +- Added two new effects by Aircoookie (Sunrise and Flow) +- Added US-style sequence to traffic light effect +- Merged pull request #964 adding 9 key IR remote + #### Build 2005280 - Added v2 usermod API diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c49c8304..878fd938 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -869,6 +869,7 @@ uint16_t WS2812FX::mode_traffic_light(void) { if (now - SEGENV.step > mdelay) { SEGENV.aux0++; + if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence if (SEGENV.aux0 > 3) SEGENV.aux0 = 0; SEGENV.step = now; } @@ -3334,3 +3335,208 @@ uint16_t WS2812FX::mode_solid_glitter() } return FRAMETIME; } + + +/* + * Mode simulates a gradual sunrise + */ +uint16_t WS2812FX::mode_sunrise() { + //speed 0 - static sun + //speed 1 - 120: sunrise time in minutes + //speed 121 - 240 : sunset time in minutes - 120; + //speed above: "breathing" rise and set + if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) { + SEGENV.step = millis(); //save starting time, millis() because now can change from sync + SEGENV.aux0 = SEGMENT.speed; + } + + fill(0); + uint16_t stage = 0xFFFF; + + uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds + + if (SEGMENT.speed > 120) { //quick sunrise and sunset + uint16_t counter = (now >> 1) * (((SEGMENT.speed -120) >> 1) +1); + stage = triwave16(counter); + } else if (SEGMENT.speed) { //sunrise + uint8_t durMins = SEGMENT.speed; + if (durMins > 60) durMins -= 60; + uint32_t s10Target = durMins * 600; + if (s10SinceStart > s10Target) s10SinceStart = s10Target; + stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF); + if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset + } + + for (uint16_t i = 0; i <= SEGLEN/2; i++) + { + //default palette is Fire + uint32_t c = color_from_palette(0, false, true, 255); //background + + uint16_t wave = triwave16((i * stage) / SEGLEN); + + wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15); + + if (wave > 240) { //clipped, full white sun + c = color_from_palette( 240, false, true, 255); + } else { //transition + c = color_from_palette(wave, false, true, 255); + } + setPixelColor(i, c); + setPixelColor(SEGLEN - i - 1, c); + } + + return FRAMETIME; +} + + +/* + * Effects by Andrew Tuline + */ +uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline. + + uint8_t allfreq = 16; // Base frequency. + //float* phasePtr = reinterpret_cast(SEGENV.step); // Phase change value gets calculated. + static float phase = 0;//phasePtr[0]; + uint8_t cutOff = (255-SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192). + uint8_t modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5). + + uint8_t index = now/64; // Set color rotation speed + phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4) + //phasePtr[0] = phase; + + for (int i = 0; i < SEGLEN; i++) { + if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. + uint16_t val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used. + if (modVal == 0) modVal = 1; + val += phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline. + uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave. + b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light. + setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b)); + index += 256 / SEGLEN; + } + + return FRAMETIME; +} + + + +uint16_t WS2812FX::mode_phased(void) { + return phased_base(0); +} + + + +uint16_t WS2812FX::mode_phased_noise(void) { + return phased_base(1); +} + + + +uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline. + random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through. + + for (int i = 0; i SEGMENT.intensity) pixBri = 0; + setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*20, false, PALETTE_SOLID_WRAP, 0), pixBri)); + } + + return FRAMETIME; +} + + +// Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls. +uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline. + uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30 + //#define scale 30 + + uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + + CRGBPalette16* palettes = reinterpret_cast(SEGENV.data); + + uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec + if (millis() - SEGENV.step > changePaletteMs) + { + SEGENV.step = millis(); + + uint8_t baseI = random8(); + palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); + } + + CRGB color; + + //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms) + nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations. + + if (SEGMENT.palette > 0) palettes[0] = currentPalette; + + for(int i = 0; i < SEGLEN; i++) { + uint8_t index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. + color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette. + setPixelColor(i, color.red, color.green, color.blue); + } + + SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. + + return FRAMETIME; +} + + +// Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline. +// SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff) +// +uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline + //#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0 + + uint16_t colorIndex = now /32;//(256 - SEGMENT.fft1); // Amount of colour change. + + SEGENV.step += SEGMENT.speed/16; // Speed of animation. + uint16_t freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. + + for (int i=0; i> 2) +1); + counter = counter >> 8; + } + + uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs + uint16_t zones = (SEGMENT.intensity * maxZones) >> 8; + if (zones & 0x01) zones++; //zones must be even + if (zones < 2) zones = 2; + uint16_t zoneLen = SEGLEN / zones; + uint16_t offset = (SEGLEN - zones * zoneLen) >> 1; + + fill(color_from_palette(-counter, false, true, 255)); + + for (uint16_t z = 0; z < zones; z++) + { + uint16_t pos = offset + z * zoneLen; + for (uint16_t i = 0; i < zoneLen; i++) + { + uint8_t colorIndex = (i * 255 / zoneLen) - counter; + uint16_t led = (z & 0x01) ? i : (zoneLen -1) -i; + if (IS_REVERSE) led = (zoneLen -1) -led; + setPixelColor(pos + led, color_from_palette(colorIndex, false, true, 255)); + } + } + + return FRAMETIME; +} diff --git a/wled00/FX.h b/wled00/FX.h index 728ab224..f807de62 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -98,7 +98,7 @@ #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED ) -#define MODE_COUNT 104 +#define MODE_COUNT 111 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -204,6 +204,13 @@ #define FX_MODE_PACIFICA 101 #define FX_MODE_CANDLE_MULTI 102 #define FX_MODE_SOLID_GLITTER 103 +#define FX_MODE_SUNRISE 104 +#define FX_MODE_PHASED 105 +#define FX_MODE_TWINKLEUP 106 +#define FX_MODE_NOISEPAL 107 +#define FX_MODE_SINEWAVE 108 +#define FX_MODE_PHASEDNOISE 109 +#define FX_MODE_FLOW 110 class WS2812FX { typedef uint16_t (WS2812FX::*mode_ptr)(void); @@ -396,6 +403,13 @@ class WS2812FX { _mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica; _mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi; _mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter; + _mode[FX_MODE_SUNRISE] = &WS2812FX::mode_sunrise; + _mode[FX_MODE_PHASED] = &WS2812FX::mode_phased; + _mode[FX_MODE_TWINKLEUP] = &WS2812FX::mode_twinkleup; + _mode[FX_MODE_NOISEPAL] = &WS2812FX::mode_noisepal; + _mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave; + _mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise; + _mode[FX_MODE_FLOW] = &WS2812FX::mode_flow; _brightness = DEFAULT_BRIGHTNESS; currentPalette = CRGBPalette16(CRGB::Black); @@ -461,7 +475,7 @@ class WS2812FX { uint32_t timebase, color_wheel(uint8_t), - color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255), + color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255), color_blend(uint32_t,uint32_t,uint8_t), gamma32(uint32_t), getLastShow(void), @@ -583,7 +597,14 @@ class WS2812FX { mode_heartbeat(void), mode_pacifica(void), mode_candle_multi(void), - mode_solid_glitter(void); + mode_solid_glitter(void), + mode_sunrise(void), + mode_phased(void), + mode_twinkleup(void), + mode_noisepal(void), + mode_sinewave(void), + mode_phased_noise(void), + mode_flow(void); private: NeoPixelWrapper *bus; @@ -630,7 +651,8 @@ class WS2812FX { running(uint32_t, uint32_t), tricolor_chase(uint32_t, uint32_t), twinklefox_base(bool), - spots_base(uint16_t); + spots_base(uint16_t), + phased_base(uint8_t); CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat); CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff); @@ -669,7 +691,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple", "Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst", "Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow", -"Heartbeat","Pacifica","Candle Multi", "Solid Glitter" +"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise","Flow" ])====="; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 3843a350..ea24d066 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -707,26 +707,28 @@ void WS2812FX::handle_palette(void) _segment_index_palette_last = _segment_index; byte paletteIndex = SEGMENT.palette; - if (SEGMENT.mode == FX_MODE_GLITTER && paletteIndex == 0) paletteIndex = 11; + if (paletteIndex == 0) //default palette. Differs depending on effect + { + switch (SEGMENT.mode) + { + case FX_MODE_FIRE_2012 : paletteIndex = 35; break; //heat palette + case FX_MODE_COLORWAVES : paletteIndex = 26; break; //landscape 33 + case FX_MODE_FILLNOISE8 : paletteIndex = 9; break; //ocean colors + case FX_MODE_NOISE16_1 : paletteIndex = 20; break; //Drywet + case FX_MODE_NOISE16_2 : paletteIndex = 43; break; //Blue cyan yellow + case FX_MODE_NOISE16_3 : paletteIndex = 35; break; //heat palette + case FX_MODE_NOISE16_4 : paletteIndex = 26; break; //landscape 33 + case FX_MODE_GLITTER : paletteIndex = 11; break; //rainbow colors + case FX_MODE_SUNRISE : paletteIndex = 35; break; //heat palette + case FX_MODE_FLOW : paletteIndex = 6; break; //party + } + } if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4; switch (paletteIndex) { - case 0: {//default palette. Differs depending on effect - switch (SEGMENT.mode) - { - case FX_MODE_FIRE_2012 : load_gradient_palette(22); break;//heat palette - case FX_MODE_COLORWAVES : load_gradient_palette(13); break;//landscape 33 - case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break; - case FX_MODE_NOISE16_1 : load_gradient_palette(17); break;//Drywet - case FX_MODE_NOISE16_2 : load_gradient_palette(30); break;//Blue cyan yellow - case FX_MODE_NOISE16_3 : load_gradient_palette(22); break;//heat palette - case FX_MODE_NOISE16_4 : load_gradient_palette(13); break;//landscape 33 - //case FX_MODE_GLITTER : targetPalette = RainbowColors_p; break; - - default: targetPalette = PartyColors_p; break;//palette, bpm - } - break;} + case 0: //default palette. Exceptions for specific effects above + targetPalette = PartyColors_p; break; case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments if (!singleSegmentMode) { @@ -778,7 +780,7 @@ void WS2812FX::handle_palette(void) case 12: //Rainbow stripe colors targetPalette = RainbowStripeColors_p; break; default: //progmem palettes - load_gradient_palette(SEGMENT.palette -13); + load_gradient_palette(paletteIndex -13); } if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode diff --git a/wled00/usermod.cpp b/wled00/usermod.cpp index 2c7c881f..3ffc86f9 100644 --- a/wled00/usermod.cpp +++ b/wled00/usermod.cpp @@ -1,9 +1,11 @@ #include "wled.h" /* - * This file allows you to add own functionality to WLED more easily + * This v1 usermod 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 const.h) - * bytes 2400+ are currently ununsed, but might be used for future wled features + * If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE) + * + * Consider the v2 usermod API if you need a more advanced feature set! */ //Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t) diff --git a/wled00/wled.h b/wled00/wled.h index cc35e34c..c393fa6f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2005280 +#define VERSION 2006060 // ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS). diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index a7afffe1..4e2a71ca 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -583,8 +583,10 @@ void loadSettingsFromEEPROM(bool first) EEPROM.write(2550, DMXStartLED); #endif - //user MOD memory - //2944 - 3071 reserved + //Usermod memory + //2551 - 2559 reserved for Usermods, usable by default + //2560 - 2943 usable, NOT reserved (need to increase EEPSIZE accordingly, new WLED core features may override this section) + //2944 - 3071 reserved for Usermods (need to increase EEPSIZE to 3072 in const.h) overlayCurrent = overlayDefault;