2016-12-17 23:43:07 +01:00
/*
2019-02-09 16:37:20 +01:00
WS2812FX . cpp contains all effect methods
2016-12-17 23:43:07 +01:00
Harm Aldick - 2016
www . aldick . org
LICENSE
The MIT License ( MIT )
2018-09-04 15:51:38 +02:00
Copyright ( c ) 2016 Harm Aldick
2016-12-17 23:43:07 +01:00
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE .
2019-02-02 15:31:43 +01:00
Modified heavily for WLED
2016-12-17 23:43:07 +01:00
*/
2019-10-07 23:38:21 +02:00
# include "FX.h"
2016-12-17 23:43:07 +01:00
2019-02-02 15:31:43 +01:00
# define IBN 5100
2019-02-09 16:37:20 +01:00
# define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
2016-12-17 23:43:07 +01:00
/*
* No blinking . Just plain old static light .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_static ( void ) {
2019-05-22 00:23:09 +02:00
fill ( SEGCOLOR ( 0 ) ) ;
2019-10-03 16:33:37 +02:00
return ( SEGMENT . getOption ( 7 ) ) ? FRAMETIME : 500 ; //update faster if in transition
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Blink / strobe function
* Alternate between color1 and color2
* if ( strobe = = true ) then create a strobe effect
2019-10-05 01:56:55 +02:00
* NOTE : Maybe re - rework without timer
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : blink ( uint32_t color1 , uint32_t color2 , bool strobe , bool do_palette ) {
2019-10-02 01:17:26 +02:00
uint16_t stateTime = SEGENV . aux1 ;
uint32_t cycleTime = ( 255 - SEGMENT . speed ) * 20 ;
uint32_t onTime = 0 ;
uint32_t offTime = cycleTime ;
if ( ! strobe ) {
onTime = ( cycleTime * SEGMENT . intensity ) > > 8 ;
offTime = cycleTime - onTime ;
}
stateTime = ( ( SEGENV . aux0 & 1 ) = = 0 ) ? onTime : offTime ;
stateTime + = 20 ;
if ( now - SEGENV . step > stateTime )
{
SEGENV . aux0 + + ;
SEGENV . aux1 = stateTime ;
SEGENV . step = now ;
}
uint32_t color = ( ( SEGENV . aux0 & 1 ) = = 0 ) ? color1 : color2 ;
2018-10-24 02:06:07 +02:00
if ( color = = color1 & & do_palette )
{
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
}
2019-10-02 01:17:26 +02:00
} else fill ( color ) ;
2018-09-04 15:51:38 +02:00
2019-10-03 16:33:37 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Normal blinking . 50 % on / off time .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_blink ( void ) {
2019-05-22 00:23:09 +02:00
return blink ( SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) , false , true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Classic Blink effect . Cycling through the rainbow .
*/
uint16_t WS2812FX : : mode_blink_rainbow ( void ) {
2019-05-22 00:23:09 +02:00
return blink ( color_wheel ( SEGENV . call & 0xFF ) , SEGCOLOR ( 1 ) , false , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Classic Strobe effect .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_strobe ( void ) {
2019-05-22 00:23:09 +02:00
return blink ( SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) , true , true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Classic Strobe effect . Cycling through the rainbow .
*/
uint16_t WS2812FX : : mode_strobe_rainbow ( void ) {
2019-05-22 00:23:09 +02:00
return blink ( color_wheel ( SEGENV . call & 0xFF ) , SEGCOLOR ( 1 ) , true , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Color wipe function
* LEDs are turned on ( color1 ) in sequence , then turned off ( color2 ) in sequence .
* if ( bool rev = = true ) then LEDs are turned off in reverse order
2016-12-17 23:43:07 +01:00
*/
2019-10-03 20:57:22 +02:00
uint16_t WS2812FX : : color_wipe ( bool rev , bool useRandomColors ) {
2019-10-03 16:33:37 +02:00
uint32_t cycleTime = 1000 + ( 255 - SEGMENT . speed ) * 200 ;
uint32_t perc = now % cycleTime ;
uint16_t prog = ( perc * 65535 ) / cycleTime ;
bool back = ( prog > 32767 ) ;
if ( back ) {
prog - = 32767 ;
if ( SEGENV . step = = 0 ) SEGENV . step = 1 ;
2018-09-04 15:51:38 +02:00
} else {
2019-10-03 16:33:37 +02:00
if ( SEGENV . step = = 2 ) SEGENV . step = 3 ; //trigger color change
2016-12-17 23:43:07 +01:00
}
2019-10-03 20:57:22 +02:00
if ( useRandomColors ) {
if ( SEGENV . call = = 0 ) {
SEGENV . aux0 = random8 ( ) ;
SEGENV . step = 3 ;
}
if ( SEGENV . step = = 1 ) { //if flag set, change to new random color
SEGENV . aux1 = get_random_wheel_index ( SEGENV . aux0 ) ;
SEGENV . step = 2 ;
}
if ( SEGENV . step = = 3 ) {
SEGENV . aux0 = get_random_wheel_index ( SEGENV . aux1 ) ;
SEGENV . step = 0 ;
}
}
2019-11-29 18:53:01 +01:00
2019-10-03 16:33:37 +02:00
uint16_t ledIndex = ( prog * SEGLEN ) > > 15 ;
uint16_t rem = 0 ;
rem = ( prog * SEGLEN ) * 2 ; //mod 0xFFFF
rem / = ( SEGMENT . intensity + 1 ) ;
if ( rem > 255 ) rem = 255 ;
2019-10-03 20:57:22 +02:00
uint32_t col1 = useRandomColors ? color_wheel ( SEGENV . aux1 ) : SEGCOLOR ( 1 ) ;
2019-10-03 16:33:37 +02:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + )
{
2019-12-21 03:17:54 +01:00
uint16_t index = ( rev & & back ) ? SEGMENT . stop - 1 - i + SEGMENT . start : i ;
2019-10-03 20:57:22 +02:00
uint32_t col0 = useRandomColors ? color_wheel ( SEGENV . aux0 ) : color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ;
2019-10-03 16:33:37 +02:00
if ( i - SEGMENT . start < ledIndex )
{
2019-10-03 20:57:22 +02:00
setPixelColor ( index , back ? col1 : col0 ) ;
2019-10-03 16:33:37 +02:00
} else
{
2019-10-03 20:57:22 +02:00
setPixelColor ( index , back ? col0 : col1 ) ;
if ( i - SEGMENT . start = = ledIndex ) setPixelColor ( index , color_blend ( back ? col0 : col1 , back ? col1 : col0 , rem ) ) ;
2019-10-03 16:33:37 +02:00
}
}
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs one after another .
*/
uint16_t WS2812FX : : mode_color_wipe ( void ) {
2019-10-03 20:57:22 +02:00
return color_wipe ( false , false ) ;
2018-09-04 15:51:38 +02:00
}
/*
* Lights all LEDs one after another . Turns off opposite
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_color_sweep ( void ) {
2019-10-03 20:57:22 +02:00
return color_wipe ( true , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Turns all LEDs after each other to a random color .
* Then starts over with another color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_color_wipe_random ( void ) {
2019-10-03 20:57:22 +02:00
return color_wipe ( false , true ) ;
2018-09-04 15:51:38 +02:00
}
/*
* Random color introduced alternating from start and end of strip .
*/
uint16_t WS2812FX : : mode_color_sweep_random ( void ) {
2019-10-03 20:57:22 +02:00
return color_wipe ( true , true ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs in one random color up . Then switches them
* to the next random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_random_color ( void ) {
2019-10-03 16:33:37 +02:00
uint32_t cycleTime = 200 + ( 255 - SEGMENT . speed ) * 50 ;
uint32_t it = now / cycleTime ;
uint32_t rem = now % cycleTime ;
uint16_t fadedur = ( cycleTime * SEGMENT . intensity ) > > 8 ;
2016-12-17 23:43:07 +01:00
2019-10-03 16:33:37 +02:00
uint32_t fade = 255 ;
if ( fadedur ) {
fade = ( rem * 255 ) / fadedur ;
if ( fade > 255 ) fade = 255 ;
2016-12-17 23:43:07 +01:00
}
2019-10-03 16:33:37 +02:00
if ( SEGENV . call = = 0 ) {
SEGENV . aux0 = random8 ( ) ;
SEGENV . step = 2 ;
}
if ( it ! = SEGENV . step ) //new color
{
SEGENV . aux1 = SEGENV . aux0 ;
2019-10-03 20:57:22 +02:00
SEGENV . aux0 = get_random_wheel_index ( SEGENV . aux0 ) ; //aux0 will store our random color wheel index
2019-10-03 16:33:37 +02:00
SEGENV . step = it ;
}
fill ( color_blend ( color_wheel ( SEGENV . aux1 ) , color_wheel ( SEGENV . aux0 ) , fade ) ) ;
return FRAMETIME ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Lights every LED in a random color . Changes all LED at the same time
2019-10-05 01:56:55 +02:00
// * to new random colors.
2018-09-04 15:51:38 +02:00
*/
uint16_t WS2812FX : : mode_dynamic ( void ) {
2019-10-05 01:56:55 +02:00
if ( SEGENV . call = = 0 ) {
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) _locked [ i ] = random8 ( ) ;
}
uint32_t cycleTime = 50 + ( 255 - SEGMENT . speed ) * 15 ;
uint32_t it = now / cycleTime ;
if ( it ! = SEGENV . step ) //new color
{
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-10-05 01:56:55 +02:00
if ( random8 ( ) < = SEGMENT . intensity ) _locked [ i ] = random8 ( ) ;
2018-09-04 15:51:38 +02:00
}
2019-10-05 01:56:55 +02:00
SEGENV . step = it ;
}
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_wheel ( _locked [ i ] ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-10-05 01:56:55 +02:00
return FRAMETIME ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
2019-10-04 01:21:18 +02:00
* Does the " standby-breathing " of well known i - Devices .
2018-09-04 15:51:38 +02:00
*/
uint16_t WS2812FX : : mode_breath ( void ) {
2019-10-04 01:21:18 +02:00
uint16_t var = 0 ;
2019-12-04 12:15:12 +01:00
uint16_t counter = ( now * ( ( SEGMENT . speed > > 3 ) + 10 ) ) ;
2019-10-04 01:21:18 +02:00
counter = ( counter > > 2 ) + ( counter > > 4 ) ; //0-16384 + 0-2048
if ( counter < 16384 ) {
if ( counter > 8192 ) counter = 8192 - ( counter - 8192 ) ;
var = sin16 ( counter ) / 103 ; //close to parabolic in range 0-8192, max val. 23170
}
uint8_t lum = 30 + var ;
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_blend ( SEGCOLOR ( 1 ) , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) , lum ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-10-04 01:21:18 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fades the LEDs between two colors
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fade ( void ) {
2019-12-04 12:15:12 +01:00
uint16_t counter = ( now * ( ( SEGMENT . speed > > 3 ) + 10 ) ) ;
uint8_t lum = triwave16 ( counter ) > > 8 ;
2019-10-04 01:21:18 +02:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-10-04 01:21:18 +02:00
setPixelColor ( i , color_blend ( SEGCOLOR ( 1 ) , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) , lum ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-10-04 01:21:18 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-10-24 02:06:07 +02:00
* Scan mode parent function
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : scan ( bool dual )
{
2019-05-22 00:23:09 +02:00
if ( SEGENV . step > ( SEGLEN * 2 ) - 3 ) {
SEGENV . step = 0 ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
fill ( SEGCOLOR ( 1 ) ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
int led_offset = SEGENV . step - ( SEGLEN - 1 ) ;
2018-10-24 02:06:07 +02:00
led_offset = abs ( led_offset ) ;
uint16_t i = SEGMENT . start + led_offset ;
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
if ( dual ) {
2019-05-22 00:23:09 +02:00
uint16_t i2 = SEGMENT . start + SEGLEN - led_offset - 1 ;
2018-10-24 02:06:07 +02:00
setPixelColor ( i2 , color_from_palette ( i2 , true , PALETTE_SOLID_WRAP , 0 ) ) ;
}
2018-09-04 15:51:38 +02:00
2019-05-22 00:23:09 +02:00
SEGENV . step + + ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
2019-10-05 01:56:55 +02:00
//NOTE: add intensity (more than 1 pixel lit)
2016-12-17 23:43:07 +01:00
/*
2018-10-24 02:06:07 +02:00
* Runs a single pixel back and forth .
2016-12-17 23:43:07 +01:00
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : mode_scan ( void ) {
return scan ( false ) ;
}
2018-09-04 15:51:38 +02:00
2018-10-24 02:06:07 +02:00
/*
* Runs two pixel back and forth in opposite directions .
*/
uint16_t WS2812FX : : mode_dual_scan ( void ) {
return scan ( true ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Cycles all LEDs at once through a rainbow .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_rainbow ( void ) {
2019-10-05 01:56:55 +02:00
uint16_t counter = ( now * ( ( SEGMENT . speed > > 3 ) + 2 ) ) & 0xFFFF ;
counter = counter > > 8 ;
fill ( color_wheel ( counter ) ) ;
2016-12-17 23:43:07 +01:00
2019-10-05 01:56:55 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
* Cycles a rainbow over the entire string of LEDs .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_rainbow_cycle ( void ) {
2019-10-05 01:56:55 +02:00
uint16_t counter = ( now * ( ( SEGMENT . speed > > 3 ) + 2 ) ) & 0xFFFF ;
counter = counter > > 8 ;
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < SEGLEN ; i + + ) {
2019-10-05 01:56:55 +02:00
//intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16)
uint8_t index = ( i * ( 16 < < ( SEGMENT . intensity / 29 ) ) / SEGLEN ) + counter ;
setPixelColor ( SEGMENT . start + i , color_wheel ( index ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-10-05 01:56:55 +02:00
return FRAMETIME ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* theater chase function
*/
2018-10-24 02:06:07 +02:00
uint16_t WS2812FX : : theater_chase ( uint32_t color1 , uint32_t color2 , bool dopalette ) {
2019-11-03 01:18:02 +01:00
byte gap = 2 + ( ( 255 - SEGMENT . intensity ) > > 5 ) ;
uint32_t cycleTime = 50 + ( 255 - SEGMENT . speed ) * 2 ;
uint32_t it = now / cycleTime ;
if ( it ! = SEGENV . step ) //new color
{
SEGENV . aux0 = ( SEGENV . aux0 + 1 ) % gap ;
SEGENV . step = it ;
}
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < SEGLEN ; i + + ) {
2019-11-03 01:18:02 +01:00
if ( ( i % gap ) = = SEGENV . aux0 ) {
2018-10-24 02:06:07 +02:00
if ( dopalette )
{
setPixelColor ( SEGMENT . start + i , color_from_palette ( SEGMENT . start + i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else {
setPixelColor ( SEGMENT . start + i , color1 ) ;
}
2018-09-04 15:51:38 +02:00
} else {
setPixelColor ( SEGMENT . start + i , color2 ) ;
}
}
2019-11-03 01:18:02 +01:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
* Theatre - style crawling lights .
* Inspired by the Adafruit examples .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_theater_chase ( void ) {
2019-05-22 00:23:09 +02:00
return theater_chase ( SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) , true ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Theatre - style crawling lights with rainbow effect .
* Inspired by the Adafruit examples .
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_theater_chase_rainbow ( void ) {
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) & 0xFF ;
return theater_chase ( color_wheel ( SEGENV . step ) , SEGCOLOR ( 1 ) , false ) ;
2016-12-17 23:43:07 +01:00
}
/*
2019-02-05 21:53:39 +01:00
* Running lights effect with smooth sine transition base .
2016-12-17 23:43:07 +01:00
*/
2019-02-05 21:53:39 +01:00
uint16_t WS2812FX : : running_base ( bool saw ) {
2019-02-05 19:40:24 +01:00
uint8_t x_scale = SEGMENT . intensity > > 2 ;
2019-10-07 23:22:56 +02:00
uint32_t counter = ( now * SEGMENT . speed ) > > 9 ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < SEGLEN ; i + + ) {
2019-02-05 21:53:39 +01:00
uint8_t s = 0 ;
2019-10-07 23:22:56 +02:00
uint8_t a = i * x_scale - counter ;
2019-02-05 21:53:39 +01:00
if ( saw ) {
if ( a < 16 )
{
a = 192 + a * 8 ;
} else {
a = map ( a , 16 , 255 , 64 , 192 ) ;
}
}
s = sin8 ( a ) ;
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + i , color_blend ( color_from_palette ( SEGMENT . start + i , true , PALETTE_SOLID_WRAP , 0 ) , SEGCOLOR ( 1 ) , s ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-10-07 23:22:56 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2019-02-05 21:53:39 +01:00
* Running lights effect with smooth sine transition .
2016-12-17 23:43:07 +01:00
*/
2019-02-05 21:53:39 +01:00
uint16_t WS2812FX : : mode_running_lights ( void ) {
return running_base ( false ) ;
2016-12-17 23:43:07 +01:00
}
2019-02-05 21:53:39 +01:00
2018-09-04 15:51:38 +02:00
/*
2019-02-05 21:53:39 +01:00
* Running lights effect with sawtooth transition .
2018-09-04 15:51:38 +02:00
*/
2019-02-05 21:53:39 +01:00
uint16_t WS2812FX : : mode_saw ( void ) {
return running_base ( true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2019-02-05 21:53:39 +01:00
2016-12-17 23:43:07 +01:00
/*
* Blink several LEDs in random colors on , reset , repeat .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2019-02-05 21:53:39 +01:00
uint16_t WS2812FX : : mode_twinkle ( void ) {
2019-05-22 00:23:09 +02:00
if ( SEGENV . step = = 0 ) {
fill ( SEGCOLOR ( 1 ) ) ;
SEGENV . step = map ( SEGMENT . intensity , 0 , 255 , 1 , SEGLEN ) ; // make sure, at least one LED is on
2019-02-05 21:53:39 +01:00
}
2019-05-22 00:23:09 +02:00
uint16_t i = SEGMENT . start + random16 ( SEGLEN ) ;
2019-02-05 21:53:39 +01:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2019-05-22 00:23:09 +02:00
SEGENV . step - - ;
2019-02-05 21:53:39 +01:00
return 20 + ( 5 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
/*
2019-01-31 23:42:48 +01:00
* Dissolve function
2018-09-04 15:51:38 +02:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : dissolve ( uint32_t color ) {
2019-05-22 00:23:09 +02:00
bool wa = ( SEGCOLOR ( 1 ) ! = 0 & & _brightness < 255 ) ; //workaround, can't compare getPixel to color if not full brightness
2019-01-31 23:42:48 +01:00
2019-05-22 00:23:09 +02:00
for ( uint16_t j = 0 ; j < = SEGLEN / 15 ; j + + )
2019-01-31 23:42:48 +01:00
{
if ( random8 ( ) < = SEGMENT . intensity ) {
for ( uint8_t times = 0 ; times < 10 ; times + + ) //attempt to spawn a new pixel 5 times
{
2019-05-22 00:23:09 +02:00
uint16_t i = SEGMENT . start + random16 ( SEGLEN ) ;
if ( SEGENV . aux0 ) { //dissolve to primary/palette
if ( getPixelColor ( i ) = = SEGCOLOR ( 1 ) | | wa ) {
if ( color = = SEGCOLOR ( 0 ) )
2019-01-31 23:42:48 +01:00
{
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
} else { setPixelColor ( i , color ) ; }
break ; //only spawn 1 new pixel per frame per 50 LEDs
}
} else { //dissolve to secondary
2019-05-22 00:23:09 +02:00
if ( getPixelColor ( i ) ! = SEGCOLOR ( 1 ) ) { setPixelColor ( i , SEGCOLOR ( 1 ) ) ; break ; }
2019-01-31 23:42:48 +01:00
}
}
2018-10-24 02:06:07 +02:00
}
2016-12-17 23:43:07 +01:00
}
2019-01-31 23:42:48 +01:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . call > ( 255 - SEGMENT . speed ) + 15 )
2019-01-31 23:42:48 +01:00
{
2019-05-22 00:23:09 +02:00
SEGENV . aux0 = ! SEGENV . aux0 ;
SEGENV . call = 0 ;
2019-01-31 23:42:48 +01:00
}
2018-10-24 02:06:07 +02:00
2019-01-31 23:42:48 +01:00
return 20 ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
2019-01-31 23:42:48 +01:00
* Blink several LEDs on and then off
2018-09-04 15:51:38 +02:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : mode_dissolve ( void ) {
2019-05-22 00:23:09 +02:00
return dissolve ( SEGCOLOR ( 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
2019-01-31 23:42:48 +01:00
* Blink several LEDs on and then off in random colors
2016-12-17 23:43:07 +01:00
*/
2019-01-31 23:42:48 +01:00
uint16_t WS2812FX : : mode_dissolve_random ( void ) {
return dissolve ( color_wheel ( random8 ( ) ) ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Blinks one LED at a time .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_sparkle ( void ) {
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-12-06 01:44:45 +01:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
}
uint32_t cycleTime = 10 + ( 255 - SEGMENT . speed ) * 2 ;
uint32_t it = now / cycleTime ;
if ( it ! = SEGENV . step )
{
SEGENV . aux0 = random16 ( SEGLEN ) ; // aux0 stores the random led index
SEGENV . step = it ;
2018-10-24 02:06:07 +02:00
}
2019-12-06 01:44:45 +01:00
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + SEGENV . aux0 , SEGCOLOR ( 0 ) ) ;
2019-12-06 01:44:45 +01:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Lights all LEDs in the color . Flashes single white pixels randomly .
2016-12-17 23:43:07 +01:00
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_flash_sparkle ( void ) {
2019-12-06 01:44:45 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
if ( random8 ( 5 ) = = 0 ) {
2019-05-22 00:23:09 +02:00
SEGENV . aux0 = random16 ( SEGLEN ) ; // aux0 stores the random led index
setPixelColor ( SEGMENT . start + SEGENV . aux0 , SEGCOLOR ( 1 ) ) ;
2018-09-04 15:51:38 +02:00
return 20 ;
}
return 20 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2016-12-17 23:43:07 +01:00
}
/*
* Like flash sparkle . With more flash .
* Inspired by www . tweaking4all . com / hardware / arduino / adruino - led - strip - effects /
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_hyper_sparkle ( void ) {
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
if ( random8 ( 5 ) < 2 ) {
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < max ( 1 , SEGLEN / 3 ) ; i + + ) {
setPixelColor ( SEGMENT . start + random16 ( SEGLEN ) , SEGCOLOR ( 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 + ( uint16_t ) ( 255 - SEGMENT . speed ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Strobe effect with different strobe count and pause , controlled by speed .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_multi_strobe ( void ) {
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
uint16_t delay = 50 + 20 * ( uint16_t ) ( 255 - SEGMENT . speed ) ;
uint16_t count = 2 * ( ( SEGMENT . speed / 10 ) + 1 ) ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . step < count ) {
if ( ( SEGENV . step & 1 ) = = 0 ) {
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-05-22 00:23:09 +02:00
setPixelColor ( i , SEGCOLOR ( 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
delay = 50 ;
2017-11-28 15:09:58 +01:00
}
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % ( count + 1 ) ;
2018-09-04 15:51:38 +02:00
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-03-18 23:16:53 +01:00
* Android loading circle
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_android ( void ) {
2019-05-22 00:23:09 +02:00
if ( SEGENV . call = = 0 )
2018-09-04 15:51:38 +02:00
{
2019-05-22 00:23:09 +02:00
SEGENV . step = SEGMENT . start ;
2018-09-04 15:51:38 +02:00
}
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux1 > ( ( float ) SEGMENT . intensity / 255.0 ) * ( float ) SEGLEN )
2018-03-18 23:16:53 +01:00
{
2019-05-22 00:23:09 +02:00
SEGENV . aux0 = 1 ;
2018-03-18 23:16:53 +01:00
} else
{
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux1 < 2 ) SEGENV . aux0 = 0 ;
2018-03-18 23:16:53 +01:00
}
2018-09-04 15:51:38 +02:00
2019-05-22 00:23:09 +02:00
uint16_t a = SEGENV . step ;
2018-03-18 23:16:53 +01:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux0 = = 0 )
2018-03-18 23:16:53 +01:00
{
2019-05-22 00:23:09 +02:00
if ( SEGENV . call % 3 = = 1 ) { a + + ; }
else { SEGENV . aux1 + + ; }
2018-03-18 23:16:53 +01:00
} else
{
a + + ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . call % 3 ! = 1 ) SEGENV . aux1 - - ;
2018-03-18 23:16:53 +01:00
}
2019-03-05 10:59:15 +01:00
if ( a > = SEGMENT . stop ) a = SEGMENT . start ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
if ( a + SEGENV . aux1 < SEGMENT . stop )
2018-03-18 23:16:53 +01:00
{
2019-05-22 00:23:09 +02:00
for ( int i = a ; i < a + SEGENV . aux1 ; i + + ) {
setPixelColor ( i , SEGCOLOR ( 0 ) ) ;
2018-03-18 23:16:53 +01:00
}
} else
{
2019-03-05 10:59:15 +01:00
for ( int i = a ; i < SEGMENT . stop ; i + + ) {
2019-05-22 00:23:09 +02:00
setPixelColor ( i , SEGCOLOR ( 0 ) ) ;
2018-03-18 23:16:53 +01:00
}
2019-05-22 00:23:09 +02:00
for ( int i = SEGMENT . start ; i < SEGENV . aux1 - ( SEGMENT . stop - a ) ; i + + ) {
setPixelColor ( i , SEGCOLOR ( 0 ) ) ;
2018-03-18 23:16:53 +01:00
}
}
2019-05-22 00:23:09 +02:00
SEGENV . step = a ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
return 3 + ( ( 8 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / SEGLEN ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* color chase function .
* color1 = background color
* color2 and color3 = colors of two adjacent leds
2016-12-17 23:43:07 +01:00
*/
2019-02-11 23:49:04 +01:00
uint16_t WS2812FX : : chase ( uint32_t color1 , uint32_t color2 , uint32_t color3 , bool dopalette ) {
2019-05-22 00:23:09 +02:00
uint16_t a = SEGENV . step ;
uint16_t b = ( a + 1 ) % SEGLEN ;
uint16_t c = ( b + 1 ) % SEGLEN ;
2018-10-24 02:06:07 +02:00
2019-02-11 23:49:04 +01:00
if ( dopalette ) color1 = color_from_palette ( SEGMENT . start + a , true , PALETTE_SOLID_WRAP , 1 ) ;
2018-10-24 02:06:07 +02:00
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + a , color1 ) ;
setPixelColor ( SEGMENT . start + b , color2 ) ;
setPixelColor ( SEGMENT . start + c , color3 ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % SEGLEN ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Bicolor chase , more primary color .
*/
uint16_t WS2812FX : : mode_chase_color ( void ) {
2019-05-22 00:23:09 +02:00
return chase ( SEGCOLOR ( 1 ) , SEGCOLOR ( 0 ) , SEGCOLOR ( 0 ) , true ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-10-25 20:55:29 +02:00
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* Primary running followed by random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_random ( void ) {
2019-05-22 00:23:09 +02:00
if ( SEGENV . step = = 0 ) {
SEGENV . aux0 = get_random_wheel_index ( SEGENV . aux0 ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
return chase ( color_wheel ( SEGENV . aux0 ) , SEGCOLOR ( 0 ) , SEGCOLOR ( 0 ) , false ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Primary running on rainbow .
*/
uint16_t WS2812FX : : mode_chase_rainbow_white ( void ) {
2019-05-22 00:23:09 +02:00
uint16_t n = SEGENV . step ;
uint16_t m = ( SEGENV . step + 1 ) % SEGLEN ;
uint32_t color2 = color_wheel ( ( ( n * 256 / SEGLEN ) + ( SEGENV . call & 0xFF ) ) & 0xFF ) ;
uint32_t color3 = color_wheel ( ( ( m * 256 / SEGLEN ) + ( SEGENV . call & 0xFF ) ) & 0xFF ) ;
2018-09-04 15:51:38 +02:00
2019-05-22 00:23:09 +02:00
return chase ( SEGCOLOR ( 0 ) , color2 , color3 , false ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Red - Amber - Green - Blue lights running
*/
uint16_t WS2812FX : : mode_colorful ( void ) {
uint32_t cols [ ] { 0x00FF0000 , 0x00EEBB00 , 0x0000EE00 , 0x000077CC , 0x00FF0000 , 0x00EEBB00 , 0x0000EE00 } ;
if ( SEGMENT . intensity < 127 ) //pastel (easter) colors
{
cols [ 0 ] = 0x00FF8040 ;
cols [ 1 ] = 0x00E5D241 ;
cols [ 2 ] = 0x0077FF77 ;
cols [ 3 ] = 0x0077F0F0 ;
for ( uint8_t i = 4 ; i < 7 ; i + + ) cols [ i ] = cols [ i - 4 ] ;
}
2019-12-21 03:17:54 +01:00
uint32_t cycleTime = 50 + ( 15 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ;
uint32_t it = now / cycleTime ;
if ( it ! = SEGENV . step )
{
if ( SEGMENT . speed > 0 ) SEGENV . aux0 + + ;
if ( SEGENV . aux0 > 3 ) SEGENV . aux0 = 0 ;
SEGENV . step = it ;
}
uint16_t i = SEGMENT . start ;
for ( i ; i < SEGMENT . stop - 3 ; i + = 4 )
2018-09-04 15:51:38 +02:00
{
2019-12-21 03:17:54 +01:00
setPixelColor ( i , cols [ SEGENV . aux0 ] ) ;
setPixelColor ( i + 1 , cols [ SEGENV . aux0 + 1 ] ) ;
setPixelColor ( i + 2 , cols [ SEGENV . aux0 + 2 ] ) ;
setPixelColor ( i + 3 , cols [ SEGENV . aux0 + 3 ] ) ;
2018-09-04 15:51:38 +02:00
}
2019-03-05 10:59:15 +01:00
if ( i < SEGMENT . stop )
2018-09-04 15:51:38 +02:00
{
2019-12-21 03:17:54 +01:00
setPixelColor ( i , cols [ SEGENV . aux0 ] ) ;
2018-09-04 15:51:38 +02:00
2019-03-05 10:59:15 +01:00
if ( i + 1 < SEGMENT . stop )
2018-09-04 15:51:38 +02:00
{
2019-12-21 03:17:54 +01:00
setPixelColor ( i + 1 , cols [ SEGENV . aux0 + 1 ] ) ;
2018-09-04 15:51:38 +02:00
2019-03-05 10:59:15 +01:00
if ( i + 2 < SEGMENT . stop )
2018-09-04 15:51:38 +02:00
{
2019-12-21 03:17:54 +01:00
setPixelColor ( i + 2 , cols [ SEGENV . aux0 + 2 ] ) ;
2018-09-04 15:51:38 +02:00
}
}
}
2019-12-21 03:17:54 +01:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Emulates a traffic light .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_traffic_light ( void ) {
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + )
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ) ;
2018-09-04 15:51:38 +02:00
uint32_t mdelay = 500 ;
2019-03-05 10:59:15 +01:00
for ( int i = SEGMENT . start ; i < SEGMENT . stop - 2 ; i + = 3 )
2018-09-04 15:51:38 +02:00
{
2019-12-21 03:17:54 +01:00
switch ( SEGENV . aux0 )
2018-09-04 15:51:38 +02:00
{
case 0 : setPixelColor ( i , 0x00FF0000 ) ; mdelay = 150 + ( 100 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
case 1 : setPixelColor ( i , 0x00FF0000 ) ; mdelay = 150 + ( 20 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; setPixelColor ( i + 1 , 0x00EECC00 ) ; break ;
case 2 : setPixelColor ( i + 2 , 0x0000FF00 ) ; mdelay = 150 + ( 100 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
case 3 : setPixelColor ( i + 1 , 0x00EECC00 ) ; mdelay = 150 + ( 20 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) ; break ;
}
2016-12-17 23:43:07 +01:00
}
2019-12-21 03:17:54 +01:00
if ( now - SEGENV . step > mdelay )
{
SEGENV . aux0 + + ;
if ( SEGENV . aux0 > 3 ) SEGENV . aux0 = 0 ;
SEGENV . step = now ;
}
return FRAMETIME ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
2018-09-04 15:51:38 +02:00
/*
* Primary , secondary running on rainbow .
*/
uint16_t WS2812FX : : mode_chase_rainbow ( void ) {
2019-05-22 00:23:09 +02:00
uint8_t color_sep = 256 / SEGLEN ;
uint8_t color_index = SEGENV . call & 0xFF ;
uint32_t color = color_wheel ( ( ( SEGENV . step * color_sep ) + color_index ) & 0xFF ) ;
2018-09-04 15:51:38 +02:00
2019-05-22 00:23:09 +02:00
return chase ( color , SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) , 0 ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Sec flashes running on prim .
2016-12-17 23:43:07 +01:00
*/
2019-03-11 19:30:49 +01:00
# define FLASH_COUNT 4
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_flash ( void ) {
2019-05-22 00:23:09 +02:00
uint8_t flash_step = SEGENV . call % ( ( FLASH_COUNT * 2 ) + 1 ) ;
2016-12-17 23:43:07 +01:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
uint16_t delay = 10 + ( ( 30 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) / SEGLEN ) ;
2019-03-11 19:30:49 +01:00
if ( flash_step < ( FLASH_COUNT * 2 ) ) {
2016-12-17 23:43:07 +01:00
if ( flash_step % 2 = = 0 ) {
2019-05-22 00:23:09 +02:00
uint16_t n = SEGENV . step ;
uint16_t m = ( SEGENV . step + 1 ) % SEGLEN ;
setPixelColor ( SEGMENT . start + n , SEGCOLOR ( 1 ) ) ;
setPixelColor ( SEGMENT . start + m , SEGCOLOR ( 1 ) ) ;
2018-09-04 15:51:38 +02:00
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2018-09-04 15:51:38 +02:00
delay = 30 ;
2016-12-17 23:43:07 +01:00
}
} else {
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % SEGLEN ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Prim flashes running , followed by random color .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_chase_flash_random ( void ) {
2019-05-22 00:23:09 +02:00
uint8_t flash_step = SEGENV . call % ( ( FLASH_COUNT * 2 ) + 1 ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < SEGENV . step ; i + + ) {
setPixelColor ( SEGMENT . start + i , color_wheel ( SEGENV . aux0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
uint16_t delay = 1 + ( ( 10 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) / SEGLEN ) ;
2019-03-11 19:30:49 +01:00
if ( flash_step < ( FLASH_COUNT * 2 ) ) {
2019-05-22 00:23:09 +02:00
uint16_t n = SEGENV . step ;
uint16_t m = ( SEGENV . step + 1 ) % SEGLEN ;
2016-12-17 23:43:07 +01:00
if ( flash_step % 2 = = 0 ) {
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + n , SEGCOLOR ( 0 ) ) ;
setPixelColor ( SEGMENT . start + m , SEGCOLOR ( 0 ) ) ;
2018-09-04 15:51:38 +02:00
delay = 20 ;
2016-12-17 23:43:07 +01:00
} else {
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + n , color_wheel ( SEGENV . aux0 ) ) ;
setPixelColor ( SEGMENT . start + m , SEGCOLOR ( 1 ) ) ;
2018-09-04 15:51:38 +02:00
delay = 30 ;
2016-12-17 23:43:07 +01:00
}
} else {
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % SEGLEN ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . step = = 0 ) {
SEGENV . aux0 = get_random_wheel_index ( SEGENV . aux0 ) ;
2016-12-17 23:43:07 +01:00
}
}
2018-09-04 15:51:38 +02:00
return delay ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Alternating pixels running function .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : running ( uint32_t color1 , uint32_t color2 ) {
2019-10-07 23:22:56 +02:00
uint8_t pxw = 1 + ( SEGMENT . intensity > > 5 ) ;
uint32_t cycleTime = 35 + ( 255 - SEGMENT . speed ) ;
uint32_t it = now / cycleTime ;
if ( SEGMENT . speed = = 0 ) it = 0 ;
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < SEGLEN ; i + + ) {
2019-10-07 23:22:56 +02:00
if ( ( i + SEGENV . aux0 ) % ( pxw * 2 ) < pxw ) {
2019-05-22 00:23:09 +02:00
if ( color1 = = SEGCOLOR ( 0 ) )
2018-10-24 02:06:07 +02:00
{
2019-10-07 23:22:56 +02:00
setPixelColor ( SEGMENT . stop - i - 1 , color_from_palette ( SEGMENT . stop - i - 1 , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-10-24 02:06:07 +02:00
} else
{
2019-03-05 10:59:15 +01:00
setPixelColor ( SEGMENT . stop - i - 1 , color1 ) ;
2018-10-24 02:06:07 +02:00
}
2018-09-04 15:51:38 +02:00
} else {
2019-03-05 10:59:15 +01:00
setPixelColor ( SEGMENT . stop - i - 1 , color2 ) ;
2018-09-04 15:51:38 +02:00
}
2016-12-17 23:43:07 +01:00
}
2019-10-07 23:22:56 +02:00
if ( it ! = SEGENV . step )
{
SEGENV . aux0 = ( SEGENV . aux0 + 1 ) % ( pxw * 2 ) ;
SEGENV . step = it ;
}
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
/*
2018-10-24 02:06:07 +02:00
* Alternating color / sec pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_color ( void ) {
2019-05-22 00:23:09 +02:00
return running ( SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) ) ;
2018-04-01 00:08:50 +02:00
}
2018-09-04 15:51:38 +02:00
2018-04-01 00:08:50 +02:00
/*
2018-09-04 15:51:38 +02:00
* Alternating red / blue pixels running .
2018-04-01 00:08:50 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_red_blue ( void ) {
return running ( RED , BLUE ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Alternating red / green pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_merry_christmas ( void ) {
return running ( RED , GREEN ) ;
2016-12-17 23:43:07 +01:00
}
2019-02-10 23:05:06 +01:00
2016-12-17 23:43:07 +01:00
/*
2018-09-04 15:51:38 +02:00
* Alternating orange / purple pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_halloween ( void ) {
return running ( PURPLE , ORANGE ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Random colored pixels running .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_running_random ( void ) {
2019-05-22 00:23:09 +02:00
for ( uint16_t i = SEGLEN - 1 ; i > 0 ; i - - ) {
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start + i , getPixelColor ( SEGMENT . start + i - 1 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
if ( SEGENV . step = = 0 ) {
SEGENV . aux0 = get_random_wheel_index ( SEGENV . aux0 ) ;
setPixelColor ( SEGMENT . start , color_wheel ( SEGENV . aux0 ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + + ;
if ( SEGENV . step > ( ( 255 - SEGMENT . intensity ) > > 4 ) )
2019-02-10 23:05:06 +01:00
{
2019-05-22 00:23:09 +02:00
SEGENV . step = 0 ;
2019-02-10 23:05:06 +01:00
}
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* K . I . T . T .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_larson_scanner ( void ) {
2019-02-11 23:49:04 +01:00
fade_out ( SEGMENT . intensity ) ;
2016-12-17 23:43:07 +01:00
2018-10-24 02:06:07 +02:00
uint16_t index = 0 ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . step < SEGLEN ) {
index = SEGMENT . start + SEGENV . step ;
2018-09-04 15:51:38 +02:00
} else {
2019-05-22 00:23:09 +02:00
index = SEGMENT . start + ( ( SEGLEN * 2 ) - SEGENV . step ) - 2 ;
2016-12-17 23:43:07 +01:00
}
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % ( ( SEGLEN * 2 ) - 2 ) ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Firing comets from one end .
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_comet ( void ) {
2019-02-11 23:49:04 +01:00
fade_out ( SEGMENT . intensity ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
uint16_t index = SEGMENT . start + SEGENV . step ;
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % SEGLEN ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fireworks function .
2016-12-17 23:43:07 +01:00
*/
2019-02-11 23:49:04 +01:00
uint16_t WS2812FX : : mode_fireworks ( ) {
fade_out ( 0 ) ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . call = = 0 ) {
SEGENV . aux0 = UINT16_MAX ;
SEGENV . aux1 = UINT16_MAX ;
2019-02-11 23:49:04 +01:00
}
2019-05-22 00:23:09 +02:00
bool valid1 = ( SEGENV . aux0 < SEGMENT . stop & & SEGENV . aux0 > = SEGMENT . start ) ;
bool valid2 = ( SEGENV . aux1 < SEGMENT . stop & & SEGENV . aux1 > = SEGMENT . start ) ;
2019-02-11 23:49:04 +01:00
uint32_t sv1 = 0 , sv2 = 0 ;
2019-05-22 00:23:09 +02:00
if ( valid1 ) sv1 = getPixelColor ( SEGENV . aux0 ) ;
if ( valid2 ) sv2 = getPixelColor ( SEGENV . aux1 ) ;
2019-02-11 23:49:04 +01:00
blur ( 255 - SEGMENT . speed ) ;
2019-05-22 00:23:09 +02:00
if ( valid1 ) setPixelColor ( SEGENV . aux0 , sv1 ) ;
if ( valid2 ) setPixelColor ( SEGENV . aux1 , sv2 ) ;
2016-12-17 23:43:07 +01:00
2019-05-22 00:23:09 +02:00
for ( uint16_t i = 0 ; i < max ( 1 , SEGLEN / 20 ) ; i + + ) {
2019-02-11 23:49:04 +01:00
if ( random8 ( 129 - ( SEGMENT . intensity > > 1 ) ) = = 0 ) {
2019-05-22 00:23:09 +02:00
uint16_t index = SEGMENT . start + random ( SEGLEN ) ;
2019-02-11 23:49:04 +01:00
setPixelColor ( index , color_from_palette ( random8 ( ) , false , false , 0 ) ) ;
2019-05-22 00:23:09 +02:00
SEGENV . aux1 = SEGENV . aux0 ;
SEGENV . aux0 = index ;
2018-09-04 15:51:38 +02:00
}
}
2019-02-11 23:49:04 +01:00
return 22 ;
2016-12-17 23:43:07 +01:00
}
2019-02-11 23:49:04 +01:00
//Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
uint16_t WS2812FX : : mode_rain ( )
{
2019-05-22 00:23:09 +02:00
SEGENV . step + = 22 ;
if ( SEGENV . step > SPEED_FORMULA_L ) {
SEGENV . step = 0 ;
2019-02-11 23:49:04 +01:00
//shift all leds right
2019-03-05 10:59:15 +01:00
uint32_t ctemp = getPixelColor ( SEGMENT . stop - 1 ) ;
for ( uint16_t i = SEGMENT . stop - 1 ; i > SEGMENT . start ; i - - ) {
2019-02-11 23:49:04 +01:00
setPixelColor ( i , getPixelColor ( i - 1 ) ) ;
}
setPixelColor ( SEGMENT . start , ctemp ) ;
2019-05-22 00:23:09 +02:00
SEGENV . aux0 + + ;
SEGENV . aux1 + + ;
if ( SEGENV . aux0 = = 0 ) SEGENV . aux0 = UINT16_MAX ;
if ( SEGENV . aux1 = = 0 ) SEGENV . aux0 = UINT16_MAX ;
if ( SEGENV . aux0 = = SEGMENT . stop ) SEGENV . aux0 = SEGMENT . start ;
if ( SEGENV . aux1 = = SEGMENT . stop ) SEGENV . aux1 = SEGMENT . start ;
2019-02-11 23:49:04 +01:00
}
return mode_fireworks ( ) ;
2016-12-17 23:43:07 +01:00
}
/*
2018-09-04 15:51:38 +02:00
* Fire flicker function
2016-12-17 23:43:07 +01:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_fire_flicker ( void ) {
2019-05-22 00:23:09 +02:00
byte w = ( SEGCOLOR ( 0 ) > > 24 ) & 0xFF ;
byte r = ( SEGCOLOR ( 0 ) > > 16 ) & 0xFF ;
byte g = ( SEGCOLOR ( 0 ) > > 8 ) & 0xFF ;
byte b = ( SEGCOLOR ( 0 ) & 0xFF ) ;
2018-10-24 02:06:07 +02:00
byte lum = ( SEGMENT . palette = = 0 ) ? max ( w , max ( r , max ( g , b ) ) ) : 255 ;
lum / = ( ( ( 256 - SEGMENT . intensity ) / 16 ) + 1 ) ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-24 02:06:07 +02:00
byte flicker = random8 ( lum ) ;
if ( SEGMENT . palette = = 0 ) {
setPixelColor ( i , max ( r - flicker , 0 ) , max ( g - flicker , 0 ) , max ( b - flicker , 0 ) , max ( w - flicker , 0 ) ) ;
} else {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 , 255 - flicker ) ) ;
}
2016-12-17 23:43:07 +01:00
}
2019-05-21 18:50:56 +02:00
return 20 + random ( ( 255 - SEGMENT . speed ) , ( 2 * ( uint16_t ) ( 255 - SEGMENT . speed ) ) ) ;
2016-12-17 23:43:07 +01:00
}
2019-02-05 19:40:24 +01:00
/*
* Gradient run base function
*/
uint16_t WS2812FX : : gradient_base ( bool loading ) {
2019-05-22 00:23:09 +02:00
if ( SEGENV . call = = 0 ) SEGENV . step = 0 ;
2019-02-05 19:40:24 +01:00
float per , val ; //0.0 = sec 1.0 = pri
float brd = SEGMENT . intensity ;
if ( ! loading ) brd = SEGMENT . intensity / 2 ;
if ( brd < 1.0 ) brd = 1.0 ;
2019-05-22 00:23:09 +02:00
int pp = SEGENV . step ;
int p1 = pp - SEGLEN ;
int p2 = pp + SEGLEN ;
2019-02-05 19:40:24 +01:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + )
2019-02-05 19:40:24 +01:00
{
if ( loading )
{
val = abs ( ( ( i > pp ) ? p2 : pp ) - i ) ;
} else {
val = min ( abs ( pp - i ) , min ( abs ( p1 - i ) , abs ( p2 - i ) ) ) ;
}
per = val / brd ;
if ( per > 1.0 ) per = 1.0 ;
2019-12-21 03:17:54 +01:00
setPixelColor ( i , color_blend ( SEGCOLOR ( 0 ) , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) , per * 255 ) ) ;
2019-02-05 19:40:24 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + + ;
if ( SEGENV . step > = SEGMENT . stop ) SEGENV . step = SEGMENT . start ;
if ( SEGMENT . speed = = 0 ) SEGENV . step = SEGMENT . start + ( SEGLEN > > 1 ) ;
2019-02-05 19:40:24 +01:00
return SPEED_FORMULA_L ;
}
2018-03-18 23:16:53 +01:00
/*
* Gradient run
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_gradient ( void ) {
2019-02-05 19:40:24 +01:00
return gradient_base ( false ) ;
2018-03-18 23:16:53 +01:00
}
2016-12-31 17:36:07 +01:00
2018-09-04 15:51:38 +02:00
2018-03-18 23:16:53 +01:00
/*
* Gradient run with hard transition
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_loading ( void ) {
2019-02-05 19:40:24 +01:00
return gradient_base ( true ) ;
2018-09-04 15:51:38 +02:00
}
2019-12-04 12:15:12 +01:00
//American Police Light with all LEDs Red and Blue
uint16_t WS2812FX : : police_base ( uint32_t color1 , uint32_t color2 )
{
uint16_t counter = now * ( ( SEGMENT . speed > > 3 ) + 1 ) ;
uint16_t idexR = ( counter * SEGLEN ) > > 16 ;
if ( idexR > = SEGLEN ) idexR = 0 ;
uint16_t topindex = SEGLEN > > 1 ;
uint16_t idexB = idexR + topindex ;
if ( idexR > topindex ) idexB - = SEGLEN ;
if ( idexB > = SEGLEN ) idexB = 0 ; //otherwise overflow on odd number of LEDs
setPixelColor ( SEGMENT . start + idexR , color1 ) ;
setPixelColor ( SEGMENT . start + idexB , color2 ) ;
return FRAMETIME ;
2018-09-04 15:51:38 +02:00
}
2019-12-04 12:15:12 +01:00
//American Police Light with all LEDs Red and Blue
uint16_t WS2812FX : : mode_police_all ( )
{
return police_base ( RED , BLUE ) ;
2018-09-04 15:51:38 +02:00
}
2019-12-04 12:15:12 +01:00
//Police Lights Red and Blue
uint16_t WS2812FX : : mode_police ( )
{
fill ( SEGCOLOR ( 1 ) ) ;
return police_base ( RED , BLUE ) ;
}
//Police All with custom colors
uint16_t WS2812FX : : mode_two_areas ( )
{
return police_base ( SEGCOLOR ( 0 ) , SEGCOLOR ( 1 ) ) ;
}
//Police Lights with custom colors
uint16_t WS2812FX : : mode_two_dots ( )
{
fill ( SEGCOLOR ( 2 ) ) ;
uint32_t color2 = ( SEGCOLOR ( 1 ) = = SEGCOLOR ( 2 ) ) ? SEGCOLOR ( 0 ) : SEGCOLOR ( 1 ) ;
return police_base ( SEGCOLOR ( 0 ) , color2 ) ;
2018-09-04 15:51:38 +02:00
}
2018-10-25 20:55:29 +02:00
/*
* Tricolor chase function
*/
2019-02-11 23:49:04 +01:00
uint16_t WS2812FX : : tricolor_chase ( uint32_t color1 , uint32_t color2 ) {
2019-05-22 00:23:09 +02:00
uint16_t index = SEGENV . step % 6 ;
for ( uint16_t i = 0 ; i < SEGLEN ; i + + , index + + ) {
2018-10-25 20:55:29 +02:00
if ( index > 5 ) index = 0 ;
uint32_t color = color1 ;
2019-02-11 23:49:04 +01:00
if ( index > 3 ) color = color_from_palette ( i , true , PALETTE_SOLID_WRAP , 1 ) ;
2018-10-25 20:55:29 +02:00
else if ( index > 1 ) color = color2 ;
2019-03-05 10:59:15 +01:00
setPixelColor ( SEGMENT . stop - i - 1 , color ) ;
2018-10-25 20:55:29 +02:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + + ;
2018-10-25 20:55:29 +02:00
return 35 + ( ( 350 * ( uint32_t ) ( 255 - SEGMENT . speed ) ) / 255 ) ;
}
2018-09-04 15:51:38 +02:00
/*
2018-10-24 02:06:07 +02:00
* Alternating white / red / black pixels running . PLACEHOLDER
2018-09-04 15:51:38 +02:00
*/
uint16_t WS2812FX : : mode_circus_combustus ( void ) {
2019-02-11 23:49:04 +01:00
return tricolor_chase ( RED , WHITE ) ;
2018-10-25 20:55:29 +02:00
}
/*
* Tricolor chase mode
*/
uint16_t WS2812FX : : mode_tricolor_chase ( void ) {
2019-05-22 00:23:09 +02:00
return tricolor_chase ( SEGCOLOR ( 2 ) , SEGCOLOR ( 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
/*
* ICU mode
*/
uint16_t WS2812FX : : mode_icu ( void ) {
2019-05-22 00:23:09 +02:00
uint16_t dest = SEGENV . step & 0xFFFF ;
2018-09-08 16:21:44 +02:00
2019-05-22 00:23:09 +02:00
fill ( SEGCOLOR ( 1 ) ) ;
2018-10-24 02:06:07 +02:00
2019-05-22 00:23:09 +02:00
byte pindex = map ( dest , 0 , SEGLEN / 2 , 0 , 255 ) ;
2018-10-24 02:06:07 +02:00
uint32_t col = color_from_palette ( pindex , false , false , 0 ) ;
2018-09-04 15:51:38 +02:00
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + dest , col ) ;
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + dest + SEGLEN / 2 , col ) ;
2018-09-04 15:51:38 +02:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux0 = = dest ) { // pause between eye movements
2018-09-04 15:51:38 +02:00
if ( random8 ( 6 ) = = 0 ) { // blink once in a while
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + dest , SEGCOLOR ( 1 ) ) ;
setPixelColor ( SEGMENT . start + dest + SEGLEN / 2 , SEGCOLOR ( 1 ) ) ;
2018-09-04 15:51:38 +02:00
return 200 ;
2017-09-18 09:50:18 +02:00
}
2019-05-22 00:23:09 +02:00
SEGENV . aux0 = random16 ( SEGLEN / 2 ) ;
2019-01-31 23:42:48 +01:00
return 1000 + random16 ( 2000 ) ;
2017-09-18 09:50:18 +02:00
}
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux0 > SEGENV . step ) {
SEGENV . step + + ;
2018-09-04 15:51:38 +02:00
dest + + ;
2019-05-22 00:23:09 +02:00
} else if ( SEGENV . aux0 < SEGENV . step ) {
SEGENV . step - - ;
2018-09-04 15:51:38 +02:00
dest - - ;
2017-09-18 09:50:18 +02:00
}
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + dest , col ) ;
2019-05-22 00:23:09 +02:00
setPixelColor ( SEGMENT . start + dest + SEGLEN / 2 , col ) ;
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Custom mode by Aircoookie . Color Wipe , but with 3 colors
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_tricolor_wipe ( void )
{
2019-05-22 00:23:09 +02:00
if ( SEGENV . step < SEGLEN ) {
uint32_t led_offset = SEGENV . step ;
setPixelColor ( SEGMENT . start + led_offset , SEGCOLOR ( 0 ) ) ;
} else if ( SEGENV . step < SEGLEN * 2 ) {
uint32_t led_offset = SEGENV . step - SEGLEN ;
setPixelColor ( SEGMENT . start + led_offset , SEGCOLOR ( 1 ) ) ;
2018-09-04 15:51:38 +02:00
} else
{
2019-05-22 00:23:09 +02:00
uint32_t led_offset = SEGENV . step - SEGLEN * 2 ;
2018-10-24 02:06:07 +02:00
setPixelColor ( SEGMENT . start + led_offset , color_from_palette ( SEGMENT . start + led_offset , true , PALETTE_SOLID_WRAP , 2 ) ) ;
2017-09-18 09:50:18 +02:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % ( SEGLEN * 3 ) ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Fades between 3 colors
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/TriFade.h
* Modified by Aircoookie
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_tricolor_fade ( void )
{
2018-10-24 02:06:07 +02:00
uint32_t color1 = 0 , color2 = 0 ;
2018-10-25 20:55:29 +02:00
byte stage = 0 ;
2017-09-18 09:50:18 +02:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . step < 256 ) {
color1 = SEGCOLOR ( 0 ) ;
color2 = SEGCOLOR ( 1 ) ;
2018-10-25 20:55:29 +02:00
stage = 0 ;
2019-05-22 00:23:09 +02:00
} else if ( SEGENV . step < 512 ) {
color1 = SEGCOLOR ( 1 ) ;
color2 = SEGCOLOR ( 2 ) ;
2018-10-25 20:55:29 +02:00
stage = 1 ;
2018-10-24 02:06:07 +02:00
} else {
2019-05-22 00:23:09 +02:00
color1 = SEGCOLOR ( 2 ) ;
color2 = SEGCOLOR ( 0 ) ;
2018-10-25 20:55:29 +02:00
stage = 2 ;
2017-09-18 09:50:18 +02:00
}
2019-05-22 00:23:09 +02:00
byte stp = SEGENV . step % 256 ;
2018-10-24 02:06:07 +02:00
uint32_t color = 0 ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-10-25 20:55:29 +02:00
if ( stage = = 2 ) {
2018-10-24 02:06:07 +02:00
color = color_blend ( color_from_palette ( i , true , PALETTE_SOLID_WRAP , 2 ) , color2 , stp ) ;
2018-10-25 20:55:29 +02:00
} else if ( stage = = 1 ) {
2018-10-24 02:06:07 +02:00
color = color_blend ( color1 , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 2 ) , stp ) ;
} else {
color = color_blend ( color1 , color2 , stp ) ;
}
2018-09-04 15:51:38 +02:00
setPixelColor ( i , color ) ;
2017-09-18 09:50:18 +02:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + = 4 ;
if ( SEGENV . step > = 768 ) SEGENV . step = 0 ;
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
return 5 + ( ( uint32_t ) ( 255 - SEGMENT . speed ) / 10 ) ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Creates random comets
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_multi_comet ( void )
{
2019-02-11 23:49:04 +01:00
fade_out ( SEGMENT . intensity ) ;
2017-09-18 09:50:18 +02:00
2019-02-11 23:49:04 +01:00
static uint16_t comets [ ] = { UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX , UINT16_MAX } ;
2018-09-04 15:51:38 +02:00
2019-02-11 23:49:04 +01:00
for ( uint8_t i = 0 ; i < 8 ; i + + ) {
2019-05-22 00:23:09 +02:00
if ( comets [ i ] < SEGLEN ) {
2018-10-24 02:06:07 +02:00
uint16_t index = SEGMENT . start + comets [ i ] ;
2019-05-22 00:23:09 +02:00
if ( SEGCOLOR ( 2 ) ! = 0 )
2018-09-04 15:51:38 +02:00
{
2019-05-22 00:23:09 +02:00
setPixelColor ( index , i % 2 ? color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) : SEGCOLOR ( 2 ) ) ;
2018-09-04 15:51:38 +02:00
} else
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
comets [ i ] + + ;
2017-09-18 09:50:18 +02:00
} else {
2019-05-22 00:23:09 +02:00
if ( ! random ( SEGLEN ) ) {
2018-09-04 15:51:38 +02:00
comets [ i ] = 0 ;
}
2017-09-18 09:50:18 +02:00
}
}
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
}
2017-09-18 09:50:18 +02:00
2018-09-04 15:51:38 +02:00
/*
* Creates two Larson scanners moving in opposite directions
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/DualLarson.h
*/
uint16_t WS2812FX : : mode_dual_larson_scanner ( void ) {
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux0 )
2018-09-04 15:51:38 +02:00
{
2019-05-22 00:23:09 +02:00
SEGENV . step - - ;
2018-09-04 15:51:38 +02:00
} else
{
2019-05-22 00:23:09 +02:00
SEGENV . step + + ;
2017-09-18 09:50:18 +02:00
}
2019-02-11 23:49:04 +01:00
fade_out ( SEGMENT . intensity ) ;
2017-09-18 09:50:18 +02:00
2019-05-22 00:23:09 +02:00
uint16_t index = SEGMENT . start + SEGENV . step ;
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2019-05-22 00:23:09 +02:00
index = SEGMENT . stop - SEGENV . step - 1 ;
if ( SEGCOLOR ( 2 ) ! = 0 )
2018-09-04 15:51:38 +02:00
{
2019-05-22 00:23:09 +02:00
setPixelColor ( index , SEGCOLOR ( 2 ) ) ;
2018-09-04 15:51:38 +02:00
} else
{
2018-10-24 02:06:07 +02:00
setPixelColor ( index , color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) ) ;
2018-09-04 15:51:38 +02:00
}
2019-05-22 00:23:09 +02:00
if ( SEGENV . step > = SEGLEN - 1 | | SEGENV . step < = 0 )
SEGENV . aux0 = ! SEGENV . aux0 ;
2018-09-04 15:51:38 +02:00
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2018-09-04 15:51:38 +02:00
2017-09-18 09:50:18 +02:00
/*
2018-09-04 15:51:38 +02:00
* Running random pixels
* Custom mode by Keith Lord : https : //github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h
2017-09-18 09:50:18 +02:00
*/
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_random_chase ( void )
{
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . stop - 1 ; i > SEGMENT . start ; i - - ) {
2018-09-04 15:51:38 +02:00
setPixelColor ( i , getPixelColor ( i - 1 ) ) ;
2017-09-18 09:50:18 +02:00
}
2019-03-05 10:59:15 +01:00
uint32_t color = getPixelColor ( SEGMENT . start ) ;
2019-05-22 00:23:09 +02:00
if ( SEGLEN > 1 ) color = getPixelColor ( SEGMENT . start + 1 ) ;
2019-02-10 23:05:06 +01:00
uint8_t r = random8 ( 6 ) ! = 0 ? ( color > > 16 & 0xFF ) : random8 ( ) ;
uint8_t g = random8 ( 6 ) ! = 0 ? ( color > > 8 & 0xFF ) : random8 ( ) ;
uint8_t b = random8 ( 6 ) ! = 0 ? ( color & 0xFF ) : random8 ( ) ;
2018-09-04 15:51:38 +02:00
setPixelColor ( SEGMENT . start , r , g , b ) ;
2017-09-18 09:50:18 +02:00
2019-02-10 23:05:06 +01:00
return SPEED_FORMULA_L ;
2017-09-18 09:50:18 +02:00
}
2019-02-11 23:49:04 +01:00
2018-09-04 15:51:38 +02:00
typedef struct Oscillator {
int16_t pos ;
int8_t size ;
int8_t dir ;
int8_t speed ;
} oscillator ;
uint16_t WS2812FX : : mode_oscillate ( void )
2017-11-29 23:56:02 +01:00
{
2019-01-31 23:42:48 +01:00
static oscillator oscillators [ 2 ] = {
2019-05-22 00:23:09 +02:00
{ SEGLEN / 4 , SEGLEN / 8 , 1 , 1 } ,
{ SEGLEN / 4 * 2 , SEGLEN / 8 , - 1 , 1 }
//{SEGLEN/4*3, SEGLEN/8, 1, 2}
2018-09-04 15:51:38 +02:00
} ;
for ( int8_t i = 0 ; i < sizeof ( oscillators ) / sizeof ( oscillators [ 0 ] ) ; i + + ) {
oscillators [ i ] . pos + = oscillators [ i ] . dir * oscillators [ i ] . speed ;
if ( ( oscillators [ i ] . dir = = - 1 ) & & ( oscillators [ i ] . pos < = 0 ) ) {
oscillators [ i ] . pos = 0 ;
oscillators [ i ] . dir = 1 ;
2019-01-31 23:42:48 +01:00
oscillators [ i ] . speed = random8 ( 1 , 3 ) ;
2018-09-04 15:51:38 +02:00
}
2019-05-22 00:23:09 +02:00
if ( ( oscillators [ i ] . dir = = 1 ) & & ( oscillators [ i ] . pos > = ( SEGLEN - 1 ) ) ) {
oscillators [ i ] . pos = SEGLEN - 1 ;
2018-09-04 15:51:38 +02:00
oscillators [ i ] . dir = - 1 ;
2019-01-31 23:42:48 +01:00
oscillators [ i ] . speed = random8 ( 1 , 3 ) ;
2017-11-29 23:56:02 +01:00
}
}
2019-05-22 00:23:09 +02:00
for ( int16_t i = 0 ; i < SEGLEN ; i + + ) {
2018-09-04 15:51:38 +02:00
uint32_t color = BLACK ;
for ( int8_t j = 0 ; j < sizeof ( oscillators ) / sizeof ( oscillators [ 0 ] ) ; j + + ) {
if ( i > = oscillators [ j ] . pos - oscillators [ j ] . size & & i < = oscillators [ j ] . pos + oscillators [ j ] . size ) {
color = ( color = = BLACK ) ? SEGMENT . colors [ j ] : color_blend ( color , SEGMENT . colors [ j ] , 128 ) ;
}
}
setPixelColor ( SEGMENT . start + i , color ) ;
}
return 15 + ( uint32_t ) ( 255 - SEGMENT . speed ) ;
}
2018-09-06 02:05:56 +02:00
uint16_t WS2812FX : : mode_lightning ( void )
{
2019-10-03 16:33:37 +02:00
uint16_t ledstart = SEGMENT . start + random16 ( SEGLEN ) ; // Determine starting location of flash
uint16_t ledlen = random16 ( SEGMENT . stop - 1 - ledstart ) ; // Determine length of flash (not to go beyond NUM_LEDS-1)
2018-09-06 02:05:56 +02:00
uint8_t bri = 255 / random8 ( 1 , 3 ) ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . step = = 0 )
2018-09-06 02:05:56 +02:00
{
2019-05-22 00:23:09 +02:00
SEGENV . aux0 = random8 ( 3 , 3 + SEGMENT . intensity / 20 ) ; //number of flashes
2018-09-06 02:05:56 +02:00
bri = 52 ;
2019-05-22 00:23:09 +02:00
SEGENV . aux1 = 1 ;
2018-09-06 02:05:56 +02:00
}
2019-05-22 00:23:09 +02:00
fill ( SEGCOLOR ( 1 ) ) ;
2018-09-06 02:05:56 +02:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux1 ) {
2018-09-06 02:05:56 +02:00
for ( int i = ledstart ; i < ledstart + ledlen ; i + + )
{
2018-10-24 02:06:07 +02:00
if ( SEGMENT . palette = = 0 )
{
setPixelColor ( i , bri , bri , bri , bri ) ;
} else {
setPixelColor ( i , color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 , bri ) ) ;
}
2018-09-06 02:05:56 +02:00
}
2019-05-22 00:23:09 +02:00
SEGENV . aux1 = 0 ;
SEGENV . step + + ;
2018-09-06 02:05:56 +02:00
return random8 ( 4 , 10 ) ; // each flash only lasts 4-10 milliseconds
}
2019-05-22 00:23:09 +02:00
SEGENV . aux1 = 1 ;
if ( SEGENV . step = = 1 ) return ( 200 ) ; // longer delay until next flash after the leader
2018-09-06 02:05:56 +02:00
2019-05-22 00:23:09 +02:00
if ( SEGENV . step < = SEGENV . aux0 ) return ( 50 + random8 ( 100 ) ) ; // shorter delay between strokes
2018-09-06 02:05:56 +02:00
2019-05-22 00:23:09 +02:00
SEGENV . step = 0 ;
2018-09-06 02:05:56 +02:00
return ( random8 ( 255 - SEGMENT . speed ) * 100 ) ; // delay between strikes
}
2018-09-08 16:21:44 +02:00
// Pride2015
// Animated, ever-changing rainbows.
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
uint16_t WS2812FX : : mode_pride_2015 ( void )
{
uint16_t duration = 10 + SEGMENT . speed ;
2019-05-22 00:23:09 +02:00
uint16_t sPseudotime = SEGENV . step ;
uint16_t sHue16 = SEGENV . aux0 ;
2018-09-08 16:21:44 +02:00
uint8_t sat8 = beatsin88 ( 87 , 220 , 250 ) ;
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 1 , 3000 ) ;
sPseudotime + = duration * msmultiplier ;
sHue16 + = duration * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
CRGB fastled_col ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-09-08 16:21:44 +02:00
hue16 + = hueinc16 ;
uint8_t hue8 = hue16 > > 8 ;
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
CRGB newcolor = CHSV ( hue8 , sat8 , bri8 ) ;
2019-08-30 15:39:34 +02:00
fastled_col = col_to_crgb ( getPixelColor ( i ) ) ;
2018-09-08 16:21:44 +02:00
nblend ( fastled_col , newcolor , 64 ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
2019-05-22 00:23:09 +02:00
SEGENV . step = sPseudotime ;
SEGENV . aux0 = sHue16 ;
2018-09-08 16:21:44 +02:00
return 20 ;
}
2019-02-09 16:37:20 +01:00
//eight colored dots, weaving in and out of sync with each other
2018-09-04 15:51:38 +02:00
uint16_t WS2812FX : : mode_juggle ( void ) {
2019-02-11 23:49:04 +01:00
fade_out ( SEGMENT . intensity ) ;
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
byte dothue = 0 ;
for ( byte i = 0 ; i < 8 ; i + + ) {
2019-05-22 00:23:09 +02:00
uint16_t index = SEGMENT . start + beatsin16 ( i + 7 , 0 , SEGLEN - 1 ) ;
2019-08-30 15:39:34 +02:00
fastled_col = col_to_crgb ( getPixelColor ( index ) ) ;
2019-02-11 23:49:04 +01:00
fastled_col | = ( SEGMENT . palette = = 0 ) ? CHSV ( dothue , 220 , 255 ) : ColorFromPalette ( currentPalette , dothue , 255 ) ;
2018-09-04 15:51:38 +02:00
setPixelColor ( index , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
dothue + = 32 ;
2017-11-30 23:35:22 +01:00
}
2018-09-04 15:51:38 +02:00
return 10 + ( uint16_t ) ( 255 - SEGMENT . speed ) / 4 ;
2017-11-30 23:35:22 +01:00
}
2017-11-20 00:07:37 +01:00
2018-09-08 16:21:44 +02:00
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_palette ( )
2016-12-17 23:43:07 +01:00
{
2019-10-07 20:17:52 +02:00
uint16_t counter = 0 ;
if ( SEGMENT . speed ! = 0 )
{
counter = ( now * ( ( SEGMENT . speed > > 3 ) + 1 ) ) & 0xFFFF ;
counter = counter > > 8 ;
}
2018-09-11 00:20:12 +02:00
bool noWrap = ( paletteBlend = = 2 | | ( paletteBlend = = 0 & & SEGMENT . speed = = 0 ) ) ;
2019-12-06 01:44:45 +01:00
for ( uint16_t i = 0 ; i < SEGLEN ; i + + )
2016-12-31 00:38:51 +01:00
{
2019-10-07 20:17:52 +02:00
uint8_t colorIndex = ( i * 255 / SEGLEN ) - counter ;
2018-09-11 00:20:12 +02:00
if ( noWrap ) colorIndex = map ( colorIndex , 0 , 255 , 0 , 240 ) ; //cut off blend at palette "end"
2019-12-06 01:44:45 +01:00
setPixelColor ( SEGMENT . start + i , color_from_palette ( colorIndex , false , true , 255 ) ) ;
2016-12-31 00:38:51 +01:00
}
2019-10-07 20:17:52 +02:00
return FRAMETIME ;
2018-09-06 02:05:56 +02:00
}
2018-09-11 00:20:12 +02:00
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts 'up' and diffuses a little
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
// 4) The heat from each cell is rendered as a color into the leds array
// The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
2019-10-07 20:17:52 +02:00
// feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used
2018-09-11 00:20:12 +02:00
// in step 3 above) (Effect Intensity = Sparking).
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_fire_2012 ( )
2018-09-11 00:20:12 +02:00
{
2019-10-07 20:17:52 +02:00
uint32_t it = now > > 5 ; //div 32
2018-09-11 00:20:12 +02:00
2019-10-07 20:17:52 +02:00
if ( it ! = SEGENV . step )
{
// Step 1. Cool down every cell a little
for ( int i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
_locked [ i ] = qsub8 ( _locked [ i ] , random8 ( 0 , ( ( ( 20 + SEGMENT . speed / 3 ) * 10 ) / SEGLEN ) + 2 ) ) ;
}
2018-09-11 00:20:12 +02:00
2019-10-07 20:17:52 +02:00
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for ( int k = SEGMENT . stop - 1 ; k > = SEGMENT . start + 2 ; k - - ) {
_locked [ k ] = ( _locked [ k - 1 ] + _locked [ k - 2 ] + _locked [ k - 2 ] ) / 3 ;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if ( random8 ( ) < = SEGMENT . intensity ) {
int y = SEGMENT . start + random8 ( 7 ) ;
if ( y < SEGMENT . stop ) _locked [ y ] = qadd8 ( _locked [ y ] , random8 ( 160 , 255 ) ) ;
}
SEGENV . step = it ;
2018-09-11 00:20:12 +02:00
}
// Step 4. Map from heat cells to LED colors
2019-03-05 10:59:15 +01:00
for ( int j = SEGMENT . start ; j < SEGMENT . stop ; j + + ) {
2018-09-11 00:20:12 +02:00
CRGB color = ColorFromPalette ( currentPalette , min ( _locked [ j ] , 240 ) , 255 , LINEARBLEND ) ;
setPixelColor ( j , color . red , color . green , color . blue ) ;
}
2019-10-07 20:17:52 +02:00
return FRAMETIME ;
2018-09-11 00:20:12 +02:00
}
2018-09-08 16:21:44 +02:00
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_colorwaves ( )
2018-09-08 16:21:44 +02:00
{
uint16_t duration = 10 + SEGMENT . speed ;
2019-05-22 00:23:09 +02:00
uint16_t sPseudotime = SEGENV . step ;
uint16_t sHue16 = SEGENV . aux0 ;
2018-09-08 16:21:44 +02:00
uint8_t brightdepth = beatsin88 ( 341 , 96 , 224 ) ;
uint16_t brightnessthetainc16 = beatsin88 ( 203 , ( 25 * 256 ) , ( 40 * 256 ) ) ;
uint8_t msmultiplier = beatsin88 ( 147 , 23 , 60 ) ;
uint16_t hue16 = sHue16 ; //gHue * 256;
uint16_t hueinc16 = beatsin88 ( 113 , 300 , 1500 ) ;
sPseudotime + = duration * msmultiplier ;
sHue16 + = duration * beatsin88 ( 400 , 5 , 9 ) ;
uint16_t brightnesstheta16 = sPseudotime ;
CRGB fastled_col ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2018-09-08 16:21:44 +02:00
hue16 + = hueinc16 ;
2019-02-02 15:31:43 +01:00
uint8_t hue8 = hue16 > > 8 ;
2018-09-08 16:21:44 +02:00
uint16_t h16_128 = hue16 > > 7 ;
if ( h16_128 & 0x100 ) {
hue8 = 255 - ( h16_128 > > 1 ) ;
} else {
hue8 = h16_128 > > 1 ;
}
brightnesstheta16 + = brightnessthetainc16 ;
uint16_t b16 = sin16 ( brightnesstheta16 ) + 32768 ;
uint16_t bri16 = ( uint32_t ) ( ( uint32_t ) b16 * ( uint32_t ) b16 ) / 65536 ;
uint8_t bri8 = ( uint32_t ) ( ( ( uint32_t ) bri16 ) * brightdepth ) / 65536 ;
bri8 + = ( 255 - brightdepth ) ;
2019-02-10 23:05:06 +01:00
CRGB newcolor = ColorFromPalette ( currentPalette , hue8 , bri8 ) ;
2019-08-30 15:39:34 +02:00
fastled_col = col_to_crgb ( getPixelColor ( i ) ) ;
2018-09-08 16:21:44 +02:00
nblend ( fastled_col , newcolor , 128 ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
2019-05-22 00:23:09 +02:00
SEGENV . step = sPseudotime ;
SEGENV . aux0 = sHue16 ;
2018-09-08 16:21:44 +02:00
return 20 ;
}
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_bpm ( )
2018-09-06 02:05:56 +02:00
{
CRGB fastled_col ;
2019-10-07 20:17:52 +02:00
uint32_t stp = ( now / 20 ) & 0xFF ;
2018-09-06 02:05:56 +02:00
uint8_t beat = beatsin8 ( SEGMENT . speed , 64 , 255 ) ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-10-07 20:17:52 +02:00
fastled_col = ColorFromPalette ( currentPalette , stp + ( i * 2 ) , beat - stp + ( i * 10 ) ) ;
2018-09-06 02:05:56 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
2019-10-07 20:17:52 +02:00
return FRAMETIME ;
2016-12-17 23:43:07 +01:00
}
2018-09-04 15:51:38 +02:00
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_fillnoise8 ( )
2016-12-31 00:38:51 +01:00
{
2019-05-22 00:23:09 +02:00
if ( SEGENV . call = = 0 ) SEGENV . step = random16 ( 12345 ) ;
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-05-22 00:23:09 +02:00
uint8_t index = inoise8 ( i * SEGLEN , SEGENV . step + i * SEGLEN ) % 255 ;
2018-09-04 15:51:38 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , 255 , LINEARBLEND ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2016-12-31 00:38:51 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + = beatsin8 ( SEGMENT . speed , 1 , 6 ) ; //10,1,4
2016-12-31 00:38:51 +01:00
2018-09-06 02:05:56 +02:00
return 20 ;
2016-12-31 00:38:51 +01:00
}
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_noise16_1 ( )
2016-12-31 00:38:51 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 320 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2019-05-22 00:23:09 +02:00
SEGENV . step + = ( 1 + SEGMENT . speed / 16 ) ;
2016-12-31 00:38:51 +01:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2016-12-31 00:38:51 +01:00
2018-09-08 16:21:44 +02:00
uint16_t shift_x = beatsin8 ( 11 ) ; // the x position of the noise field swings @ 17 bpm
2019-05-22 00:23:09 +02:00
uint16_t shift_y = SEGENV . step / 42 ; // the y position becomes slowly incremented
2018-09-04 15:51:38 +02:00
uint16_t real_x = ( i + shift_x ) * scale ; // the x position of the noise field swings @ 17 bpm
uint16_t real_y = ( i + shift_y ) * scale ; // the y position becomes slowly incremented
2019-05-22 00:23:09 +02:00
uint32_t real_z = SEGENV . step ; // the z position becomes quickly incremented
2018-09-04 15:51:38 +02:00
uint8_t noise = inoise16 ( real_x , real_y , real_z ) > > 8 ; // get the noise data and scale it down
uint8_t index = sin8 ( noise * 3 ) ; // map LED color based on noise data
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , 255 , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2016-12-31 00:38:51 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2016-12-31 00:38:51 +01:00
}
2017-11-19 15:31:17 +01:00
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_noise16_2 ( )
2018-03-06 23:47:08 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 1000 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2019-10-07 20:17:52 +02:00
SEGENV . step + = ( 1 + ( SEGMENT . speed > > 1 ) ) ;
2018-03-06 23:47:08 +01:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2017-12-14 00:12:02 +01:00
2019-05-22 00:23:09 +02:00
uint16_t shift_x = SEGENV . step > > 6 ; // x as a function of time
uint16_t shift_y = SEGENV . step / 42 ;
2017-12-19 16:12:51 +01:00
2018-09-04 15:51:38 +02:00
uint32_t real_x = ( i + shift_x ) * scale ; // calculate the coordinates within the noise field
2017-12-14 00:12:02 +01:00
2018-09-08 16:21:44 +02:00
uint8_t noise = inoise16 ( real_x , 0 , 4223 ) > > 8 ; // get the noise data and scale it down
2017-12-14 00:12:02 +01:00
2018-09-04 15:51:38 +02:00
uint8_t index = sin8 ( noise * 3 ) ; // map led color based on noise data
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , noise , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2017-12-14 00:12:02 +01:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2017-11-29 23:56:02 +01:00
}
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_noise16_3 ( )
2017-11-29 23:56:02 +01:00
{
2018-09-08 16:21:44 +02:00
uint16_t scale = 800 ; // the "zoom factor" for the noise
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2019-05-22 00:23:09 +02:00
SEGENV . step + = ( 1 + SEGMENT . speed ) ;
2017-11-29 23:56:02 +01:00
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint16_t shift_x = 4223 ; // no movement along x and y
uint16_t shift_y = 1234 ;
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint32_t real_x = ( i + shift_x ) * scale ; // calculate the coordinates within the noise field
uint32_t real_y = ( i + shift_y ) * scale ; // based on the precalculated positions
2019-05-22 00:23:09 +02:00
uint32_t real_z = SEGENV . step * 8 ;
2017-11-29 23:56:02 +01:00
2018-09-08 16:21:44 +02:00
uint8_t noise = inoise16 ( real_x , real_y , real_z ) > > 8 ; // get the noise data and scale it down
2017-11-29 23:56:02 +01:00
2018-09-04 15:51:38 +02:00
uint8_t index = sin8 ( noise * 3 ) ; // map led color based on noise data
2017-11-29 23:56:02 +01:00
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index , noise , LINEARBLEND ) ; // With that value, look up the 8 bit colour palette value and assign it to the current LED.
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2018-04-13 00:28:29 +02:00
}
2018-09-04 15:51:38 +02:00
return 20 ;
2017-09-18 12:24:31 +02:00
}
2018-09-04 15:51:38 +02:00
//https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino
2019-10-07 20:17:52 +02:00
uint16_t WS2812FX : : mode_noise16_4 ( )
2017-09-27 21:45:58 +02:00
{
2018-09-04 15:51:38 +02:00
CRGB fastled_col ;
2019-05-22 00:23:09 +02:00
SEGENV . step + = SEGMENT . speed ;
2019-10-07 20:17:52 +02:00
uint32_t stp = ( now / 160 ) * SEGMENT . speed ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-10-07 20:17:52 +02:00
int16_t index = inoise16 ( uint32_t ( i - SEGMENT . start ) < < 12 , stp ) ;
2018-09-06 02:05:56 +02:00
fastled_col = ColorFromPalette ( currentPalette , index ) ;
2018-09-04 15:51:38 +02:00
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2017-12-14 00:12:02 +01:00
}
2019-10-07 20:17:52 +02:00
return FRAMETIME ;
2017-09-27 21:45:58 +02:00
}
2018-11-04 20:14:23 +01:00
2018-11-07 20:22:05 +01:00
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
2018-11-04 20:14:23 +01:00
uint16_t WS2812FX : : mode_colortwinkle ( )
{
CRGB fastled_col , prev ;
fract8 fadeUpAmount = 8 + ( SEGMENT . speed / 4 ) , fadeDownAmount = 5 + ( SEGMENT . speed / 7 ) ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-08-30 15:39:34 +02:00
fastled_col = col_to_crgb ( getPixelColor ( i ) ) ;
2018-11-04 20:14:23 +01:00
prev = fastled_col ;
if ( _locked [ i ] ) {
CRGB incrementalColor = fastled_col ;
incrementalColor . nscale8_video ( fadeUpAmount ) ;
fastled_col + = incrementalColor ;
if ( fastled_col . red = = 255 | | fastled_col . green = = 255 | | fastled_col . blue = = 255 ) {
_locked [ i ] = false ;
}
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
2019-08-30 15:39:34 +02:00
if ( col_to_crgb ( getPixelColor ( i ) ) = = prev ) //fix "stuck" pixels
2018-11-04 20:14:23 +01:00
{
fastled_col + = fastled_col ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
} else {
fastled_col . nscale8 ( 255 - fadeDownAmount ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
}
2018-12-16 20:38:00 +01:00
2019-05-22 00:23:09 +02:00
for ( uint16_t j = 0 ; j < = SEGLEN / 50 ; j + + )
2018-12-16 20:38:00 +01:00
{
if ( random8 ( ) < = SEGMENT . intensity ) {
for ( uint8_t times = 0 ; times < 5 ; times + + ) //attempt to spawn a new pixel 5 times
{
2019-05-22 00:23:09 +02:00
int i = SEGMENT . start + random16 ( SEGLEN ) ;
2018-12-16 20:38:00 +01:00
if ( getPixelColor ( i ) = = 0 ) {
fastled_col = ColorFromPalette ( currentPalette , random8 ( ) , 64 , NOBLEND ) ;
_locked [ i ] = true ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
break ; //only spawn 1 new pixel per frame per 50 LEDs
}
2018-11-04 20:14:23 +01:00
}
}
}
return 20 ;
}
2018-11-07 20:22:05 +01:00
//Calm effect, like a lake at night
uint16_t WS2812FX : : mode_lake ( ) {
uint8_t sp = SEGMENT . speed / 10 ;
int wave1 = beatsin8 ( sp + 2 , - 64 , 64 ) ;
int wave2 = beatsin8 ( sp + 1 , - 64 , 64 ) ;
uint8_t wave3 = beatsin8 ( sp + 2 , 0 , 80 ) ;
CRGB fastled_col ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + )
2018-11-07 20:22:05 +01:00
{
int index = cos8 ( ( i * 15 ) + wave1 ) / 2 + cubicwave8 ( ( i * 23 ) + wave2 ) / 2 ;
uint8_t lum = ( index > wave3 ) ? index - wave3 : 0 ;
fastled_col = ColorFromPalette ( currentPalette , map ( index , 0 , 255 , 0 , 240 ) , lum , LINEARBLEND ) ;
setPixelColor ( i , fastled_col . red , fastled_col . green , fastled_col . blue ) ;
}
2019-10-07 20:17:52 +02:00
return FRAMETIME ;
2018-11-07 20:22:05 +01:00
}
2018-11-20 20:32:21 +01:00
2018-11-28 12:24:32 +01:00
2018-11-20 20:32:21 +01:00
// meteor effect
2018-11-28 12:24:32 +01:00
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
2018-11-20 20:32:21 +01:00
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX : : mode_meteor ( ) {
2019-05-22 00:23:09 +02:00
byte meteorSize = 1 + SEGLEN / 10 ;
uint16_t in = SEGMENT . start + SEGENV . step ;
2018-11-28 12:24:32 +01:00
2018-11-20 20:32:21 +01:00
// fade all leds to colors[1] in LEDs one step
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-02-02 15:31:43 +01:00
if ( random8 ( ) < = 255 - SEGMENT . intensity )
2018-11-28 12:24:32 +01:00
{
byte meteorTrailDecay = 128 + random8 ( 127 ) ;
_locked [ i ] = scale8 ( _locked [ i ] , meteorTrailDecay ) ;
setPixelColor ( i , color_from_palette ( _locked [ i ] , false , true , 255 ) ) ;
2018-11-20 20:32:21 +01:00
}
}
// draw meteor
2018-11-28 12:24:32 +01:00
for ( int j = 0 ; j < meteorSize ; j + + ) {
uint16_t index = in + j ;
2019-03-05 10:59:15 +01:00
if ( in + j > = SEGMENT . stop ) {
2019-03-27 21:06:07 +01:00
index = SEGMENT . start + ( in + j - SEGMENT . stop ) ;
2018-11-20 20:32:21 +01:00
}
2018-11-28 12:24:32 +01:00
_locked [ index ] = 240 ;
setPixelColor ( index , color_from_palette ( _locked [ index ] , false , true , 255 ) ) ;
2018-11-20 20:32:21 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step = ( SEGENV . step + 1 ) % ( SEGLEN ) ;
2018-11-20 20:32:21 +01:00
return SPEED_FORMULA_L ;
}
2018-11-28 12:24:32 +01:00
2018-12-06 00:27:36 +01:00
2018-12-02 02:49:05 +01:00
// smooth meteor effect
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX : : mode_meteor_smooth ( ) {
2019-05-22 00:23:09 +02:00
byte meteorSize = 1 + SEGLEN / 10 ;
uint16_t in = map ( ( SEGENV . step > > 6 & 0xFF ) , 0 , 255 , SEGMENT . start , SEGMENT . stop - 1 ) ;
2018-12-02 02:49:05 +01:00
// fade all leds to colors[1] in LEDs one step
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
2019-02-02 15:31:43 +01:00
if ( _locked [ i ] ! = 0 & & random8 ( ) < = 255 - SEGMENT . intensity )
2018-12-02 02:49:05 +01:00
{
int change = 3 - random8 ( 12 ) ; //change each time between -8 and +3
_locked [ i ] + = change ;
if ( _locked [ i ] > 245 ) _locked [ i ] = 0 ;
if ( _locked [ i ] > 240 ) _locked [ i ] = 240 ;
setPixelColor ( i , color_from_palette ( _locked [ i ] , false , true , 255 ) ) ;
}
}
// draw meteor
for ( int j = 0 ; j < meteorSize ; j + + ) {
uint16_t index = in + j ;
2019-03-05 10:59:15 +01:00
if ( in + j > = SEGMENT . stop ) {
2019-03-27 21:06:07 +01:00
index = SEGMENT . start + ( in + j - SEGMENT . stop ) ;
2018-12-02 02:49:05 +01:00
}
setPixelColor ( index , color_blend ( getPixelColor ( index ) , color_from_palette ( 240 , false , true , 255 ) , 48 ) ) ;
2019-01-18 01:20:36 +01:00
_locked [ index ] = 240 ;
2018-12-02 02:49:05 +01:00
}
2019-05-22 00:23:09 +02:00
SEGENV . step + = SEGMENT . speed + 1 ;
2018-12-02 02:49:05 +01:00
return 20 ;
}
//Railway Crossing / Christmas Fairy lights
uint16_t WS2812FX : : mode_railway ( )
{
uint16_t dur = 40 + ( 255 - SEGMENT . speed ) * 10 ;
uint16_t rampdur = ( dur * SEGMENT . intensity ) > > 8 ;
2019-05-22 00:23:09 +02:00
if ( SEGENV . step > dur )
2018-12-02 02:49:05 +01:00
{
//reverse direction
2019-05-22 00:23:09 +02:00
SEGENV . step = 0 ;
SEGENV . aux0 = ! SEGENV . aux0 ;
2018-12-02 02:49:05 +01:00
}
uint8_t pos = 255 ;
if ( rampdur ! = 0 )
{
2019-05-22 00:23:09 +02:00
uint16_t p0 = ( SEGENV . step * 255 ) / rampdur ;
2018-12-02 02:49:05 +01:00
if ( p0 < 255 ) pos = p0 ;
}
2019-05-22 00:23:09 +02:00
if ( SEGENV . aux0 ) pos = 255 - pos ;
2019-03-05 10:59:15 +01:00
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + = 2 )
2018-12-02 02:49:05 +01:00
{
setPixelColor ( i , color_from_palette ( 255 - pos , false , false , 255 ) ) ;
2019-03-05 10:59:15 +01:00
if ( i < SEGMENT . stop - 1 )
2018-12-02 02:49:05 +01:00
{
setPixelColor ( i + 1 , color_from_palette ( pos , false , false , 255 ) ) ;
}
}
2019-10-07 20:17:52 +02:00
SEGENV . step + = FRAMETIME ;
return FRAMETIME ;
2018-12-02 02:49:05 +01:00
}
2019-01-31 23:42:48 +01:00
//Water ripple
//propagation velocity from speed
//drop rate from intensity
uint16_t WS2812FX : : mode_ripple ( )
{
2019-05-22 00:23:09 +02:00
uint16_t maxripples = SEGLEN / 4 ;
2019-01-31 23:42:48 +01:00
if ( maxripples = = 0 ) return mode_static ( ) ;
2019-05-22 00:23:09 +02:00
fill ( SEGCOLOR ( 1 ) ) ;
2019-01-31 23:42:48 +01:00
//draw wave
for ( uint16_t rippleI = 0 ; rippleI < maxripples ; rippleI + + )
{
2019-02-02 15:31:43 +01:00
uint16_t storeI = SEGMENT . start + 4 * rippleI ;
uint16_t ripplestate = _locked [ storeI ] ;
2019-01-31 23:42:48 +01:00
if ( ripplestate )
{
2019-02-02 15:31:43 +01:00
uint8_t rippledecay = ( SEGMENT . speed > > 4 ) + 1 ; //faster decay if faster propagation
uint16_t rippleorigin = ( _locked [ storeI + 1 ] < < 8 ) + _locked [ storeI + 2 ] ;
uint32_t col = color_from_palette ( _locked [ storeI + 3 ] , false , false , 255 ) ;
uint16_t propagation = ( ( ripplestate / rippledecay - 1 ) * SEGMENT . speed ) ;
int16_t propI = propagation > > 8 ;
uint8_t propF = propagation & 0xFF ;
int16_t left = rippleorigin - propI - 1 ;
uint8_t amp = ( ripplestate < 17 ) ? triwave8 ( ( ripplestate - 1 ) * 8 ) : map ( ripplestate , 17 , 255 , 255 , 2 ) ;
for ( int16_t v = left ; v < left + 4 ; v + + )
{
uint8_t mag = scale8 ( cubicwave8 ( ( propF > > 2 ) + ( v - left ) * 64 ) , amp ) ;
if ( v > = SEGMENT . start )
{
setPixelColor ( v , color_blend ( getPixelColor ( v ) , col , mag ) ) ;
}
int16_t w = left + propI * 2 + 3 - ( v - left ) ;
2019-03-05 10:59:15 +01:00
if ( w < SEGMENT . stop & & w > = SEGMENT . start )
2019-02-02 15:31:43 +01:00
{
setPixelColor ( w , color_blend ( getPixelColor ( w ) , col , mag ) ) ;
}
}
ripplestate + = rippledecay ;
_locked [ storeI ] = ( ripplestate > 254 ) ? 0 : ripplestate ;
} else //randomly create new wave
2019-01-31 23:42:48 +01:00
{
2019-02-02 15:31:43 +01:00
if ( random16 ( IBN + 10000 ) < = SEGMENT . intensity )
2019-01-31 23:42:48 +01:00
{
2019-02-02 15:31:43 +01:00
_locked [ storeI ] = 1 ;
2019-05-22 00:23:09 +02:00
uint16_t origin = SEGMENT . start + random16 ( SEGLEN ) ;
2019-02-02 15:31:43 +01:00
_locked [ storeI + 1 ] = origin > > 8 ;
_locked [ storeI + 2 ] = origin & 0xFF ;
2019-10-02 01:17:26 +02:00
_locked [ storeI + 3 ] = random8 ( ) ; //color
2019-01-31 23:42:48 +01:00
}
}
}
return 20 ;
}
2019-08-30 15:39:34 +02:00
// 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
2019-10-02 01:17:26 +02:00
CRGB WS2812FX : : twinklefox_one_twinkle ( uint32_t ms , uint8_t salt , bool cat )
2019-08-30 15:39:34 +02:00
{
// 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
2019-10-02 01:17:26 +02:00
if ( cat ) //twinklecat, variant where the leds instantly turn on
{
bright = 255 - ph ;
} else { //vanilla twinklefox
if ( ph < 86 ) {
bright = ph * 3 ;
} else {
ph - = 86 ;
bright = 255 - ( ph + ( ph / 2 ) ) ;
}
2019-08-30 15:39:34 +02:00
}
}
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.
2019-12-04 12:15:12 +01:00
uint16_t WS2812FX : : twinklefox_base ( bool cat )
2019-08-30 15:39:34 +02:00
{
// "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 ;
// 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 ;
2019-10-02 01:17:26 +02:00
uint32_t myclock30 = ( uint32_t ) ( ( now * myspeedmultiplierQ5_3 ) > > 3 ) + myclockoffset16 ;
2019-08-30 15:39:34 +02:00
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.
2019-10-02 01:17:26 +02:00
CRGB c = twinklefox_one_twinkle ( myclock30 , myunique8 , cat ) ;
2019-08-30 15:39:34 +02:00
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.
2019-10-07 20:17:52 +02:00
setPixelColor ( i , c . red , c . green , c . blue ) ;
2019-08-30 15:39:34 +02:00
} 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.
2019-10-07 20:17:52 +02:00
setPixelColor ( i , bg . r , bg . g , bg . b ) ;
2019-08-30 15:39:34 +02:00
}
}
2019-12-04 12:15:12 +01:00
return FRAMETIME ;
2019-10-02 01:17:26 +02:00
}
uint16_t WS2812FX : : mode_twinklefox ( )
{
2019-12-04 12:15:12 +01:00
return twinklefox_base ( false ) ;
2019-10-02 01:17:26 +02:00
}
uint16_t WS2812FX : : mode_twinklecat ( )
{
2019-12-04 12:15:12 +01:00
return twinklefox_base ( true ) ;
2019-10-02 01:17:26 +02:00
}
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
# define HALLOWEEN_EYE_SPACE 3
# define HALLOWEEN_EYE_WIDTH 1
uint16_t WS2812FX : : mode_halloween_eyes ( )
{
uint16_t eyeLength = ( 2 * HALLOWEEN_EYE_WIDTH ) + HALLOWEEN_EYE_SPACE ;
if ( eyeLength > SEGLEN ) return mode_static ( ) ; //bail if segment too short
fill ( SEGCOLOR ( 1 ) ) ; //fill background
uint8_t state = SEGENV . aux1 > > 8 ;
uint16_t stateTime = SEGENV . call ;
if ( stateTime = = 0 ) stateTime = 2000 ;
if ( state = = 0 ) { //spawn eyes
2019-10-03 16:33:37 +02:00
SEGENV . aux0 = random16 ( SEGMENT . start , SEGMENT . stop - eyeLength ) ; //start pos
2019-10-02 01:17:26 +02:00
SEGENV . aux1 = random8 ( ) ; //color
state = 1 ;
}
if ( state < 2 ) { //fade eyes
uint16_t startPos = SEGENV . aux0 ;
uint16_t start2ndEye = startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE ;
uint32_t fadestage = ( now - SEGENV . step ) * 255 / stateTime ;
if ( fadestage > 255 ) fadestage = 255 ;
uint32_t c = color_blend ( color_from_palette ( SEGENV . aux1 & 0xFF , false , false , 0 ) , SEGCOLOR ( 1 ) , fadestage ) ;
for ( uint16_t i = 0 ; i < HALLOWEEN_EYE_WIDTH ; i + + )
{
setPixelColor ( startPos + i , c ) ;
setPixelColor ( start2ndEye + i , c ) ;
}
}
if ( now - SEGENV . step > stateTime )
{
state + + ;
if ( state > 2 ) state = 0 ;
if ( state < 2 )
{
stateTime = 100 + ( 255 - SEGMENT . intensity ) * 10 ; //eye fade time
} else {
uint16_t eyeOffTimeBase = ( 255 - SEGMENT . speed ) * 10 ;
2019-10-03 16:33:37 +02:00
stateTime = eyeOffTimeBase + random16 ( eyeOffTimeBase ) ;
2019-10-02 01:17:26 +02:00
}
SEGENV . step = now ;
SEGENV . call = stateTime ;
}
SEGENV . aux1 = ( SEGENV . aux1 & 0xFF ) + ( state < < 8 ) ; //save state
2019-10-03 16:33:37 +02:00
return FRAMETIME ;
2019-08-30 15:39:34 +02:00
}
2019-11-18 12:29:36 +01:00
//Speed slider sets amount of LEDs lit, intensity sets unlit
uint16_t WS2812FX : : mode_static_pattern ( )
{
uint16_t lit = 1 + SEGMENT . speed ;
uint16_t unlit = 1 + SEGMENT . intensity ;
bool drawingLit = true ;
uint16_t cnt = 0 ;
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
setPixelColor ( i , ( drawingLit ) ? color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) : SEGCOLOR ( 1 ) ) ;
cnt + + ;
if ( cnt > = ( ( drawingLit ) ? lit : unlit ) ) {
cnt = 0 ;
drawingLit = ! drawingLit ;
}
}
return FRAMETIME ;
}
2019-11-29 18:53:01 +01:00
uint16_t WS2812FX : : mode_tri_static_pattern ( )
{
uint8_t segSize = ( SEGMENT . intensity > > 5 ) + 1 ;
uint8_t currSeg = 0 ;
uint16_t currSegCount = 0 ;
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
if ( currSeg % 3 = = 0 ) {
setPixelColor ( i , SEGCOLOR ( 0 ) ) ;
} else if ( currSeg % 3 = = 1 ) {
setPixelColor ( i , SEGCOLOR ( 1 ) ) ;
} else {
setPixelColor ( i , ( SEGCOLOR ( 2 ) > 0 ? SEGCOLOR ( 2 ) : WHITE ) ) ;
}
currSegCount + = 1 ;
if ( currSegCount > = segSize ) {
currSeg + = 1 ;
currSegCount = 0 ;
}
}
return FRAMETIME ;
}
2019-11-22 19:19:48 +01:00
2019-12-04 12:15:12 +01:00
uint16_t WS2812FX : : spots_base ( uint16_t threshold )
{
fill ( SEGCOLOR ( 1 ) ) ;
uint16_t maxZones = SEGLEN > > 2 ;
uint16_t zones = 1 + ( ( SEGMENT . intensity * maxZones ) > > 8 ) ;
uint16_t zoneLen = SEGLEN / zones ;
uint16_t offset = ( SEGLEN - zones * zoneLen ) > > 1 ;
2019-11-22 19:19:48 +01:00
2019-12-04 12:15:12 +01:00
for ( uint16_t z = 0 ; z < zones ; z + + )
{
uint16_t pos = offset + z * zoneLen ;
for ( uint16_t i = 0 ; i < zoneLen ; i + + )
{
uint16_t wave = triwave16 ( ( i * 0xFFFF ) / zoneLen ) ;
if ( wave > threshold ) {
uint16_t index = SEGMENT . start + pos + i ;
uint8_t s = ( wave - threshold ) * 255 / ( 0xFFFF - threshold ) ;
setPixelColor ( index , color_blend ( color_from_palette ( index , true , PALETTE_SOLID_WRAP , 0 ) , SEGCOLOR ( 1 ) , 255 - s ) ) ;
}
}
}
return FRAMETIME ;
2019-11-22 19:19:48 +01:00
}
2019-11-25 01:20:03 +01:00
2019-12-04 12:15:12 +01:00
//Intensity slider sets number of "lights", speed sets LEDs per light
uint16_t WS2812FX : : mode_spots ( )
2019-11-22 19:19:48 +01:00
{
2019-12-04 12:15:12 +01:00
return spots_base ( ( 255 - SEGMENT . speed ) < < 8 ) ;
2019-11-25 01:20:03 +01:00
}
2019-11-22 19:19:48 +01:00
2019-11-18 12:29:36 +01:00
2019-12-04 12:15:12 +01:00
//Intensity slider sets number of "lights", LEDs per light fade in and out
uint16_t WS2812FX : : mode_spots_fade ( )
2019-11-18 12:29:36 +01:00
{
2019-12-04 12:15:12 +01:00
uint16_t counter = now * ( ( SEGMENT . speed > > 2 ) + 8 ) ;
uint16_t t = triwave16 ( counter ) ;
uint16_t tr = ( t > > 1 ) + ( t > > 2 ) ;
return spots_base ( tr ) ;
}
2019-12-06 01:44:45 +01:00
//Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
uint16_t WS2812FX : : mode_glitter ( )
{
mode_palette ( ) ;
if ( SEGMENT . intensity > random8 ( ) )
{
setPixelColor ( SEGMENT . start + random16 ( SEGLEN ) , ULTRAWHITE ) ;
}
return FRAMETIME ;
}
2019-12-11 00:59:15 +01:00
//values close to 100 produce 5Hz flicker, which looks very candle-y
//Inspired by https://github.com/avanhanegem/ArduinoCandleEffectNeoPixel
//and https://cpldcpu.wordpress.com/2016/01/05/reverse-engineering-a-real-candle/
2019-12-06 01:44:45 +01:00
uint16_t WS2812FX : : mode_candle ( )
{
if ( SEGENV . call = = 0 ) {
SEGENV . aux0 = 128 ; SEGENV . aux1 = 132 ; SEGENV . step = 1 ;
}
bool newTarget = false ;
uint8_t s = SEGENV . aux0 , target = SEGENV . aux1 , fadeStep = SEGENV . step ;
if ( target > s ) { //fade up
s = qadd8 ( s , fadeStep ) ;
if ( s > = target ) newTarget = true ;
} else {
s = qsub8 ( s , fadeStep ) ;
if ( s < = target ) newTarget = true ;
}
SEGENV . aux0 = s ;
for ( uint16_t i = SEGMENT . start ; i < SEGMENT . stop ; i + + ) {
setPixelColor ( i , color_blend ( color_from_palette ( i , true , PALETTE_SOLID_WRAP , 0 ) , SEGCOLOR ( 1 ) , 255 - s ) ) ;
}
if ( newTarget )
{
uint8_t valrange = SEGMENT . intensity ;
uint8_t rndval = valrange > > 1 ;
target = random8 ( rndval ) + random8 ( rndval ) ;
2019-12-11 00:59:15 +01:00
if ( target < ( rndval > > 1 ) ) target = ( rndval > > 1 ) + random8 ( rndval ) ;
2019-12-06 01:44:45 +01:00
uint8_t offset = ( 255 - valrange ) > > 1 ;
target + = offset ;
uint8_t dif = ( target > s ) ? target - s : s - target ;
//how much to move closer to target per frame
2019-12-11 00:59:15 +01:00
fadeStep = dif > > 2 ; //mode called every ~25 ms, so 4 frames to have a new target every 100ms
2019-12-06 01:44:45 +01:00
if ( fadeStep = = 0 ) fadeStep = 1 ;
SEGENV . step = fadeStep ;
SEGENV . aux1 = target ;
}
return FRAMETIME ;
}