Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TV Simulator Effect #1548

Merged
merged 4 commits into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

#include "FX.h"
#include "tv_colors.h"

#define IBN 5100
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
Expand Down Expand Up @@ -3752,4 +3753,96 @@ uint16_t WS2812FX::mode_blends(void) {
}

return FRAMETIME;
}
}

typedef struct TvSim {
uint32_t totalTime = 0;
uint32_t fadeTime = 0;
uint32_t startTime = 0;
uint32_t elapsed = 0;
uint32_t pixelNum = 0;
uint16_t pr = 0; // Prev R, G, B
uint16_t pg = 0;
uint16_t pb = 0;
} tvSim;

#define numTVPixels (sizeof(tv_colors) / 2) // 2 bytes per Pixel (5/6/5)

/*
TV Simulator
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
*/
uint16_t WS2812FX::mode_tv_simulator(void) {
#ifdef WLED_DISABLE_FX_HIGH_FLASH_USE
return mode_static();
#else
uint16_t nr, ng, nb, r, g, b, i;
uint8_t hi, lo, r8, g8, b8;

if (!SEGENV.allocateData(sizeof(tvSim))) return mode_static(); //allocation failed
TvSim* tvSimulator = reinterpret_cast<TvSim*>(SEGENV.data);

// initialize start of the TV-Colors
if (SEGENV.call == 0) {
tvSimulator->pixelNum = ((uint8_t)random(18)) * numTVPixels / 18; // Begin at random movie (18 in total)
}

// Read next 16-bit (5/6/5) color
hi = pgm_read_byte(&tv_colors[tvSimulator->pixelNum * 2 ]);
lo = pgm_read_byte(&tv_colors[tvSimulator->pixelNum * 2 + 1]);

// Expand to 24-bit (8/8/8)
r8 = (hi & 0xF8) | (hi >> 5);
g8 = ((hi << 5) & 0xff) | ((lo & 0xE0) >> 3) | ((hi & 0x06) >> 1);
b8 = ((lo << 3) & 0xff) | ((lo & 0x1F) >> 2);

// Apply gamma correction, further expand to 16/16/16
nr = (uint8_t)gamma8(r8) * 257; // New R/G/B
ng = (uint8_t)gamma8(g8) * 257;
nb = (uint8_t)gamma8(b8) * 257;

if (SEGENV.aux0 == 0) { // initialize next iteration
SEGENV.aux0 = 1;

// increase color-index for next loop
tvSimulator->pixelNum++;
if (tvSimulator->pixelNum >= numTVPixels) tvSimulator->pixelNum = 0;

// randomize total duration and fade duration for the actual color
tvSimulator->totalTime = random(250, 2500); // Semi-random pixel-to-pixel time
tvSimulator->fadeTime = random(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
if (random(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time

tvSimulator->startTime = millis();
} // end of initialization

// how much time is elapsed ?
tvSimulator->elapsed = millis() - tvSimulator->startTime;

// fade from prev volor to next color
if (tvSimulator->elapsed < tvSimulator->fadeTime) {
r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb);
} else { // Avoid divide-by-zero in map()
r = nr;
g = ng;
b = nb;
}

// set strip color
for (i = 0; i < SEGLEN; i++) {
setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
}

// if total duration has passed, remember last color and restart the loop
if ( tvSimulator->elapsed >= tvSimulator->totalTime) {
tvSimulator->pr = nr; // Prev RGB = new RGB
tvSimulator->pg = ng;
tvSimulator->pb = nb;
SEGENV.aux0 = 0;
}

return FRAMETIME;
#endif
}
12 changes: 9 additions & 3 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif

/* Disable effects with high flash memory usage (currently TV simulator) - saves 18.5kB */
//#define WLED_DISABLE_FX_HIGH_FLASH_USE

/* Not used in all effects yet */
#define WLED_FPS 42
#define FRAMETIME (1000/WLED_FPS)
Expand Down Expand Up @@ -116,7 +119,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )

#define MODE_COUNT 116
#define MODE_COUNT 117

#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
Expand Down Expand Up @@ -234,6 +237,7 @@
#define FX_MODE_WASHING_MACHINE 113
#define FX_MODE_CANDY_CANE 114
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116

class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
Expand Down Expand Up @@ -463,6 +467,7 @@ class WS2812FX {
_mode[FX_MODE_WASHING_MACHINE] = &WS2812FX::mode_washing_machine;
_mode[FX_MODE_CANDY_CANE] = &WS2812FX::mode_candy_cane;
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;

_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
Expand Down Expand Up @@ -673,7 +678,8 @@ class WS2812FX {
mode_dancing_shadows(void),
mode_washing_machine(void),
mode_candy_cane(void),
mode_blends(void);
mode_blends(void),
mode_tv_simulator(void);

private:
NeoPixelWrapper *bus;
Expand Down Expand Up @@ -761,7 +767,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends"
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator"
])=====";


Expand Down
Loading