Skip to content

Instantly share code, notes, and snippets.

@fredolivas
Created December 8, 2017 04:00
Show Gist options
  • Save fredolivas/5248c3088ee2ace488148cf54414a28a to your computer and use it in GitHub Desktop.
Save fredolivas/5248c3088ee2ace488148cf54414a28a to your computer and use it in GitHub Desktop.
Cine-Lights Fire Lamp code. Supporting files in folder but can't upload folder.
/* Teensyduino program
* Torch: https://github.com/evilgeniuslabs/torch
* Copyright (C) 2015 Jason Coon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <FastLED.h>
#include <IRremote.h>
#include <EEPROM.h>
#include <Bounce2.h>
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif
#define LED_PIN 11
#define IR_RECV_PIN 12
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define NUM_LEDS 264
const uint8_t MATRIX_WIDTH = 12;
const uint8_t MATRIX_HEIGHT = 22;
const int MATRIX_CENTER_X = MATRIX_WIDTH / 2;
const int MATRIX_CENTER_Y = MATRIX_HEIGHT / 2;
const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1;
const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1;
const uint8_t brightnessCount = 5;
uint8_t brightnessMap[brightnessCount] = { 16, 32, 64, 128, 255 };
uint8_t brightness = brightnessMap[0];
CRGB leds[NUM_LEDS + 1];
IRrecv irReceiver(IR_RECV_PIN);
#define BUTTON_1_PIN 16
#define BUTTON_2_PIN 17
Bounce button1 = Bounce();
Bounce button2 = Bounce();
#include "Commands.h"
#include "GradientPalettes.h"
CRGB solidColor = CRGB::White;
typedef uint16_t(*PatternFunctionPointer)();
typedef PatternFunctionPointer PatternList [];
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
int autoPlayDurationSeconds = 10;
unsigned int autoPlayTimout = 0;
bool autoplayEnabled = false;
InputCommand command;
int currentPatternIndex = 0;
PatternFunctionPointer currentPattern;
CRGB w(85, 85, 85), W(CRGB::White);
CRGBPalette16 snowColors = CRGBPalette16( W, W, W, W, w, w, w, w, w, w, w, w, w, w, w, w );
CRGB l(0xE1A024);
CRGBPalette16 incandescentColors = CRGBPalette16( l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l );
const CRGBPalette16 palettes[] = {
RainbowColors_p,
RainbowStripeColors_p,
OceanColors_p,
CloudColors_p,
ForestColors_p,
PartyColors_p,
HeatColors_p,
LavaColors_p,
snowColors,
};
const int paletteCount = ARRAY_SIZE(palettes);
int currentPaletteIndex = 0;
CRGBPalette16 palette = palettes[0];
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
#include "Drawing.h"
#include "Effects.h"
#include "Noise.h"
#include "Pulse.h"
#include "Wave.h"
#include "Fire2012WithPalette.h"
#include "Torch.h"
#include "Torch2.h"
#include "AudioLogic.h"
#include "AudioPatterns.h"
const PatternList patterns = {
// analyzerColumns,
//analyzerColumnsSolid,
// analyzerPixels,
// fallingSpectrogram,
audioFire,
audioFire2,
torch,
torch2,
fire2012WithPalette,
pulse,
blackAndBlueNoise,
fireNoise,
lavaNoise,
wave,
rainbowNoise,
rainbowStripeNoise,
// blackAndWhiteAudioNoise,
colorWaves,
partyNoise,
forestNoise,
cloudNoise,
oceanNoise,
// blackAndWhiteNoise,
pride,
rainbow,
rainbowWithGlitter,
confetti,
// bpm,
juggle,
sinelon,
hueCycle,
rainbowTwinkles,
snowTwinkles,
cloudTwinkles,
incandescentTwinkles,
fireflies,
showSolidColor
};
const int patternCount = ARRAY_SIZE(patterns);
void setup() {
delay(500); // sanity delay
// Serial.begin(9600);
// Serial.println("setup start");
loadSettings();
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.setBrightness(brightness);
// FastLED.setDither(false);
FastLED.setDither(brightness < 255);
// Initialize the IR receiver
irReceiver.enableIRIn();
irReceiver.blink13(true);
pinMode(BUTTON_1_PIN, INPUT_PULLUP);
pinMode(BUTTON_2_PIN, INPUT_PULLUP);
button1.attach(BUTTON_1_PIN);
button2.attach(BUTTON_2_PIN);
button1.interval(5);
button2.interval(5);
currentPattern = patterns[currentPatternIndex];
autoPlayTimout = millis() + (autoPlayDurationSeconds * 1000);
initializeAudio();
// Serial.println("setup end");
}
void loop() {
// Add entropy to random number generator; we use a lot of it.
random16_add_entropy(random());
EVERY_N_MILLISECONDS(30) {
readAudio();
}
uint16_t requestedDelay = currentPattern();
FastLED.show(); // display this frame
handleInput(requestedDelay);
if (autoplayEnabled && millis() > autoPlayTimout) {
move(1);
autoPlayTimout = millis() + (autoPlayDurationSeconds * 1000);
}
// do some periodic updates
EVERY_N_MILLISECONDS(20) {
gHue++; // slowly cycle the "base color" through the rainbow
}
}
void loadSettings() {
// load settings from EEPROM
// brightness
brightness = EEPROM.read(0);
if (brightness < 1)
brightness = 1;
else if (brightness > 255)
brightness = 255;
// currentPatternIndex
currentPatternIndex = EEPROM.read(1);
if (currentPatternIndex < 0)
currentPatternIndex = 0;
else if (currentPatternIndex >= patternCount)
currentPatternIndex = patternCount - 1;
// solidColor
solidColor.r = EEPROM.read(2);
solidColor.g = EEPROM.read(3);
solidColor.b = EEPROM.read(4);
if (solidColor.r == 0 && solidColor.g == 0 && solidColor.b == 0)
solidColor = CRGB::White;
}
void setSolidColor(CRGB color) {
solidColor = color;
EEPROM.write(2, solidColor.r);
EEPROM.write(3, solidColor.g);
EEPROM.write(4, solidColor.b);
moveTo(patternCount - 1);
}
void powerOff()
{
// clear the display
const uint8_t stepSize = 4;
for (uint8_t i = 0; i < NUM_LEDS / 2 - stepSize; i += stepSize) {
for (uint8_t j = 0; j < stepSize; j++) {
leds[i + j] = CRGB::Black;
leds[(NUM_LEDS - 1) - (i + j)] = CRGB::Black;
}
FastLED.show(); // display this frame
}
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show(); // display this frame
while (true) {
// check for physical button input
button1.update();
button2.update();
if (button1.rose() || button2.rose()) {
Serial.println("Button released");
return;
}
// check for ir remote input
InputCommand command = readCommand();
if (command != InputCommand::None)
return;
}
}
void move(int delta) {
moveTo(currentPatternIndex + delta);
}
void moveTo(int index) {
currentPatternIndex = index;
if (currentPatternIndex >= patternCount)
currentPatternIndex = 0;
else if (currentPatternIndex < 0)
currentPatternIndex = patternCount - 1;
currentPattern = patterns[currentPatternIndex];
fill_solid(leds, NUM_LEDS, CRGB::Black);
EEPROM.write(1, currentPatternIndex);
}
int getBrightnessLevel() {
int level = 0;
for (int i = 0; i < brightnessCount; i++) {
if (brightnessMap[i] >= brightness) {
level = i;
break;
}
}
return level;
}
uint8_t cycleBrightness() {
adjustBrightness(1);
if (brightness == brightnessMap[0])
return 0;
return brightness;
}
void adjustBrightness(int delta) {
int level = getBrightnessLevel();
level += delta;
// don't wrap
if (level < 0)
level = 0;
if (level >= brightnessCount)
level = brightnessCount - 1;
brightness = brightnessMap[level];
FastLED.setBrightness(brightness);
FastLED.setDither(brightness < 255);
EEPROM.write(0, brightness);
}
void cyclePalette(int delta = 1) {
if (currentPaletteIndex == 0 && delta < 0)
currentPaletteIndex = paletteCount - 1;
else if (currentPaletteIndex >= paletteCount - 1 && delta > 0)
currentPaletteIndex = 0;
else
currentPaletteIndex += delta;
if (currentPaletteIndex >= paletteCount)
currentPaletteIndex = 0;
palette = palettes[currentPaletteIndex];
}
unsigned long button1PressTimeStamp;
unsigned long button2PressTimeStamp;
void handleInput(unsigned int requestedDelay) {
unsigned int requestedDelayTimeout = millis() + requestedDelay;
while (true) {
// check for physical button input
button1.update();
button2.update();
if (button1.fell()) {
Serial.println("Button 1 depressed");
button1PressTimeStamp = millis();
}
if (button2.fell()) {
Serial.println("Button 2 depressed");
button2PressTimeStamp = millis();
}
if (button1.rose()) {
Serial.println("Button 1 released");
move(1);
}
if (button2.rose()) {
Serial.println("Button 2 released");
powerOff();
break;
}
command = readCommand(defaultHoldDelay);
if (command != InputCommand::None) {
// Serial.print("command: ");
// Serial.println((int) command);
}
if (command == InputCommand::Up) {
move(1);
break;
}
else if (command == InputCommand::Down) {
move(-1);
break;
}
else if (command == InputCommand::Brightness) {
if (isHolding || cycleBrightness() == 0) {
heldButtonHasBeenHandled();
powerOff();
break;
}
}
else if (command == InputCommand::Power) {
powerOff();
break;
}
else if (command == InputCommand::BrightnessUp) {
adjustBrightness(1);
}
else if (command == InputCommand::BrightnessDown) {
adjustBrightness(-1);
}
else if (command == InputCommand::PlayMode) { // toggle pause/play
autoplayEnabled = !autoplayEnabled;
}
else if (command == InputCommand::NextPalette) { // cycle color palette
cyclePalette(1);
}
else if (command == InputCommand::PreviousPalette) { // cycle color palette
cyclePalette(-1);
}
// pattern buttons
else if (command == InputCommand::Pattern1) {
moveTo(0);
break;
}
else if (command == InputCommand::Pattern2) {
moveTo(1);
break;
}
else if (command == InputCommand::Pattern3) {
moveTo(2);
break;
}
else if (command == InputCommand::Pattern4) {
moveTo(3);
break;
}
else if (command == InputCommand::Pattern5) {
moveTo(4);
break;
}
else if (command == InputCommand::Pattern6) {
moveTo(5);
break;
}
else if (command == InputCommand::Pattern7) {
moveTo(6);
break;
}
else if (command == InputCommand::Pattern8) {
moveTo(7);
break;
}
else if (command == InputCommand::Pattern9) {
moveTo(8);
break;
}
else if (command == InputCommand::Pattern10) {
moveTo(9);
break;
}
else if (command == InputCommand::Pattern11) {
moveTo(10);
break;
}
else if (command == InputCommand::Pattern12) {
moveTo(11);
break;
}
// custom color adjustment buttons
else if (command == InputCommand::RedUp) {
solidColor.red += 1;
setSolidColor(solidColor);
break;
}
else if (command == InputCommand::RedDown) {
solidColor.red -= 1;
setSolidColor(solidColor);
break;
}
else if (command == InputCommand::GreenUp) {
solidColor.green += 1;
setSolidColor(solidColor); \
break;
}
else if (command == InputCommand::GreenDown) {
solidColor.green -= 1;
setSolidColor(solidColor);
break;
}
else if (command == InputCommand::BlueUp) {
solidColor.blue += 1;
setSolidColor(solidColor);
break;
}
else if (command == InputCommand::BlueDown) {
solidColor.blue -= 1;
setSolidColor(solidColor);
break;
}
// color buttons
else if (command == InputCommand::Red && currentPatternIndex != patternCount - 2 && currentPatternIndex != patternCount - 3) { // Red, Green, and Blue buttons can be used by ColorInvaders game, which is the next to last pattern
setSolidColor(CRGB::Red);
break;
}
else if (command == InputCommand::RedOrange) {
setSolidColor(CRGB::OrangeRed);
break;
}
else if (command == InputCommand::Orange) {
setSolidColor(CRGB::Orange);
break;
}
else if (command == InputCommand::YellowOrange) {
setSolidColor(CRGB::Goldenrod);
break;
}
else if (command == InputCommand::Yellow) {
setSolidColor(CRGB::Yellow);
break;
}
else if (command == InputCommand::Green && currentPatternIndex != patternCount - 2 && currentPatternIndex != patternCount - 3) { // Red, Green, and Blue buttons can be used by ColorInvaders game, which is the next to last pattern
setSolidColor(CRGB::Green);
break;
}
else if (command == InputCommand::Lime) {
setSolidColor(CRGB::Lime);
break;
}
else if (command == InputCommand::Aqua) {
setSolidColor(CRGB::Aqua);
break;
}
else if (command == InputCommand::Teal) {
setSolidColor(CRGB::Teal);
break;
}
else if (command == InputCommand::Navy) {
setSolidColor(CRGB::Navy);
break;
}
else if (command == InputCommand::Blue && currentPatternIndex != patternCount - 2 && currentPatternIndex != patternCount - 3) { // Red, Green, and Blue buttons can be used by ColorInvaders game, which is the next to last pattern
setSolidColor(CRGB::Blue);
break;
}
else if (command == InputCommand::RoyalBlue) {
setSolidColor(CRGB::RoyalBlue);
break;
}
else if (command == InputCommand::Purple) {
setSolidColor(CRGB::Purple);
break;
}
else if (command == InputCommand::Indigo) {
setSolidColor(CRGB::Indigo);
break;
}
else if (command == InputCommand::Magenta) {
setSolidColor(CRGB::Magenta);
break;
}
else if (command == InputCommand::White && currentPatternIndex != patternCount - 2 && currentPatternIndex != patternCount - 3) {
setSolidColor(CRGB::White);
break;
}
else if (command == InputCommand::Pink) {
setSolidColor(CRGB::Pink);
break;
}
else if (command == InputCommand::LightPink) {
setSolidColor(CRGB::LightPink);
break;
}
else if (command == InputCommand::BabyBlue) {
setSolidColor(CRGB::CornflowerBlue);
break;
}
else if (command == InputCommand::LightBlue) {
setSolidColor(CRGB::LightBlue);
break;
}
if (millis() >= requestedDelayTimeout)
break;
}
}
uint16_t XY( uint8_t x, uint8_t y) // maps the matrix to the strip
{
uint16_t i;
i = (y * MATRIX_WIDTH) + (MATRIX_WIDTH - x);
i = (NUM_LEDS - 1) - i;
if (i > NUM_LEDS)
i = NUM_LEDS;
return i;
}
// scale the brightness of the screenbuffer down
void dimAll(byte value)
{
for (int i = 0; i < NUM_LEDS; i++) {
leds[i].nscale8(value);
}
}
uint16_t showSolidColor() {
fill_solid(leds, NUM_LEDS, solidColor);
return 60;
}
uint16_t rainbow()
{
// FastLED's built-in rainbow generator
fill_rainbow(leds, NUM_LEDS, gHue, 1);
return 8;
}
uint16_t rainbowWithGlitter()
{
// built-in FastLED rainbow, plus some random sparkly glitter
rainbow();
addGlitter(80);
return 8;
}
void addGlitter(fract8 chanceOfGlitter)
{
if (random8() < chanceOfGlitter) {
leds[random16(NUM_LEDS)] += CRGB::White;
}
}
uint16_t confetti()
{
// random colored speckles that blink in and fade smoothly
fadeToBlackBy(leds, NUM_LEDS, 10);
int pos = random16(NUM_LEDS);
leds[pos] += ColorFromPalette(palette, gHue + random8(64), 255); // CHSV(gHue + random8(64), 200, 255);
return 8;
}
uint16_t bpm()
{
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint8_t BeatsPerMinute = 62;
uint8_t beat = beatsin8(BeatsPerMinute, 64, 255);
for (int i = 0; i < NUM_LEDS; i++) { //9948
leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
}
return 8;
}
uint16_t juggle() {
// N colored dots, weaving in and out of sync with each other
fadeToBlackBy(leds, NUM_LEDS, 20);
byte dothue = 0;
byte dotCount = 3;
for (int i = 0; i < dotCount; i++) {
leds[beatsin16(i + dotCount - 1, 0, NUM_LEDS)] |= CHSV(dothue, 200, 255);
dothue += 256 / dotCount;
}
return 0;
}
// An animation to play while the crowd goes wild after the big performance
uint16_t applause()
{
static uint16_t lastPixel = 0;
fadeToBlackBy(leds, NUM_LEDS, 32);
leds[lastPixel] = CHSV(random8(HUE_BLUE, HUE_PURPLE), 255, 255);
lastPixel = random16(NUM_LEDS);
leds[lastPixel] = CRGB::White;
return 8;
}
// An "animation" to just fade to black. Useful as the last track
// in a non-looping performance-oriented playlist.
uint16_t fadeToBlack()
{
fadeToBlackBy(leds, NUM_LEDS, 10);
return 8;
}
uint16_t sinelon()
{
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( leds, NUM_LEDS, 20);
uint16_t pos = beatsin16(13, 0, NUM_LEDS);
static uint16_t prevpos = 0;
if ( pos < prevpos ) {
fill_solid( leds + pos, (prevpos - pos) + 1, CHSV(gHue, 220, 255));
} else {
fill_solid( leds + prevpos, (pos - prevpos) + 1, CHSV( gHue, 220, 255));
}
prevpos = pos;
return 8;
}
uint16_t hueCycle() {
fill_solid(leds, NUM_LEDS, CHSV(gHue, 255, 255));
return 60;
}
// Pride2015 by Mark Kriegsman
// https://gist.github.com/kriegsman/964de772d64c502760e5
// This function draws rainbows with an ever-changing,
// widely-varying set of parameters.
uint16_t pride()
{
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
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);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88(400, 5, 9);
uint16_t brightnesstheta16 = sPseudotime;
for (int i = 0; i < NUM_LEDS; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
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);
uint8_t pixelnumber = i;
pixelnumber = (NUM_LEDS - 1) - pixelnumber;
nblend(leds[pixelnumber], newcolor, 64);
}
return 0;
}
///////////////////////////////////////////////////////////////////////
// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are. The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes[];
extern const uint8_t gGradientPaletteCount;
// Current palette number from the 'playlist' of color palettes
uint8_t gCurrentPaletteNumber = 0;
CRGBPalette16 gCurrentPalette( CRGB::Black);
CRGBPalette16 gTargetPalette( gGradientPalettes[0] );
// ten seconds per color palette makes a good demo
// 20-120 is better for deployment
#define SECONDS_PER_PALETTE 10
uint16_t colorWaves()
{
EVERY_N_SECONDS( SECONDS_PER_PALETTE ) {
gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount);
gTargetPalette = gGradientPalettes[ gCurrentPaletteNumber ];
}
EVERY_N_MILLISECONDS(40) {
nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 16);
}
colorwaves( leds, NUM_LEDS, gCurrentPalette);
return 20;
}
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette)
{
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
// 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, 300, 1500);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88( 400, 5, 9);
uint16_t brightnesstheta16 = sPseudotime;
for ( uint16_t i = 0 ; i < numleds; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
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);
uint8_t index = hue8;
//index = triwave8( index);
index = scale8( index, 240);
CRGB newcolor = ColorFromPalette( palette, index, bri8);
uint16_t pixelnumber = i;
pixelnumber = (numleds - 1) - pixelnumber;
nblend( ledarray[pixelnumber], newcolor, 128);
}
}
// Alternate rendering function just scrolls the current palette
// across the defined LED strip.
void palettetest( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& gCurrentPalette)
{
static uint8_t startindex = 0;
startindex--;
fill_palette( ledarray, numleds, startindex, (256 / NUM_LEDS) + 1, gCurrentPalette, 255, LINEARBLEND);
}
#define STARTING_BRIGHTNESS 64
#define FADE_IN_SPEED 32
#define FADE_OUT_SPEED 20
uint8_t DENSITY = 255;
uint16_t cloudTwinkles()
{
DENSITY = 255;
colortwinkles(CloudColors_p);
return 20;
}
uint16_t rainbowTwinkles()
{
DENSITY = 255;
colortwinkles(RainbowColors_p);
return 20;
}
uint16_t snowTwinkles()
{
DENSITY = 255;
colortwinkles(snowColors);
return 20;
}
uint16_t incandescentTwinkles()
{
DENSITY = 255;
colortwinkles(incandescentColors);
return 20;
}
uint16_t fireflies()
{
DENSITY = 16;
colortwinkles(incandescentColors);
return 20;
}
enum { GETTING_DARKER = 0, GETTING_BRIGHTER = 1 };
void colortwinkles(CRGBPalette16 palette)
{
// Make each pixel brighter or darker, depending on
// its 'direction' flag.
brightenOrDarkenEachPixel( FADE_IN_SPEED, FADE_OUT_SPEED);
// Now consider adding a new random twinkle
if ( random8() < DENSITY ) {
int pos = random16(NUM_LEDS);
if ( !leds[pos]) {
leds[pos] = ColorFromPalette( palette, random8(), STARTING_BRIGHTNESS, NOBLEND);
setPixelDirection(pos, GETTING_BRIGHTER);
}
}
}
void brightenOrDarkenEachPixel( fract8 fadeUpAmount, fract8 fadeDownAmount)
{
for ( uint16_t i = 0; i < NUM_LEDS; i++) {
if ( getPixelDirection(i) == GETTING_DARKER) {
// This pixel is getting darker
leds[i] = makeDarker( leds[i], fadeDownAmount);
} else {
// This pixel is getting brighter
leds[i] = makeBrighter( leds[i], fadeUpAmount);
// now check to see if we've maxxed out the brightness
if ( leds[i].r == 255 || leds[i].g == 255 || leds[i].b == 255) {
// if so, turn around and start getting darker
setPixelDirection(i, GETTING_DARKER);
}
}
}
}
CRGB makeBrighter( const CRGB& color, fract8 howMuchBrighter)
{
CRGB incrementalColor = color;
incrementalColor.nscale8( howMuchBrighter);
return color + incrementalColor;
}
CRGB makeDarker( const CRGB& color, fract8 howMuchDarker)
{
CRGB newcolor = color;
newcolor.nscale8( 255 - howMuchDarker);
return newcolor;
}
// Compact implementation of
// the directionFlags array, using just one BIT of RAM
// per pixel. This requires a bunch of bit wrangling,
// but conserves precious RAM. The cost is a few
// cycles and about 100 bytes of flash program memory.
uint8_t directionFlags[ (NUM_LEDS + 7) / 8];
bool getPixelDirection( uint16_t i) {
uint16_t index = i / 8;
uint8_t bitNum = i & 0x07;
uint8_t andMask = 1 << bitNum;
return (directionFlags[index] & andMask) != 0;
}
void setPixelDirection( uint16_t i, bool dir) {
uint16_t index = i / 8;
uint8_t bitNum = i & 0x07;
uint8_t orMask = 1 << bitNum;
uint8_t andMask = 255 - orMask;
uint8_t value = directionFlags[index] & andMask;
if ( dir ) {
value += orMask;
}
directionFlags[index] = value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment