├── AudioLogic.h ├── AudioPatterns.h ├── Commands.h ├── Drawing.h ├── Effects.h ├── Fire2012Rainbow.h ├── Fire2012WithPalette.h ├── FireBlue.h ├── FireChemical.h ├── FireElectricBlue.h ├── FireGreen.h ├── FireOrange.h ├── FirePurple.h ├── FireRainbow.h ├── FireRed.h ├── FireWhite.h ├── GradientPalettes.h ├── LEDEffectLampProject.ino ├── LICENSE ├── Noise.h ├── Pulse.h ├── README.md ├── VariableList.txt └── Wave.h /AudioLogic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #define MSGEQ7_STROBE_PIN 2 20 | #define MSGEQ7_RESET_PIN 3 21 | #define MSGEQ7_LEFT_PIN A0 22 | #define MSGEQ7_RIGHT_PIN A1 23 | 24 | const uint8_t bandCount = 7; 25 | 26 | int levelsLeft[bandCount]; 27 | int peaksLeft[bandCount]; 28 | 29 | int levelsRight[bandCount]; 30 | int peaksRight[bandCount]; 31 | 32 | static const uint8_t peakDecay = (1024 / MATRIX_HEIGHT) / 6; 33 | bool drawPeaks = true; 34 | 35 | int noiseCorrection[bandCount] = { 36 | -55, -50, -45, -55, -40, -55, -50, 37 | //0, 0, 0, 0, 0, 0, 0 38 | }; 39 | 40 | uint8_t bandOffset = 3; 41 | uint8_t horizontalPixelsPerBand = MATRIX_WIDTH / (bandCount * 2); 42 | uint8_t levelsPerVerticalPixel = 63; // 1024 / MATRIX_HEIGHT; 43 | uint8_t levelsPerHue = 1024 / 256; 44 | 45 | void initializeAudio() { 46 | pinMode(MSGEQ7_LEFT_PIN, INPUT); 47 | pinMode(MSGEQ7_RIGHT_PIN, INPUT); 48 | pinMode(MSGEQ7_RESET_PIN, OUTPUT); 49 | pinMode(MSGEQ7_STROBE_PIN, OUTPUT); 50 | digitalWrite(MSGEQ7_RESET_PIN, LOW); 51 | digitalWrite(MSGEQ7_STROBE_PIN, HIGH); 52 | } 53 | 54 | void readAudio() { 55 | digitalWrite(MSGEQ7_RESET_PIN, HIGH); 56 | digitalWrite(MSGEQ7_RESET_PIN, LOW); 57 | 58 | int levelLeft; 59 | int levelRight; 60 | 61 | for (uint8_t band = 0; band < bandCount; band++) { 62 | digitalWrite(MSGEQ7_STROBE_PIN, LOW); 63 | delayMicroseconds(30); 64 | 65 | levelLeft = analogRead(MSGEQ7_LEFT_PIN); 66 | levelRight = analogRead(MSGEQ7_RIGHT_PIN); 67 | digitalWrite(MSGEQ7_STROBE_PIN, HIGH); 68 | 69 | levelLeft += noiseCorrection[band]; 70 | levelRight += noiseCorrection[band]; 71 | 72 | // if (levelLeft < 0) levelLeft = 0; 73 | // if (levelLeft > 1023) levelLeft = 1023; 74 | // 75 | // if (levelRight < 0) levelRight = 0; 76 | // if (levelRight > 1023) levelRight = 1023; 77 | 78 | levelsLeft[band] = levelLeft; 79 | levelsRight[band] = levelRight; 80 | 81 | // if (levelLeft >= peaksLeft[band]) { 82 | peaksLeft[band] = levelLeft; 83 | // } 84 | // else if (peaksLeft[band] > 0) { 85 | // peaksLeft[band] = peaksLeft[band] - peakDecay; 86 | // if(peaksLeft[band] < 0) peaksLeft[band] = 0; 87 | // } 88 | // 89 | // if (levelRight >= peaksRight[band]) { 90 | peaksRight[band] = levelRight; 91 | // } 92 | // else if (peaksRight[band] > 0) { 93 | // peaksRight[band] = peaksRight[band] - peakDecay; 94 | // if(peaksRight[band] < 0) peaksRight[band] = 0; 95 | // } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AudioPatterns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | uint16_t AudioAnalyzerColumns() { 20 | fill_solid(leds, NUM_LEDS, CRGB::Black); 21 | 22 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 23 | int levelLeft = levelsLeft[bandIndex]; 24 | int levelRight = levelsRight[bandIndex]; 25 | 26 | if (drawPeaks) { 27 | levelLeft = peaksLeft[bandIndex]; 28 | levelRight = peaksRight[bandIndex]; 29 | } 30 | 31 | CRGB colorLeft = ColorFromPalette(palette, levelLeft / levelsPerHue); 32 | CRGB colorRight = ColorFromPalette(palette, levelRight / levelsPerHue); 33 | 34 | uint8_t x = bandIndex + bandOffset; 35 | if (x >= MATRIX_WIDTH) 36 | x -= MATRIX_WIDTH; 37 | 38 | drawFastVLine(x, (MATRIX_HEIGHT - 1) - levelLeft / levelsPerVerticalPixel, MATRIX_HEIGHT - 1, colorLeft); 39 | drawFastVLine(x + bandCount, (MATRIX_HEIGHT - 1) - levelRight / levelsPerVerticalPixel, MATRIX_HEIGHT - 1, colorRight); 40 | } 41 | 42 | return 1; 43 | } 44 | 45 | //=========================================== 46 | uint16_t AudioAnalyzerColumnsSolid() { 47 | fill_solid(leds, NUM_LEDS, CRGB::Black); 48 | 49 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 50 | int levelLeft = levelsLeft[bandIndex]; 51 | int levelRight = levelsRight[bandIndex]; 52 | 53 | if (drawPeaks) { 54 | levelLeft = peaksLeft[bandIndex]; 55 | levelRight = peaksRight[bandIndex]; 56 | } 57 | 58 | CRGB colorLeft = ColorFromPalette(palette, gHue); 59 | CRGB colorRight = ColorFromPalette(palette, gHue); 60 | 61 | uint8_t x = bandIndex + bandOffset; 62 | if (x >= MATRIX_WIDTH) 63 | x -= MATRIX_WIDTH; 64 | 65 | drawFastVLine(x, (MATRIX_HEIGHT - 1) - levelLeft / levelsPerVerticalPixel, MATRIX_HEIGHT - 1, colorLeft); 66 | drawFastVLine(x + bandCount, (MATRIX_HEIGHT - 1) - levelRight / levelsPerVerticalPixel, MATRIX_HEIGHT - 1, colorRight); 67 | } 68 | 69 | return 1; 70 | } 71 | 72 | //=========================================== 73 | uint16_t AudioAnalyzerPixels() { 74 | fill_solid(leds, NUM_LEDS, CRGB::Black); 75 | 76 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 77 | int levelLeft = levelsLeft[bandIndex]; 78 | int levelRight = levelsRight[bandIndex]; 79 | 80 | if (drawPeaks) { 81 | levelLeft = peaksLeft[bandIndex]; 82 | levelRight = peaksRight[bandIndex]; 83 | } 84 | 85 | CRGB colorLeft = ColorFromPalette(palette, levelLeft / levelsPerHue); 86 | CRGB colorRight = ColorFromPalette(palette, levelRight / levelsPerHue); 87 | 88 | uint8_t x = bandIndex + bandOffset; 89 | if (x >= MATRIX_WIDTH) 90 | x -= MATRIX_WIDTH; 91 | 92 | leds[XY(x, (MATRIX_HEIGHT - 1) - levelLeft / levelsPerVerticalPixel)] = colorLeft; 93 | leds[XY(x + bandCount, (MATRIX_HEIGHT - 1) - levelLeft / levelsPerVerticalPixel)] = colorRight; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | //=========================================== 100 | uint16_t AudioFallingSpectrogram() { 101 | moveDown(); 102 | 103 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 104 | int levelLeft = levelsLeft[bandIndex]; 105 | int levelRight = levelsRight[bandIndex]; 106 | 107 | if (drawPeaks) { 108 | levelLeft = peaksLeft[bandIndex]; 109 | levelRight = peaksRight[bandIndex]; 110 | } 111 | 112 | if (levelLeft <= 8) levelLeft = 0; 113 | if (levelRight <= 8) levelRight = 0; 114 | 115 | CRGB colorLeft; 116 | CRGB colorRight; 117 | 118 | if (currentPaletteIndex < 2) { // invert the first two palettes 119 | colorLeft = ColorFromPalette(palette, 205 - (levelLeft / levelsPerHue - 205)); 120 | colorRight = ColorFromPalette(palette, 205 - (levelLeft / levelsPerHue - 205)); 121 | } 122 | else { 123 | colorLeft = ColorFromPalette(palette, levelLeft / levelsPerHue); 124 | colorRight = ColorFromPalette(palette, levelRight / levelsPerHue); 125 | } 126 | 127 | uint8_t x = bandIndex + bandOffset; 128 | if (x >= MATRIX_WIDTH) 129 | x -= MATRIX_WIDTH; 130 | 131 | leds[XY(x, 0)] = colorLeft; 132 | leds[XY(x + bandCount, 0)] = colorRight; 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | //=========================================== 139 | uint16_t AudioFire1() { 140 | moveUp(); 141 | 142 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 143 | int levelLeft = levelsLeft[bandIndex]; 144 | int levelRight = levelsRight[bandIndex]; 145 | 146 | if (drawPeaks) { 147 | levelLeft = peaksLeft[bandIndex]; 148 | levelRight = peaksRight[bandIndex]; 149 | } 150 | 151 | if (levelLeft <= 8) levelLeft = 0; 152 | if (levelRight <= 8) levelRight = 0; 153 | 154 | CRGB colorLeft = ColorFromPalette(HeatColors_p, levelLeft / 5); 155 | CRGB colorRight = ColorFromPalette(HeatColors_p, levelRight / 2); 156 | 157 | uint8_t x = bandIndex + bandOffset; 158 | if (x >= MATRIX_WIDTH) 159 | x -= MATRIX_WIDTH; 160 | 161 | leds[XY(x, MATRIX_HEIGHT - 1)] = colorLeft; 162 | leds[XY(x + bandCount, MATRIX_HEIGHT - 1)] = colorRight; 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | //=========================================== 169 | uint16_t AudioFire2() { 170 | moveUp(); 171 | 172 | for (uint8_t bandIndex = 0; bandIndex < bandCount; bandIndex++) { 173 | int levelLeft = levelsLeft[bandIndex]; 174 | int levelRight = levelsRight[bandIndex]; 175 | 176 | if (drawPeaks) { 177 | levelLeft = peaksLeft[bandIndex]; 178 | levelRight = peaksRight[bandIndex]; 179 | } 180 | 181 | if (levelLeft <= 8) levelLeft = 0; 182 | if (levelRight <= 8) levelRight = 0; 183 | 184 | CRGB colorLeft = ColorFromPalette(OceanColors_p, levelLeft / 5); 185 | CRGB colorRight = ColorFromPalette(OceanColors_p, levelRight / 5); 186 | 187 | uint8_t x = bandIndex + bandOffset; 188 | if (x >= MATRIX_WIDTH) 189 | x -= MATRIX_WIDTH; 190 | 191 | leds[XY(x, MATRIX_HEIGHT - 1)] = colorLeft; 192 | leds[XY(x + bandCount, MATRIX_HEIGHT - 1)] = colorRight; 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | //=========================================== 199 | uint16_t AudioFire3() { 200 | static int lastPeak0 = 0; 201 | static int lastPeak6 = 0; 202 | noisespeedx = 0; 203 | noisespeedz = 0; 204 | if (peaksLeft[0] >= lastPeak0) { 205 | noisespeedx = peaksLeft[0] / 32; 206 | } 207 | if (peaksLeft[6] >= lastPeak6) { 208 | noisespeedz = peaksLeft[6] / 128; 209 | } 210 | lastPeak0 = peaksLeft[0]; 211 | lastPeak6 = peaksLeft[6]; 212 | noisespeedy = 0; 213 | noisescale = 50; 214 | colorLoop = 0; 215 | return drawNoise(HeatColors_p, 60); 216 | } 217 | 218 | //=========================================== 219 | uint16_t AudioLavaRainbow() { 220 | static int lastPeak0 = 0; 221 | noisespeedx = 0; 222 | if (peaksLeft[0] >= lastPeak0) { 223 | noisespeedx = peaksLeft[0] / 57; 224 | } 225 | lastPeak0 = peaksLeft[0]; 226 | noisespeedy = 3; 227 | noisespeedz = 0; 228 | noisescale = 30; 229 | colorLoop = 0; 230 | return drawNoise(RainbowColors_p); 231 | //return drawNoise(LavaColors_p); 232 | } 233 | 234 | //=========================================== 235 | uint16_t AudioLava() { 236 | static int lastPeak0 = 0; 237 | noisespeedx = 0; 238 | if (peaksLeft[0] >= lastPeak0) { 239 | noisespeedx = peaksLeft[0] / 57; 240 | } 241 | lastPeak0 = peaksLeft[0]; 242 | noisespeedy = 3; 243 | noisespeedz = 0; 244 | noisescale = 30; 245 | colorLoop = 0; 246 | return drawNoise(LavaColors_p); 247 | } 248 | 249 | //=========================================== 250 | uint16_t AudioForest() { 251 | static int lastPeak0 = 0; 252 | noisespeedx = 0; 253 | if (peaksLeft[0] >= lastPeak0) { 254 | noisespeedx = peaksLeft[0] / 57; 255 | } 256 | lastPeak0 = peaksLeft[0]; 257 | noisespeedy = 0; 258 | noisespeedz = 0; 259 | noisescale = 120; 260 | colorLoop = 0; 261 | return drawNoise(ForestColors_p); 262 | } 263 | 264 | //=========================================== 265 | uint16_t AudioRainbowStripe() { 266 | static int lastPeak0 = 0; 267 | noisespeedy = 0; 268 | if (peaksLeft[0] >= lastPeak0) { 269 | noisespeedy = peaksLeft[0] / 57; 270 | } 271 | lastPeak0 = peaksLeft[0]; 272 | noisespeedx = 0; 273 | noisespeedz = 0; 274 | noisescale = 20; 275 | colorLoop = 0; 276 | return drawNoise(RainbowStripeColors_p); 277 | } 278 | 279 | //=========================================== 280 | uint16_t AudioParty() { 281 | static int lastPeak0 = 0; 282 | noisespeedx = 0; 283 | if (peaksLeft[0] >= lastPeak0) { 284 | noisespeedx = peaksLeft[0] / 57; 285 | } 286 | lastPeak0 = peaksLeft[0]; 287 | noisespeedy = 0; 288 | noisespeedz = 0; 289 | noisescale = 30; 290 | colorLoop = 0; 291 | return drawNoise(PartyColors_p); 292 | } 293 | 294 | //=========================================== 295 | uint16_t AudioLavaMagenta() { 296 | static int lastPeak0 = 0; 297 | noisespeedx = 0; 298 | if (peaksLeft[0] >= lastPeak0) { 299 | noisespeedx = peaksLeft[0] / 57; 300 | } 301 | lastPeak0 = peaksLeft[0]; 302 | noisespeedy = 0; 303 | noisespeedz = 0; 304 | noisescale = 5; 305 | colorLoop = 0; 306 | //return drawNoise(Magenta_Evening_gp); 307 | return drawNoise(BlacK_Magenta_Red_gp); 308 | //return drawNoise(fire_gp); 309 | } 310 | 311 | //=========================================== 312 | uint16_t AudioCloud() { 313 | static int lastPeak0 = 0; 314 | noisespeedx = 0; 315 | if (peaksLeft[0] >= lastPeak0) { 316 | noisespeedx = peaksLeft[0] / 57; 317 | } 318 | lastPeak0 = peaksLeft[0]; 319 | noisespeedy = 0; 320 | noisespeedz = 0; 321 | noisescale = 30; 322 | colorLoop = 0; 323 | return drawNoise(CloudColors_p); 324 | } 325 | 326 | //=========================================== 327 | uint16_t AudioLava2() { 328 | static int lastPeak0 = 0; 329 | static int lastPeak6 = 0; 330 | noisespeedy = 0; 331 | noisespeedz = 0; 332 | if (peaksLeft[0] >= lastPeak0) { 333 | noisespeedy = peaksLeft[0] / 32; 334 | } 335 | if (peaksLeft[6] >= lastPeak6) { 336 | noisespeedz = peaksLeft[6] / 128; 337 | } 338 | lastPeak0 = peaksLeft[0]; 339 | lastPeak6 = peaksLeft[6]; 340 | noisespeedx = 0; 341 | noisescale = 50; 342 | colorLoop = 0; 343 | return drawNoise(LavaColors_p); 344 | } 345 | 346 | //=========================================== 347 | uint16_t AudioOcean() { 348 | static int lastPeak0 = 0; 349 | noisespeedy = 0; 350 | if (peaksLeft[0] >= lastPeak0) { 351 | noisespeedy = peaksLeft[0] / 57; 352 | } 353 | lastPeak0 = peaksLeft[0]; 354 | noisespeedx = 0; 355 | noisespeedz = 0; 356 | noisescale = 90; 357 | colorLoop = 0; 358 | return drawNoise(OceanColors_p); 359 | } 360 | 361 | //=========================================== 362 | uint16_t AudioBlackAndWhite() { 363 | SetupBlackAndWhiteStripedPalette(); 364 | static int lastPeak0 = 0; 365 | noisespeedy = 0; 366 | if (peaksLeft[0] >= lastPeak0) { 367 | noisespeedy = peaksLeft[0] / 128; 368 | } 369 | lastPeak0 = peaksLeft[0]; 370 | noisespeedx = 0; 371 | noisespeedz = 0; 372 | noisescale = 15; 373 | colorLoop = 0; 374 | return drawNoise(blackAndWhiteStripedPalette); 375 | } 376 | 377 | //=========================================== 378 | uint16_t AudioBlackAndBlue() { 379 | SetupBlackAndBlueStripedPalette(); 380 | static int lastPeak0 = 0; 381 | noisespeedx = 0; 382 | if (peaksLeft[0] >= lastPeak0) { 383 | noisespeedx = peaksLeft[0] / 57; 384 | } 385 | lastPeak0 = peaksLeft[0]; 386 | noisespeedy = 0; 387 | noisespeedz = 0; 388 | noisescale = 45; 389 | colorLoop = 0; 390 | return drawNoise(blackAndBlueStripedPalette); 391 | } 392 | -------------------------------------------------------------------------------- /Commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef IrCodes_H 20 | #define IrCodes_H 21 | 22 | enum class InputCommand { 23 | None, 24 | Up, 25 | Down, 26 | Left, 27 | Right, 28 | Select, 29 | Brightness, 30 | PlayMode, 31 | Power, 32 | BrightnessUp, 33 | BrightnessDown, 34 | CyclePalette, 35 | NextPalette, 36 | PreviousPalette, 37 | 38 | Pattern1, 39 | Pattern2, 40 | Pattern3, 41 | Pattern4, 42 | Pattern5, 43 | Pattern6, 44 | Pattern7, 45 | Pattern8, 46 | Pattern9, 47 | Pattern10, 48 | Pattern11, 49 | Pattern12, 50 | 51 | RedUp, 52 | RedDown, 53 | GreenUp, 54 | GreenDown, 55 | BlueUp, 56 | BlueDown, 57 | 58 | Red, 59 | RedOrange, 60 | Orange, 61 | YellowOrange, 62 | Yellow, 63 | 64 | Green, 65 | Lime, 66 | Aqua, 67 | Teal, 68 | Navy, 69 | 70 | Blue, 71 | RoyalBlue, 72 | Purple, 73 | Indigo, 74 | Magenta, 75 | 76 | White, 77 | Pink, 78 | LightPink, 79 | BabyBlue, 80 | LightBlue, 81 | }; 82 | 83 | // IR Raw Key Codes for SparkFun remote 84 | #define IRCODE_SPARKFUN_POWER 0x10EFD827 // 284153895 85 | #define IRCODE_SPARKFUN_A 0x10EFF807 // 86 | #define IRCODE_SPARKFUN_B 0x10EF7887 87 | #define IRCODE_SPARKFUN_C 0x10EF58A7 88 | #define IRCODE_SPARKFUN_UP 0x10EFA05F // 284139615 89 | #define IRCODE_SPARKFUN_LEFT 0x10EF10EF 90 | #define IRCODE_SPARKFUN_SELECT 0x10EF20DF 91 | #define IRCODE_SPARKFUN_RIGHT 0x10EF807F 92 | #define IRCODE_SPARKFUN_DOWN 0x10EF00FF 93 | #define IRCODE_SPARKFUN_HELD 0xFFFFFFFF 94 | 95 | // IR Raw Key Codes for Adafruit remote 96 | #define IRCODE_ADAFRUIT_HELD 0x7FFFFFFF // 4294967295 97 | #define IRCODE_ADAFRUIT_VOLUME_UP 0x00FD40BF // 16597183 98 | #define IRCODE_ADAFRUIT_PLAY_PAUSE 0x00FD807F // 16613503 99 | #define IRCODE_ADAFRUIT_VOLUME_DOWN 0x00FD00FF // 16580863 100 | #define IRCODE_ADAFRUIT_SETUP 0x00FD20DF // 16589023 101 | #define IRCODE_ADAFRUIT_UP 0x00FDA05F // 16621663 102 | #define IRCODE_ADAFRUIT_STOP_MODE 0x00FD609F // 16605343 103 | #define IRCODE_ADAFRUIT_LEFT 0x00FD10EF // 16584943 104 | #define IRCODE_ADAFRUIT_ENTER_SAVE 0x00FD906F // 16617583 105 | #define IRCODE_ADAFRUIT_RIGHT 0x00FD50AF // 16601263 106 | #define IRCODE_ADAFRUIT_0_10_PLUS 0x00FD30CF // 16593103 107 | #define IRCODE_ADAFRUIT_DOWN 0x00FDB04F // 16625743 108 | #define IRCODE_ADAFRUIT_BACK 0x00FD708F // 16609423 109 | #define IRCODE_ADAFRUIT_1 0x00FD08F7 // 16582903 110 | #define IRCODE_ADAFRUIT_2 0x00FD8877 // 16615543 111 | #define IRCODE_ADAFRUIT_3 0x00FD48B7 // 16599223 112 | #define IRCODE_ADAFRUIT_4 0x00FD28D7 // 16591063 113 | #define IRCODE_ADAFRUIT_5 0x00FDA857 // 16623703 114 | #define IRCODE_ADAFRUIT_6 0x00FD6897 // 16607383 115 | #define IRCODE_ADAFRUIT_7 0x00FD18E7 // 16586983 116 | #define IRCODE_ADAFRUIT_8 0x00FD9867 // 16619623 117 | #define IRCODE_ADAFRUIT_9 0x00FD58A7 // 16603303 118 | 119 | // IR Raw Key Codes for eTopxizu 44Key IR Remote Controller for 5050 3528 RGB LED Light Strip 120 | #define IRCODE_ETOPXIZU_HELD 0x7FFFFFFF // 4294967295 121 | #define IRCODE_ETOPXIZU_POWER 16712445 122 | #define IRCODE_ETOPXIZU_PLAY_PAUSE 16745085 123 | #define IRCODE_ETOPXIZU_BRIGHTNESS_UP 16726725 124 | #define IRCODE_ETOPXIZU_BRIGHTNESS_DOWN 16759365 125 | 126 | #define IRCODE_ETOPXIZU_DIY1 16724175 127 | #define IRCODE_ETOPXIZU_DIY2 16756815 128 | #define IRCODE_ETOPXIZU_DIY3 16740495 129 | #define IRCODE_ETOPXIZU_DIY4 16716015 130 | #define IRCODE_ETOPXIZU_DIY5 16748655 131 | #define IRCODE_ETOPXIZU_DIY6 16732335 132 | 133 | #define IRCODE_ETOPXIZU_JUMP3 16720095 134 | #define IRCODE_ETOPXIZU_JUMP7 16752735 135 | #define IRCODE_ETOPXIZU_FADE3 16736415 136 | #define IRCODE_ETOPXIZU_FADE7 16769055 137 | #define IRCODE_ETOPXIZU_FLASH 16764975 138 | #define IRCODE_ETOPXIZU_AUTO 16773135 139 | 140 | #define IRCODE_ETOPXIZU_QUICK 16771095 141 | #define IRCODE_ETOPXIZU_SLOW 16762935 142 | 143 | #define IRCODE_ETOPXIZU_RED_UP 16722135 144 | #define IRCODE_ETOPXIZU_RED_DOWN 16713975 145 | 146 | #define IRCODE_ETOPXIZU_GREEN_UP 16754775 147 | #define IRCODE_ETOPXIZU_GREEN_DOWN 16746615 148 | 149 | #define IRCODE_ETOPXIZU_BLUE_UP 16738455 150 | #define IRCODE_ETOPXIZU_BLUE_DOWN 16730295 151 | 152 | #define IRCODE_ETOPXIZU_RED 16718565 153 | #define IRCODE_ETOPXIZU_RED_ORANGE 16722645 154 | #define IRCODE_ETOPXIZU_ORANGE 16714485 155 | #define IRCODE_ETOPXIZU_YELLOW_ORANGE 16726215 156 | #define IRCODE_ETOPXIZU_YELLOW 16718055 157 | 158 | #define IRCODE_ETOPXIZU_GREEN 16751205 159 | #define IRCODE_ETOPXIZU_LIME 16755285 160 | #define IRCODE_ETOPXIZU_AQUA 16747125 161 | #define IRCODE_ETOPXIZU_TEAL 16758855 162 | #define IRCODE_ETOPXIZU_NAVY 16750695 163 | 164 | #define IRCODE_ETOPXIZU_BLUE 16753245 165 | #define IRCODE_ETOPXIZU_ROYAL_BLUE 16749165 166 | #define IRCODE_ETOPXIZU_PURPLE 16757325 167 | #define IRCODE_ETOPXIZU_INDIGO 16742535 168 | #define IRCODE_ETOPXIZU_MAGENTA 16734375 169 | 170 | #define IRCODE_ETOPXIZU_WHITE 16720605 171 | #define IRCODE_ETOPXIZU_PINK 16716525 172 | #define IRCODE_ETOPXIZU_LIGHT_PINK 16724685 173 | #define IRCODE_ETOPXIZU_BABY_BLUE 16775175 174 | #define IRCODE_ETOPXIZU_LIGHT_BLUE 16767015 175 | 176 | bool sparkfunRemoteEnabled = false; 177 | bool adafruitRemoteEnabled = true; 178 | bool etopxizuRemoteEnabled = true; 179 | 180 | // Low level IR code reading function 181 | // Function will return 0 if no IR code available 182 | unsigned long decodeIRCode() { 183 | 184 | decode_results results; 185 | 186 | results.value = 0; 187 | 188 | // Attempt to read an IR code ? 189 | if (irReceiver.decode(&results)) { 190 | delay(20); 191 | 192 | if (results.value != 0) 193 | // Serial.println(results.value); 194 | 195 | // Prepare to receive the next IR code 196 | irReceiver.resume(); 197 | } 198 | 199 | return results.value; 200 | } 201 | 202 | // Read an IR code 203 | // Function will return 0 if no IR code available 204 | unsigned long readIRCode() { 205 | 206 | // Is there an IR code to read ? 207 | unsigned long code = decodeIRCode(); 208 | if (code == 0) { 209 | // No code so return 0 210 | return 0; 211 | } 212 | 213 | // Keep reading until code changes 214 | while (decodeIRCode() == code) { 215 | ; 216 | } 217 | // Serial.println(code); 218 | return code; 219 | } 220 | 221 | unsigned long lastIrCode = 0; 222 | 223 | unsigned int holdStartTime = 0; 224 | unsigned int defaultHoldDelay = 500; 225 | bool isHolding = false; 226 | 227 | unsigned int zeroStartTime = 0; 228 | unsigned int zeroDelay = 120; 229 | 230 | unsigned long readIRCode(unsigned int holdDelay) { 231 | // read the raw code from the sensor 232 | unsigned long irCode = readIRCode(); 233 | 234 | //Serial.print(millis()); 235 | //Serial.print("\t"); 236 | //Serial.println(irCode); 237 | 238 | // don't return a short click until we know it's not a long hold 239 | // we'll have to wait for holdDelay ms to pass before returning a non-zero IR code 240 | // then, after that delay, as long as the button is held, we can keep returning the code 241 | // every time until it's released 242 | 243 | // the ir remote only sends codes every 107 ms or so (avg 106.875, max 111, min 102), 244 | // so the ir sensor will return 0 even if a button is held 245 | // so we have to wait longer than that before returning a non-zero code 246 | // in order to detect that a button has been released and is no longer held 247 | 248 | // only reset after we've gotten 0 back for more than the ir remote send interval 249 | unsigned int zeroTime = 0; 250 | 251 | if (irCode == 0) { 252 | zeroTime = millis() - zeroStartTime; 253 | if (zeroTime >= zeroDelay && lastIrCode != 0) { 254 | //Serial.println(F("zero delay has elapsed, returning last ir code")); 255 | // the button has been released for longer than the zero delay 256 | // start over delays over and return the last code 257 | irCode = lastIrCode; 258 | lastIrCode = 0; 259 | return irCode; 260 | } 261 | 262 | return 0; 263 | } 264 | 265 | // reset the zero timer every time a non-zero code is read 266 | zeroStartTime = millis(); 267 | 268 | unsigned int heldTime = 0; 269 | 270 | if (irCode == IRCODE_SPARKFUN_HELD || irCode == IRCODE_ADAFRUIT_HELD) { 271 | // has the hold delay passed? 272 | heldTime = millis() - holdStartTime; 273 | if (heldTime >= holdDelay) { 274 | isHolding = true; 275 | //Serial.println(F("hold delay has elapsed, returning last ir code")); 276 | return lastIrCode; 277 | } 278 | else if (holdStartTime == 0) { 279 | isHolding = false; 280 | holdStartTime = millis(); 281 | } 282 | } 283 | else { 284 | // not zero, not IRCODE_SPARKFUN_HELD 285 | // store it for use later, until the hold and zero delays have elapsed 286 | holdStartTime = millis(); 287 | isHolding = false; 288 | lastIrCode = irCode; 289 | return 0; 290 | } 291 | 292 | return 0; 293 | } 294 | 295 | void heldButtonHasBeenHandled() { 296 | lastIrCode = 0; 297 | isHolding = false; 298 | holdStartTime = 0; 299 | } 300 | 301 | unsigned long waitForIRCode() { 302 | 303 | unsigned long irCode = readIRCode(); 304 | while ((irCode == 0) || (irCode == 0xFFFFFFFF)) { 305 | delay(200); 306 | irCode = readIRCode(); 307 | } 308 | return irCode; 309 | } 310 | 311 | InputCommand getCommand(unsigned long input) { 312 | if (adafruitRemoteEnabled) { 313 | switch (input) { 314 | case IRCODE_ADAFRUIT_UP: 315 | return InputCommand::Up; 316 | 317 | case IRCODE_ADAFRUIT_DOWN: 318 | return InputCommand::Down; 319 | 320 | case IRCODE_ADAFRUIT_LEFT: 321 | return InputCommand::Left; 322 | 323 | case IRCODE_ADAFRUIT_RIGHT: 324 | return InputCommand::Right; 325 | 326 | case IRCODE_ADAFRUIT_ENTER_SAVE: 327 | return InputCommand::Select; 328 | 329 | case IRCODE_ADAFRUIT_STOP_MODE: 330 | case IRCODE_ADAFRUIT_1: 331 | return InputCommand::PlayMode; 332 | 333 | case IRCODE_ADAFRUIT_2: 334 | return InputCommand::CyclePalette; 335 | 336 | case IRCODE_ADAFRUIT_PLAY_PAUSE: 337 | return InputCommand::Power; 338 | 339 | case IRCODE_ADAFRUIT_VOLUME_UP: 340 | return InputCommand::BrightnessUp; 341 | 342 | case IRCODE_ADAFRUIT_VOLUME_DOWN: 343 | return InputCommand::BrightnessDown; 344 | } 345 | } 346 | 347 | if (sparkfunRemoteEnabled) { 348 | switch (input) { 349 | case IRCODE_SPARKFUN_UP: 350 | return InputCommand::Up; 351 | 352 | case IRCODE_SPARKFUN_DOWN: 353 | return InputCommand::Down; 354 | 355 | case IRCODE_SPARKFUN_LEFT: 356 | return InputCommand::Left; 357 | 358 | case IRCODE_SPARKFUN_RIGHT: 359 | return InputCommand::Right; 360 | 361 | case IRCODE_SPARKFUN_SELECT: 362 | return InputCommand::Select; 363 | 364 | case IRCODE_SPARKFUN_POWER: 365 | return InputCommand::Brightness; 366 | 367 | case IRCODE_SPARKFUN_A: 368 | return InputCommand::PlayMode; 369 | 370 | case IRCODE_SPARKFUN_B: 371 | return InputCommand::CyclePalette; 372 | } 373 | } 374 | 375 | if (etopxizuRemoteEnabled) { 376 | switch (input) { 377 | case IRCODE_ETOPXIZU_QUICK: 378 | return InputCommand::Up; 379 | 380 | case IRCODE_ETOPXIZU_SLOW: 381 | return InputCommand::Down; 382 | 383 | case IRCODE_ETOPXIZU_PLAY_PAUSE: 384 | return InputCommand::PlayMode; 385 | 386 | case IRCODE_ETOPXIZU_POWER: 387 | return InputCommand::Power; 388 | 389 | case IRCODE_ETOPXIZU_BRIGHTNESS_UP: 390 | return InputCommand::BrightnessUp; 391 | case IRCODE_ETOPXIZU_BRIGHTNESS_DOWN: 392 | return InputCommand::BrightnessDown; 393 | 394 | case IRCODE_ETOPXIZU_DIY1: 395 | return InputCommand::Pattern1; 396 | case IRCODE_ETOPXIZU_DIY2: 397 | return InputCommand::Pattern2; 398 | case IRCODE_ETOPXIZU_DIY3: 399 | return InputCommand::Pattern3; 400 | case IRCODE_ETOPXIZU_DIY4: 401 | return InputCommand::Pattern4; 402 | case IRCODE_ETOPXIZU_DIY5: 403 | return InputCommand::Pattern5; 404 | case IRCODE_ETOPXIZU_DIY6: 405 | return InputCommand::Pattern6; 406 | case IRCODE_ETOPXIZU_JUMP3: 407 | return InputCommand::Pattern7; 408 | case IRCODE_ETOPXIZU_JUMP7: 409 | return InputCommand::Pattern8; 410 | case IRCODE_ETOPXIZU_FADE3: 411 | return InputCommand::Pattern9; 412 | case IRCODE_ETOPXIZU_FADE7: 413 | return InputCommand::Pattern10; 414 | 415 | case IRCODE_ETOPXIZU_FLASH: 416 | return InputCommand::PreviousPalette; 417 | // return InputCommand::Pattern11; 418 | 419 | case IRCODE_ETOPXIZU_AUTO: 420 | return InputCommand::NextPalette; 421 | // return InputCommand::Pattern12; 422 | 423 | case IRCODE_ETOPXIZU_RED_UP: 424 | return InputCommand::RedUp; 425 | case IRCODE_ETOPXIZU_RED_DOWN: 426 | return InputCommand::RedDown; 427 | 428 | case IRCODE_ETOPXIZU_GREEN_UP: 429 | return InputCommand::GreenUp; 430 | case IRCODE_ETOPXIZU_GREEN_DOWN: 431 | return InputCommand::GreenDown; 432 | 433 | case IRCODE_ETOPXIZU_BLUE_UP: 434 | return InputCommand::BlueUp; 435 | case IRCODE_ETOPXIZU_BLUE_DOWN: 436 | return InputCommand::BlueDown; 437 | 438 | case IRCODE_ETOPXIZU_RED: 439 | return InputCommand::Red; 440 | case IRCODE_ETOPXIZU_RED_ORANGE: 441 | return InputCommand::RedOrange; 442 | case IRCODE_ETOPXIZU_ORANGE: 443 | return InputCommand::Orange; 444 | case IRCODE_ETOPXIZU_YELLOW_ORANGE: 445 | return InputCommand::YellowOrange; 446 | case IRCODE_ETOPXIZU_YELLOW: 447 | return InputCommand::Yellow; 448 | 449 | case IRCODE_ETOPXIZU_GREEN: 450 | return InputCommand::Green; 451 | case IRCODE_ETOPXIZU_LIME: 452 | return InputCommand::Lime; 453 | case IRCODE_ETOPXIZU_AQUA: 454 | return InputCommand::Aqua; 455 | case IRCODE_ETOPXIZU_TEAL: 456 | return InputCommand::Teal; 457 | case IRCODE_ETOPXIZU_NAVY: 458 | return InputCommand::Navy; 459 | 460 | case IRCODE_ETOPXIZU_BLUE: 461 | return InputCommand::Blue; 462 | case IRCODE_ETOPXIZU_ROYAL_BLUE: 463 | return InputCommand::RoyalBlue; 464 | case IRCODE_ETOPXIZU_PURPLE: 465 | return InputCommand::Purple; 466 | case IRCODE_ETOPXIZU_INDIGO: 467 | return InputCommand::Indigo; 468 | case IRCODE_ETOPXIZU_MAGENTA: 469 | return InputCommand::Magenta; 470 | 471 | case IRCODE_ETOPXIZU_WHITE: 472 | return InputCommand::White; 473 | case IRCODE_ETOPXIZU_PINK: 474 | return InputCommand::Pink; 475 | case IRCODE_ETOPXIZU_LIGHT_PINK: 476 | return InputCommand::LightPink; 477 | case IRCODE_ETOPXIZU_BABY_BLUE: 478 | return InputCommand::BabyBlue; 479 | case IRCODE_ETOPXIZU_LIGHT_BLUE: 480 | return InputCommand::LightBlue; 481 | } 482 | } 483 | 484 | return InputCommand::None; 485 | } 486 | 487 | InputCommand readCommand() { 488 | return getCommand(readIRCode()); 489 | } 490 | 491 | InputCommand readCommand(unsigned int holdDelay) { 492 | return getCommand(readIRCode(holdDelay)); 493 | } 494 | 495 | #endif 496 | -------------------------------------------------------------------------------- /Drawing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | void drawCircle(int16_t x0, int16_t y0, uint16_t radius, const CRGB& color) 20 | { 21 | int a = radius, b = 0; 22 | int radiusError = 1 - a; 23 | 24 | if (radius == 0) { 25 | leds[XY(x0, y0)] = color; 26 | return; 27 | } 28 | 29 | while (a >= b) 30 | { 31 | leds[XY(a + x0, b + y0)] = color; 32 | leds[XY(b + x0, a + y0)] = color; 33 | leds[XY(-a + x0, b + y0)] = color; 34 | leds[XY(-b + x0, a + y0)] = color; 35 | leds[XY(-a + x0, -b + y0)] = color; 36 | leds[XY(-b + x0, -a + y0)] = color; 37 | leds[XY(a + x0, -b + y0)] = color; 38 | leds[XY(b + x0, -a + y0)] = color; 39 | 40 | b++; 41 | if (radiusError < 0) 42 | radiusError += 2 * b + 1; 43 | else 44 | { 45 | a--; 46 | radiusError += 2 * (b - a + 1); 47 | } 48 | } 49 | } 50 | 51 | void drawFastVLine(uint16_t x, uint16_t y0, uint16_t y1, const CRGB& color) { 52 | uint16_t i; 53 | 54 | for (i = y0; i <= y1; i++) { 55 | leds[XY(x, i)] = color; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Effects.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | // give it a linear tail to the right 20 | void streamRight(byte scale, int fromX = 0, int toX = MATRIX_WIDTH, int fromY = 0, int toY = MATRIX_HEIGHT) 21 | { 22 | for (int x = fromX + 1; x < toX; x++) { 23 | for (int y = fromY; y < toY; y++) { 24 | leds[XY(x, y)] += leds[XY(x - 1, y)]; 25 | leds[XY(x, y)].nscale8(scale); 26 | } 27 | } 28 | for (int y = fromY; y < toY; y++) 29 | leds[XY(0, y)].nscale8(scale); 30 | } 31 | 32 | // give it a linear tail to the left 33 | void streamLeft(byte scale, int fromX = MATRIX_WIDTH, int toX = 0, int fromY = 0, int toY = MATRIX_HEIGHT) 34 | { 35 | for (int x = toX; x < fromX; x++) { 36 | for (int y = fromY; y < toY; y++) { 37 | leds[XY(x, y)] += leds[XY(x + 1, y)]; 38 | leds[XY(x, y)].nscale8(scale); 39 | } 40 | } 41 | for (int y = fromY; y < toY; y++) 42 | leds[XY(0, y)].nscale8(scale); 43 | } 44 | 45 | // give it a linear tail downwards 46 | void streamDown(byte scale) 47 | { 48 | for (int x = 0; x < MATRIX_WIDTH; x++) { 49 | for (int y = 1; y < MATRIX_HEIGHT; y++) { 50 | leds[XY(x, y)] += leds[XY(x, y - 1)]; 51 | leds[XY(x, y)].nscale8(scale); 52 | } 53 | } 54 | for (int x = 0; x < MATRIX_WIDTH; x++) 55 | leds[XY(x, 0)].nscale8(scale); 56 | } 57 | 58 | // give it a linear tail upwards 59 | void streamUp(byte scale) 60 | { 61 | for (int x = 0; x < MATRIX_WIDTH; x++) { 62 | for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) { 63 | leds[XY(x, y)] += leds[XY(x, y + 1)]; 64 | leds[XY(x, y)].nscale8(scale); 65 | } 66 | } 67 | for (int x = 0; x < MATRIX_WIDTH; x++) 68 | leds[XY(x, MATRIX_HEIGHT - 1)].nscale8(scale); 69 | } 70 | 71 | // give it a linear tail up and to the left 72 | void streamUpAndLeft(byte scale) 73 | { 74 | for (int x = 0; x < MATRIX_WIDTH - 1; x++) { 75 | for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) { 76 | leds[XY(x, y)] += leds[XY(x + 1, y + 1)]; 77 | leds[XY(x, y)].nscale8(scale); 78 | } 79 | } 80 | for (int x = 0; x < MATRIX_WIDTH; x++) 81 | leds[XY(x, MATRIX_HEIGHT - 1)].nscale8(scale); 82 | for (int y = 0; y < MATRIX_HEIGHT; y++) 83 | leds[XY(MATRIX_WIDTH - 1, y)].nscale8(scale); 84 | } 85 | 86 | // give it a linear tail up and to the right 87 | void streamUpAndRight(byte scale) 88 | { 89 | for (int x = 0; x < MATRIX_WIDTH - 1; x++) { 90 | for (int y = MATRIX_HEIGHT - 2; y >= 0; y--) { 91 | leds[XY(x + 1, y)] += leds[XY(x, y + 1)]; 92 | leds[XY(x, y)].nscale8(scale); 93 | } 94 | } 95 | // fade the bottom row 96 | for (int x = 0; x < MATRIX_WIDTH; x++) 97 | leds[XY(x, MATRIX_HEIGHT - 1)].nscale8(scale); 98 | 99 | // fade the right column 100 | for (int y = 0; y < MATRIX_HEIGHT; y++) 101 | leds[XY(MATRIX_WIDTH - 1, y)].nscale8(scale); 102 | } 103 | 104 | void moveUp() 105 | { 106 | for (int y = 0; y < MATRIX_HEIGHT - 1; y++) { 107 | for (int x = 0; x < MATRIX_WIDTH; x++) { 108 | leds[XY(x, y)] = leds[XY(x, y + 1)]; 109 | } 110 | } 111 | } 112 | 113 | void moveDown() { 114 | for (int y = MATRIX_HEIGHT - 1; y > 0; y--) { 115 | for (int x = 0; x < MATRIX_WIDTH; x++) { 116 | leds[XY(x, y)] = leds[XY(x, y - 1)]; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Fire2012Rainbow.h: -------------------------------------------------------------------------------- 1 | // Fire2012 with programmable Color Palette 2 | // by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino 3 | // 4 | // This code is the same fire simulation as the original "Fire2012", 5 | // but each heat cell's temperature is translated to color through a FastLED 6 | // programmable color palette, instead of through the "HeatColor(...)" function. 7 | // 8 | // Four different static color palettes are provided here, plus one dynamic one. 9 | // 10 | // The three static ones are: 11 | // 1. the FastLED built-in HeatColors_p -- this is the default, and it looks 12 | // pretty much exactly like the original Fire2012. 13 | // 14 | // To use any of the other palettes below, just "uncomment" the corresponding code. 15 | // 16 | // 2. a gradient from black to red to yellow to white, which is 17 | // visually similar to the HeatColors_p, and helps to illustrate 18 | // what the 'heat colors' palette is actually doing, 19 | // 3. a similar gradient, but in blue colors rather than red ones, 20 | // i.e. from black to blue to aqua to white, which results in 21 | // an "icy blue" fire effect, 22 | // 4. a simplified three-step gradient, from black to red to white, just to show 23 | // that these gradients need not have four components; two or 24 | // three are possible, too, even if they don't look quite as nice for fire. 25 | // 26 | // The dynamic palette shows how you can change the basic 'hue' of the 27 | // color palette every time through the loop, producing "rainbow fire". 28 | 29 | // Fire2012 by Mark Kriegsman, July 2012 30 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY 31 | //// 32 | // This basic one-dimensional 'fire' simulation works roughly as follows: 33 | // There's a underlying array of 'heat' cells, that model the temperature 34 | // at each point along the line. Every cycle through the simulation, 35 | // four steps are performed: 36 | // 1) All cells cool down a little bit, losing heat to the air 37 | // 2) The heat from each cell drifts 'up' and diffuses a little 38 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom 39 | // 4) The heat from each cell is rendered as a color into the leds array 40 | // The heat-to-color mapping uses a black-body radiation approximation. 41 | // 42 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). 43 | // 44 | // This simulation scales it self a bit depending on MATRIX_HEIGHT; it should look 45 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. 46 | // 47 | // I recommend running this simulation at anywhere from 30-100 frames per second, 48 | // meaning an interframe delay of about 10-35 milliseconds. 49 | // 50 | // Looks best on a high-density LED setup (60+ pixels/meter). 51 | // 52 | // 53 | // There are two main parameters you can play with to control the look and 54 | // feel of your fire: COOLING (used in step 1 above), and SPARKING (used 55 | // in step 3 above). 56 | // 57 | // COOLING: How much does the air cool as it rises? 58 | // Less cooling = taller flames. More cooling = shorter flames. 59 | // Default 55, suggested range 20-100 60 | #define COOLINGRainbow 80 // 100 // 55 // 86 61 | 62 | // SPARKING: What chance (out of 255) is there that a new spark will be lit? 63 | // Higher chance = more roaring fire. Lower chance = more flickery fire. 64 | // Default 120, suggested range 50-200. 65 | #define SPARKINGRainbow 130 // 30 // 120 // 90 // 60 66 | uint16_t Fire2012Rainbow1() 67 | { 68 | // Array of temperature readings at each simulation cell 69 | static byte heat[MATRIX_WIDTH][MATRIX_HEIGHT]; 70 | 71 | for(uint8_t x = 0; x < MATRIX_WIDTH; x++) { 72 | // Step 1. Cool down every cell a little 73 | for (int i = 0; i < MATRIX_HEIGHT; i++) { 74 | heat[x][i] = qsub8(heat[x][i], random8(0, ((COOLINGRainbow * 10) / MATRIX_HEIGHT) + 2)); 75 | } 76 | 77 | // Step 2. Heat from each cell drifts 'up' and diffuses a little 78 | for (int k = MATRIX_HEIGHT - 1; k >= 2; k--) { 79 | heat[x][k] = (heat[x][k - 1] + heat[x][k - 2] + heat[x][k - 2]) / 3; 80 | } 81 | 82 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom 83 | if (random8() < SPARKINGRainbow) { 84 | int y = random8(2); 85 | heat[x][y] = qadd8(heat[x][y], random8(160, 255)); 86 | } 87 | 88 | // Step 4. Map from heat cells to LED colors 89 | for (int j = 0; j < MATRIX_HEIGHT; j++) { 90 | // Scale the heat value from 0-255 down to 0-240 91 | // for best results with color palettes. 92 | byte colorindex = scale8(heat[x][j], 160); 93 | leds[XY(x, (MATRIX_HEIGHT - 1) - j)] = ColorFromPalette(RainbowColors_p, colorindex); 94 | } 95 | } 96 | 97 | return 15; 98 | } 99 | -------------------------------------------------------------------------------- /Fire2012WithPalette.h: -------------------------------------------------------------------------------- 1 | // Fire2012 with programmable Color Palette 2 | // by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino 3 | // 4 | // This code is the same fire simulation as the original "Fire2012", 5 | // but each heat cell's temperature is translated to color through a FastLED 6 | // programmable color palette, instead of through the "HeatColor(...)" function. 7 | // 8 | // Four different static color palettes are provided here, plus one dynamic one. 9 | // 10 | // The three static ones are: 11 | // 1. the FastLED built-in HeatColors_p -- this is the default, and it looks 12 | // pretty much exactly like the original Fire2012. 13 | // 14 | // To use any of the other palettes below, just "uncomment" the corresponding code. 15 | // 16 | // 2. a gradient from black to red to yellow to white, which is 17 | // visually similar to the HeatColors_p, and helps to illustrate 18 | // what the 'heat colors' palette is actually doing, 19 | // 3. a similar gradient, but in blue colors rather than red ones, 20 | // i.e. from black to blue to aqua to white, which results in 21 | // an "icy blue" fire effect, 22 | // 4. a simplified three-step gradient, from black to red to white, just to show 23 | // that these gradients need not have four components; two or 24 | // three are possible, too, even if they don't look quite as nice for fire. 25 | // 26 | // The dynamic palette shows how you can change the basic 'hue' of the 27 | // color palette every time through the loop, producing "rainbow fire". 28 | 29 | // Fire2012 by Mark Kriegsman, July 2012 30 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY 31 | //// 32 | // This basic one-dimensional 'fire' simulation works roughly as follows: 33 | // There's a underlying array of 'heat' cells, that model the temperature 34 | // at each point along the line. Every cycle through the simulation, 35 | // four steps are performed: 36 | // 1) All cells cool down a little bit, losing heat to the air 37 | // 2) The heat from each cell drifts 'up' and diffuses a little 38 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom 39 | // 4) The heat from each cell is rendered as a color into the leds array 40 | // The heat-to-color mapping uses a black-body radiation approximation. 41 | // 42 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). 43 | // 44 | // This simulation scales it self a bit depending on MATRIX_HEIGHT; it should look 45 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. 46 | // 47 | // I recommend running this simulation at anywhere from 30-100 frames per second, 48 | // meaning an interframe delay of about 10-35 milliseconds. 49 | // 50 | // Looks best on a high-density LED setup (60+ pixels/meter). 51 | // 52 | // 53 | // There are two main parameters you can play with to control the look and 54 | // feel of your fire: COOLING (used in step 1 above), and SPARKING (used 55 | // in step 3 above). 56 | // 57 | // COOLING: How much does the air cool as it rises? 58 | // Less cooling = taller flames. More cooling = shorter flames. 59 | // Default 55, suggested range 20-100 60 | #define COOLING 200 // 100 // 55 // 86 61 | 62 | // SPARKING: What chance (out of 255) is there that a new spark will be lit? 63 | // Higher chance = more roaring fire. Lower chance = more flickery fire. 64 | // Default 120, suggested range 50-200. 65 | #define SPARKING 230 // 30 // 120 // 90 // 60 66 | 67 | uint16_t Fire2012WithPalette() 68 | { 69 | // Array of temperature readings at each simulation cell 70 | static byte heat[MATRIX_WIDTH][MATRIX_HEIGHT]; 71 | 72 | for(uint8_t x = 0; x < MATRIX_WIDTH; x++) { 73 | // Step 1. Cool down every cell a little 74 | for (int i = 0; i < MATRIX_HEIGHT; i++) { 75 | heat[x][i] = qsub8(heat[x][i], random8(0, ((COOLING * 10) / MATRIX_HEIGHT) + 2)); 76 | } 77 | 78 | // Step 2. Heat from each cell drifts 'up' and diffuses a little 79 | for (int k = MATRIX_HEIGHT - 1; k >= 2; k--) { 80 | heat[x][k] = (heat[x][k - 1] + heat[x][k - 2] + heat[x][k - 2]) / 3; 81 | } 82 | 83 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom 84 | if (random8() < SPARKING) { 85 | int y = random8(2); 86 | heat[x][y] = qadd8(heat[x][y], random8(160, 255)); 87 | } 88 | 89 | // Step 4. Map from heat cells to LED colors 90 | for (int j = 0; j < MATRIX_HEIGHT; j++) { 91 | // Scale the heat value from 0-255 down to 0-240 92 | // for best results with color palettes. 93 | byte colorindex = scale8(heat[x][j], 160); 94 | leds[XY(x, (MATRIX_HEIGHT - 1) - j)] = ColorFromPalette(HeatColors_p, colorindex); 95 | } 96 | } 97 | 98 | return 15; 99 | } 100 | -------------------------------------------------------------------------------- /FireBlue.h: -------------------------------------------------------------------------------- 1 | // Slightly modified version of the fire pattern from MessageTorch by Lukas Zeller: 2 | // https://github.com/plan44/messagetorch 3 | 4 | // The MIT License (MIT) 5 | 6 | // Copyright (c) 2014 Lukas Zeller 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | // this software and associated documentation files (the "Software"), to deal in 10 | // the Software without restriction, including without limitation the rights to 11 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | // the Software, and to permit persons to whom the Software is furnished to do so, 13 | // subject to the following conditions: 14 | 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | // torch parameters 26 | 27 | uint16_t cycle_wait2 = 1; // 0..255 28 | 29 | byte flame_min2 = 100; // 0..255 30 | byte flame_max2 = 220; // 0..255 31 | 32 | byte random_spark_probability2 = 2; // 0..100 33 | byte spark_min2 = 200; // 0..255 34 | byte spark_max2 = 255; // 0..255 35 | 36 | byte spark_tfr2 = 40; // 0..256 how much energy is transferred up for a spark per cycle 37 | uint16_t spark_cap2 = 200; // 0..255: spark cells: how much energy is retained from previous cycle 38 | 39 | uint16_t up_rad2 = 40; // up radiation 40 | uint16_t side_rad2 = 35; // sidewards radiation 41 | uint16_t heat_cap2 = 0; // 0..255: passive cells: how much energy is retained from previous cycle 42 | 43 | byte red_bg2 = 0; 44 | byte green_bg2 = 0; //0 45 | byte blue_bg2 = 0; 46 | byte red_bias2 = 0; //10 47 | byte green_bias2 = 0; 48 | byte blue_bias2 = 10; 49 | int red_energy2 = 0; //180 50 | int green_energy2 = 0; // 80; 51 | int blue_energy2 = 220; 52 | 53 | byte upside_down2 = 0; // if set, flame (or rather: drop) animation is upside down. Text remains as-is 54 | 55 | // torch mode 56 | // ========== 57 | 58 | #define numLeds NUM_LEDS 59 | #define ledsPerLevel MATRIX_WIDTH 60 | #define levels MATRIX_HEIGHT 61 | 62 | byte currentEnergy2[numLeds]; // current energy level 63 | byte nextEnergy2[numLeds]; // next energy level 64 | byte energyMode2[numLeds]; // mode how energy is calculated for this point 65 | 66 | enum { 67 | torch_passive2 = 0, // just environment, glow from nearby radiation 68 | torch_nop2 = 1, // no processing 69 | torch_spark2= 2, // slowly looses energy, moves up 70 | torch_spark2_temp = 3, // a spark still getting energy from the level below 71 | }; 72 | 73 | inline void reduce2(byte &aByte, byte aAmount, byte aMin = 0) 74 | { 75 | int r = aByte-aAmount; 76 | if (raMax) 87 | aByte = aMax; 88 | else 89 | aByte = (byte)r; 90 | } 91 | 92 | uint16_t randomBlue(uint16_t aMinOrMax, uint16_t aMax = 0) 93 | { 94 | if (aMax==0) { 95 | aMax = aMinOrMax; 96 | aMinOrMax = 0; 97 | } 98 | uint32_t r = aMinOrMax; 99 | aMax = aMax - aMinOrMax + 1; 100 | r += rand() % aMax; 101 | return r; 102 | } 103 | 104 | void resetEnergy2() 105 | { 106 | for (int i=0; i>8; 140 | // this cell becomes active spark 141 | energyMode2[i] = torch_spark2; 142 | } 143 | else { 144 | increase2(e, spark_tfr2); 145 | } 146 | break; 147 | } 148 | case torch_passive: { 149 | e = ((int)e*heat_cap2)>>8; 150 | increase2(e, ((((int)currentEnergy2[i-1]+(int)currentEnergy2[i+1])*side_rad2)>>9) + (((int)currentEnergy2[i-ledsPerLevel]*up_rad2)>>8)); 151 | } 152 | default: 153 | break; 154 | } 155 | nextEnergy2[i++] = e; 156 | } 157 | } 158 | } 159 | 160 | const uint8_t energymap2[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 161 | 162 | void calcNextColors2() 163 | { 164 | for (int i=0; i250) 173 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 174 | else { 175 | if (e>0) { 176 | // energy to brightness is non-linear 177 | byte eb = energymap[e>>3]; 178 | byte r = red_bias2; 179 | byte g = green_bias2; 180 | byte b = blue_bias2; 181 | increase2(r, (eb*red_energy2)>>8); 182 | increase2(g, (eb*green_energy2)>>8); 183 | increase2(b, (eb*blue_energy2)>>8); 184 | leds[i] = CRGB(r, g, b); 185 | } 186 | else { 187 | // background, no energy 188 | leds[i] = CRGB(red_bg2, green_bg2, blue_bg2); 189 | } 190 | } 191 | } 192 | } 193 | 194 | void injectRandom2() 195 | { 196 | // random flame energy at bottom row 197 | for (int i=0; iaMax) 83 | aByte = aMax; 84 | else 85 | aByte = (byte)r; 86 | } 87 | 88 | uint16_t randomChemicalFire(uint16_t aMinOrMax, uint16_t aMax = 0) // not really sure if this is needed at this stage 89 | { 90 | if (aMax==0) { 91 | aMax = aMinOrMax; 92 | aMinOrMax = 0; 93 | } 94 | uint32_t r = aMinOrMax; 95 | aMax = aMax - aMinOrMax + 1; 96 | r += rand() % aMax; 97 | return r; 98 | } 99 | 100 | void resetEnergy6() 101 | { 102 | for (int i=0; i>8; 136 | // this cell becomes active spark 137 | energyModeChemicalFire[i] = torch_sparkChemicalFire; 138 | } 139 | else { 140 | increaseChemicalFire(e, spark_tfrChemicalFire); 141 | } 142 | break; 143 | } 144 | case torch_passive: { 145 | e = ((int)e*heat_capChemicalFire)>>8; 146 | increaseChemicalFire(e, ((((int)currentEnergyChemicalFire[i-1]+(int)currentEnergyChemicalFire[i+1])*side_radChemicalFire)>>9) + (((int)currentEnergyChemicalFire[i-ledsPerLevel]*up_radChemicalFire)>>8)); 147 | } 148 | default: 149 | break; 150 | } 151 | nextEnergyChemicalFire[i++] = e; 152 | } 153 | } 154 | } 155 | 156 | const uint8_t energymapChemicalFire[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 157 | 158 | void calcNextColorsChemicalFire() 159 | { 160 | for (int i=0; i250) 169 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 170 | else { 171 | if (e>0) { 172 | // energy to brightness is non-linear 173 | byte eb = energymap[e>>3]; 174 | byte r = red_biasChemicalFire; 175 | byte g = green_biasChemicalFire; 176 | byte b = blue_biasChemicalFire; 177 | increaseChemicalFire(r, (eb*red_energyChemicalFire)>>8); 178 | increaseChemicalFire(g, (eb*green_energyChemicalFire)>>8); 179 | increaseChemicalFire(b, (eb*blue_energyChemicalFire)>>8); 180 | leds[i] = CRGB(r, g, b); 181 | } 182 | else { 183 | // background, no energy 184 | leds[i] = CRGB(red_bgChemicalFire, green_bgChemicalFire, blue_bgChemicalFire); 185 | } 186 | } 187 | } 188 | } 189 | 190 | void injectRandomChemicalFire() 191 | { 192 | // random flame energy at bottom row 193 | for (int i=0; iaMax) 59 | aByte = aMax; 60 | else 61 | aByte = (byte)r; 62 | } 63 | 64 | uint16_t randomCustom6(uint16_t aMinOrMax, uint16_t aMax = 0) 65 | { 66 | if (aMax==0) { 67 | aMax = aMinOrMax; 68 | aMinOrMax = 0; 69 | } 70 | uint32_t r = aMinOrMax; 71 | aMax = aMax - aMinOrMax + 1; 72 | r += rand() % aMax; 73 | return r; 74 | } 75 | 76 | void resetEnergyCustom6() 77 | { 78 | for (int i=0; i>8; 112 | // this cell becomes active spark 113 | energyModeCustom6[i] = torch_sparkCustom6; 114 | } 115 | else { 116 | increaseCustom6(e, spark_tfrCustom6); 117 | } 118 | break; 119 | } 120 | case torch_passive: { 121 | e = ((int)e*heat_capCustom6)>>8; 122 | increaseCustom6(e, ((((int)currentEnergyCustom6[i-1]+(int)currentEnergyCustom6[i+1])*side_radCustom6)>>9) + (((int)currentEnergyCustom6[i-ledsPerLevel]*up_radCustom6)>>8)); 123 | } 124 | default: 125 | break; 126 | } 127 | nextEnergyCustom6[i++] = e; 128 | } 129 | } 130 | } 131 | 132 | const uint8_t energymapCustom6[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 133 | 134 | void calcNextColorsCustom6() 135 | { 136 | for (int i=0; i250) 145 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 146 | else { 147 | if (e>0) { 148 | // energy to brightness is non-linear 149 | byte eb = energymap[e>>3]; 150 | byte r = red_biasCustom6; 151 | byte g = green_biasCustom6; 152 | byte b = blue_biasCustom6; 153 | increaseCustom6(r, (eb*red_energyCustom6)>>8); 154 | increaseCustom6(g, (eb*green_energyCustom6)>>8); 155 | increaseCustom6(b, (eb*blue_energyCustom6)>>8); 156 | leds[i] = CRGB(r, g, b); 157 | } 158 | else { 159 | // background, no energy 160 | leds[i] = CRGB(red_bgCustom6, green_bgCustom6, blue_bgCustom6); 161 | } 162 | } 163 | } 164 | } 165 | 166 | void injectRandomCustom6() 167 | { 168 | // random flame energy at bottom row 169 | for (int i=0; iaMax) 87 | aByte = aMax; 88 | else 89 | aByte = (byte)r; 90 | } 91 | 92 | uint16_t randomGreen(uint16_t aMinOrMax, uint16_t aMax = 0) 93 | { 94 | if (aMax==0) { 95 | aMax = aMinOrMax; 96 | aMinOrMax = 0; 97 | } 98 | uint32_t r = aMinOrMax; 99 | aMax = aMax - aMinOrMax + 1; 100 | r += rand() % aMax; 101 | return r; 102 | } 103 | 104 | void resetEnergy3() 105 | { 106 | for (int i=0; i>8; 140 | // this cell becomes active spark 141 | energyMode3[i] = torch_spark3; 142 | } 143 | else { 144 | increase3(e, spark_tfr3); 145 | } 146 | break; 147 | } 148 | case torch_passive: { 149 | e = ((int)e*heat_cap3)>>8; 150 | increase3(e, ((((int)currentEnergy3[i-1]+(int)currentEnergy3[i+1])*side_rad3)>>9) + (((int)currentEnergy3[i-ledsPerLevel]*up_rad3)>>8)); 151 | } 152 | default: 153 | break; 154 | } 155 | nextEnergy3[i++] = e; 156 | } 157 | } 158 | } 159 | 160 | const uint8_t energymap3[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 161 | 162 | void calcNextColors3() 163 | { 164 | for (int i=0; i250) 173 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 174 | else { 175 | if (e>0) { 176 | // energy to brightness is non-linear 177 | byte eb = energymap[e>>3]; 178 | byte r = red_bias3; 179 | byte g = green_bias3; 180 | byte b = blue_bias3; 181 | increase3(r, (eb*red_energy3)>>8); 182 | increase3(g, (eb*green_energy3)>>8); 183 | increase3(b, (eb*blue_energy3)>>8); 184 | leds[i] = CRGB(r, g, b); 185 | } 186 | else { 187 | // background, no energy 188 | leds[i] = CRGB(red_bg3, green_bg3, blue_bg3); 189 | } 190 | } 191 | } 192 | } 193 | 194 | void injectRandom3() 195 | { 196 | // random flame energy at bottom row 197 | for (int i=0; iaMax) 83 | aByte = aMax; 84 | else 85 | aByte = (byte)r; 86 | } 87 | 88 | uint16_t random6(uint16_t aMinOrMax, uint16_t aMax = 0) 89 | { 90 | if (aMax==0) { 91 | aMax = aMinOrMax; 92 | aMinOrMax = 0; 93 | } 94 | uint32_t r = aMinOrMax; 95 | aMax = aMax - aMinOrMax + 1; 96 | r += rand() % aMax; 97 | return r; 98 | } 99 | 100 | void resetEnergy5() 101 | { 102 | for (int i=0; i>8; 136 | // this cell becomes active spark 137 | energyMode5[i] = torch_spark5; 138 | } 139 | else { 140 | increase5(e, spark_tfr5); 141 | } 142 | break; 143 | } 144 | case torch_passive: { 145 | e = ((int)e*heat_cap5)>>8; 146 | increase5(e, ((((int)currentEnergy5[i-1]+(int)currentEnergy5[i+1])*side_rad5)>>9) + (((int)currentEnergy5[i-ledsPerLevel]*up_rad5)>>8)); 147 | } 148 | default: 149 | break; 150 | } 151 | nextEnergy5[i++] = e; 152 | } 153 | } 154 | } 155 | 156 | const uint8_t energymap5[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 157 | 158 | void calcNextColors5() 159 | { 160 | for (int i=0; i250) 169 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 170 | else { 171 | if (e>0) { 172 | // energy to brightness is non-linear 173 | byte eb = energymap[e>>3]; 174 | byte r = red_bias5; 175 | byte g = green_bias5; 176 | byte b = blue_bias5; 177 | increase5(r, (eb*red_energy5)>>8); 178 | increase5(g, (eb*green_energy5)>>8); 179 | increase5(b, (eb*blue_energy5)>>8); 180 | leds[i] = CRGB(r, g, b); 181 | } 182 | else { 183 | // background, no energy 184 | leds[i] = CRGB(red_bg5, green_bg5, blue_bg5); 185 | } 186 | } 187 | } 188 | } 189 | 190 | void injectRandom5() 191 | { 192 | // random flame energy at bottom row 193 | for (int i=0; iaMax) 87 | aByte = aMax; 88 | else 89 | aByte = (byte)r; 90 | } 91 | 92 | uint16_t random5(uint16_t aMinOrMax, uint16_t aMax = 0) 93 | { 94 | if (aMax==0) { 95 | aMax = aMinOrMax; 96 | aMinOrMax = 0; 97 | } 98 | uint32_t r = aMinOrMax; 99 | aMax = aMax - aMinOrMax + 1; 100 | r += rand() % aMax; 101 | return r; 102 | } 103 | 104 | void resetEnergy4() 105 | { 106 | for (int i=0; i>8; 140 | // this cell becomes active spark 141 | energyMode4[i] = torch_spark4; 142 | } 143 | else { 144 | increase4(e, spark_tfr4); 145 | } 146 | break; 147 | } 148 | case torch_passive: { 149 | e = ((int)e*heat_cap4)>>8; 150 | increase4(e, ((((int)currentEnergy4[i-1]+(int)currentEnergy4[i+1])*side_rad4)>>9) + (((int)currentEnergy4[i-ledsPerLevel]*up_rad4)>>8)); 151 | } 152 | default: 153 | break; 154 | } 155 | nextEnergy4[i++] = e; 156 | } 157 | } 158 | } 159 | 160 | const uint8_t energymap4[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 161 | 162 | void calcNextColors4() 163 | { 164 | for (int i=0; i250) 173 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 174 | else { 175 | if (e>0) { 176 | // energy to brightness is non-linear 177 | byte eb = energymap[e>>3]; 178 | byte r = red_bias4; 179 | byte g = green_bias4; 180 | byte b = blue_bias4; 181 | increase4(r, (eb*red_energy4)>>8); 182 | increase4(g, (eb*green_energy4)>>8); 183 | increase4(b, (eb*blue_energy4)>>8); 184 | leds[i] = CRGB(r, g, b); 185 | } 186 | else { 187 | // background, no energy 188 | leds[i] = CRGB(red_bg4, green_bg4, blue_bg4); 189 | } 190 | } 191 | } 192 | } 193 | 194 | void injectRandom4() 195 | { 196 | // random flame energy at bottom row 197 | for (int i=0; iaMax) 80 | aByte = aMax; 81 | else 82 | aByte = (byte)r; 83 | } 84 | 85 | uint16_t randomRainbow(uint16_t aMinOrMax, uint16_t aMax = 0) 86 | { 87 | if (aMax==0) { 88 | aMax = aMinOrMax; 89 | aMinOrMax = 0; 90 | } 91 | uint32_t r = aMinOrMax; 92 | aMax = aMax - aMinOrMax + 1; 93 | r += rand() % aMax; 94 | return r; 95 | } 96 | 97 | void resetEnergy8() 98 | { 99 | for (int i=0; i>8; 133 | // this cell becomes active spark 134 | energyMode8[i] = torch_spark8; 135 | } 136 | else { 137 | increase8(e, spark_tfr8); 138 | } 139 | break; 140 | } 141 | case torch_passive: { 142 | e = ((int)e*heat_cap8)>>8; 143 | increase8(e, ((((int)currentEnergy8[i-1]+(int)currentEnergy8[i+1])*side_rad8)>>9) + (((int)currentEnergy8[i-ledsPerLevel]*up_rad8)>>8)); 144 | } 145 | default: 146 | break; 147 | } 148 | nextEnergy8[i++] = e; 149 | } 150 | } 151 | } 152 | 153 | const uint8_t energymap8[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 154 | 155 | void calcNextColors8() 156 | { 157 | for (int i=0; i250) 167 | leds[i] = ColorFromPalette( RainbowColors_p, 60); //CRGB(0, 15, e); // blueish extra-bright spark 168 | else { 169 | if (e>0) { 170 | // energy to brightness is non-linear 171 | byte eb = energymap[e>>3]; 172 | byte r = red_bias8; 173 | byte g = green_bias8; 174 | byte b = blue_bias8; 175 | increase8(r, (eb*red_energy8)>>8); 176 | increase8(g, (eb*green_energy8)>>8); 177 | increase8(b, (eb*blue_energy8)>>8); 178 | leds[i] = CRGB(r, g, b); 179 | } 180 | else { 181 | // background, no energy 182 | leds[i] = CRGB(red_bg8, green_bg8, blue_bg8); 183 | } 184 | } 185 | } 186 | } 187 | 188 | void injectrandom8() 189 | { 190 | // random flame energy at bottom row 191 | for (int i=0; iaMax) 87 | aByte = aMax; 88 | else 89 | aByte = (byte)r; 90 | } 91 | 92 | uint16_t randomRed(uint16_t aMinOrMax, uint16_t aMax = 0) 93 | { 94 | if (aMax==0) { 95 | aMax = aMinOrMax; 96 | aMinOrMax = 0; 97 | } 98 | uint32_t r = aMinOrMax; 99 | aMax = aMax - aMinOrMax + 1; 100 | r += rand() % aMax; 101 | return r; 102 | } 103 | 104 | void resetEnergy() 105 | { 106 | for (int i=0; i>8; 140 | // this cell becomes active spark 141 | energyMode[i] = torch_spark; 142 | } 143 | else { 144 | increase(e, spark_tfr); 145 | } 146 | break; 147 | } 148 | case torch_passive: { 149 | e = ((int)e*heat_cap)>>8; 150 | increase(e, ((((int)currentEnergy[i-1]+(int)currentEnergy[i+1])*side_rad)>>9) + (((int)currentEnergy[i-ledsPerLevel]*up_rad)>>8)); 151 | } 152 | default: 153 | break; 154 | } 155 | nextEnergy[i++] = e; 156 | } 157 | } 158 | } 159 | 160 | const uint8_t energymap[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 161 | 162 | void calcNextColors() 163 | { 164 | for (int i=0; i250) 173 | leds[i] = CRGB(170, 170, e); // blueish extra-bright spark 174 | else { 175 | if (e>0) { 176 | // energy to brightness is non-linear 177 | byte eb = energymap[e>>3]; 178 | byte r = red_bias; 179 | byte g = green_bias; 180 | byte b = blue_bias; 181 | increase(r, (eb*red_energy)>>8); 182 | increase(g, (eb*green_energy)>>8); 183 | increase(b, (eb*blue_energy)>>8); 184 | leds[i] = CRGB(r, g, b); 185 | } 186 | else { 187 | // background, no energy 188 | leds[i] = CRGB(red_bg, green_bg, blue_bg); 189 | } 190 | } 191 | } 192 | } 193 | 194 | void injectRandom() 195 | { 196 | // random flame energy at bottom row 197 | for (int i=0; iaMax) 85 | aByte = aMax; 86 | else 87 | aByte = (byte)r; 88 | } 89 | 90 | uint16_t randomFireWhite(uint16_t aMinOrMax, uint16_t aMax = 0) 91 | { 92 | if (aMax==0) { 93 | aMax = aMinOrMax; 94 | aMinOrMax = 0; 95 | } 96 | uint32_t r = aMinOrMax; 97 | aMax = aMax - aMinOrMax + 1; 98 | r += rand() % aMax; 99 | return r; 100 | } 101 | 102 | void resetEnergyFireWhite() 103 | { 104 | for (int i=0; i>8; 138 | // this cell becomes active spark 139 | energyModeFireWhite[i] = torch_sparkFireWhite; 140 | } 141 | else { 142 | increaseFireWhite(e, spark_tfrFireWhite); 143 | } 144 | break; 145 | } 146 | case torch_passiveFireWhite: { 147 | e = ((int)e*heat_capFireWhite)>>8; 148 | increaseFireWhite(e, ((((int)currentEnergyFireWhite[i-1]+(int)currentEnergyFireWhite[i+1])*side_radFireWhite)>>9) + (((int)currentEnergyFireWhite[i-ledsPerLevel]*up_radFireWhite)>>8)); 149 | } 150 | default: 151 | break; 152 | } 153 | nextEnergyFireWhite[i++] = e; 154 | } 155 | } 156 | } 157 | 158 | const uint8_t energymapFireWhite[32] = {0, 64, 96, 112, 128, 144, 152, 160, 168, 176, 184, 184, 192, 200, 200, 208, 208, 216, 216, 224, 224, 224, 232, 232, 232, 240, 240, 240, 240, 248, 248, 248}; 159 | 160 | void calcNextColorsFireWhite() 161 | { 162 | for (int i=0; i250) 171 | leds[i] = CRGB(0, 0, 0); // blueish extra-bright spark 172 | else { 173 | if (e>0) { 174 | // energy to brightness is non-linear 175 | byte eb = energymapFireWhite[e>>3]; 176 | byte r = red_biasFireWhite; 177 | byte g = green_biasFireWhite; 178 | byte b = blue_biasFireWhite; 179 | increaseFireWhite(r, (eb*red_energyFireWhite)>>8); 180 | increaseFireWhite(g, (eb*green_energyFireWhite)>>8); 181 | increaseFireWhite(b, (eb*blue_energyFireWhite)>>8); 182 | leds[i] = CRGB(r, g, b); 183 | } 184 | else { 185 | // background, no energy 186 | leds[i] = CRGB(red_bgFireWhite, green_bgFireWhite, blue_bgFireWhite); 187 | } 188 | } 189 | } 190 | } 191 | 192 | void injectRandomFireWhite() 193 | { 194 | // random flame energy at bottom row 195 | for (int i=0; i. 16 | * 17 | * ---------------------------------------------------------------------------------------------------* 18 | * 19 | * Modified by Making Things With LEDs https://www.youtube.com/@MakingThingsWithLEDs 20 | * I have left all previous comments from the original code writers in place, i ask you do the same. 21 | * If you use this code for your own projects and upload it please link back to the original sources. 22 | * 23 | * SUPPORT 24 | * Discord: https://discord.gg/SESbv89gq2 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #if FASTLED_VERSION < 3001000 33 | #error "Requires FastLED 3.1 or later; check github for latest code." 34 | #endif 35 | 36 | #define LED_PIN 11 // Edit this to your required pin number (leave at 11 recommended) 37 | #define IR_RECV_PIN 12 // Pin for use with an IR remote control 38 | #define COLOR_ORDER GRB // LED order Green, Red, Blue as default 39 | #define CHIPSET 1, WS2812B // LED Chipset if using teensy 4.0 or above add 1, if below remove 1, 40 | #define NUM_LEDS 174 // How many leds total? 41 | #define MAX_POWER_MILLIAMPS 5000 // Power Supply In m/A 1000=1amp 5000=5amp 10000=10amp etc. 42 | #define BUTTON_1_PIN 16 43 | #define BUTTON_2_PIN 17 44 | 45 | const uint8_t MATRIX_WIDTH = 6; // Edit this to your matrix width 46 | const uint8_t MATRIX_HEIGHT = 29; // Edit this to your matrix height 47 | 48 | uint16_t XY(uint8_t x, uint8_t y); 49 | void dimAll(byte value); 50 | uint16_t ColorWaves(); 51 | uint16_t Pride(); 52 | uint16_t CloudTwinkles(); 53 | uint16_t RainbowTwinkles(); 54 | uint16_t SnowTwinkles(); 55 | uint16_t IncandescentTwinkles(); 56 | uint16_t Fireflies(); 57 | uint16_t Rainbow(); 58 | uint16_t RainbowWithGlitter(); 59 | void AddGlitter(fract8 chanceOfGlitter); 60 | uint16_t Confetti(); 61 | uint16_t BPM(); 62 | uint16_t Juggle(); 63 | uint16_t ShowSolidColor(); 64 | uint16_t HueCycle(); 65 | uint16_t Sinelon(); 66 | 67 | const int MATRIX_CENTER_X = MATRIX_WIDTH / 2; 68 | const int MATRIX_CENTER_Y = MATRIX_HEIGHT / 2; 69 | 70 | const byte MATRIX_CENTRE_X = MATRIX_CENTER_X - 1; 71 | const byte MATRIX_CENTRE_Y = MATRIX_CENTER_Y - 1; 72 | 73 | const uint8_t brightnessCount = 5; 74 | uint8_t brightnessMap[brightnessCount] = { 16, 32, 64, 128, 255 }; 75 | uint8_t brightness = brightnessMap[0]; 76 | 77 | CRGB leds[NUM_LEDS + 1]; 78 | IRrecv irReceiver(IR_RECV_PIN); 79 | 80 | Bounce button1 = Bounce(); 81 | Bounce button2 = Bounce(); 82 | 83 | #include "Commands.h" 84 | #include "GradientPalettes.h" 85 | 86 | CRGB solidColor = CRGB::Purple; //Solid Colour Effect 87 | 88 | typedef uint16_t(*PatternFunctionPointer)(); 89 | typedef PatternFunctionPointer PatternList []; 90 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 91 | 92 | int autoPlayDurationSeconds = 60; // Set automatic play time per effect adjust as required 93 | unsigned int autoPlayTimeout = 10; 94 | bool autoplayEnabled = true; // Disable / Enable automatic play function, use false if you wish to use momentary switch to control effects. 95 | 96 | InputCommand command; 97 | 98 | int currentPatternIndex = 0; 99 | PatternFunctionPointer currentPattern; 100 | 101 | CRGB w(85, 85, 85), W(CRGB::White); 102 | CRGBPalette16 snowColors = CRGBPalette16( W, W, W, W, w, w, w, w, w, w, w, w, w, w, w, w ); 103 | 104 | CRGB l(0xE1A024); 105 | CRGBPalette16 incandescentColors = CRGBPalette16( l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l ); 106 | 107 | const CRGBPalette16 palettes[] = { 108 | RainbowColors_p, 109 | RainbowStripeColors_p, 110 | OceanColors_p, 111 | CloudColors_p, 112 | ForestColors_p, 113 | PartyColors_p, 114 | HeatColors_p, 115 | LavaColors_p, 116 | snowColors, 117 | }; 118 | 119 | const int paletteCount = ARRAY_SIZE(palettes); 120 | 121 | int currentPaletteIndex = 0; 122 | CRGBPalette16 palette = palettes[0]; 123 | 124 | uint8_t gHue = 0; // rotating "base color" used by many of the patterns 125 | 126 | #include "Drawing.h" 127 | #include "Effects.h" 128 | #include "Noise.h" 129 | #include "Pulse.h" 130 | #include "Wave.h" 131 | #include "Fire2012WithPalette.h" 132 | #include "Fire2012Rainbow.h" 133 | #include "FireWhite.h" 134 | #include "FireRed.h" 135 | #include "FireGreen.h" 136 | #include "FireBlue.h" 137 | #include "FireElectricBlue.h" 138 | #include "FireChemical.h" 139 | #include "FireRainbow.h" 140 | #include "FirePurple.h" 141 | #include "FireOrange.h" 142 | #include "AudioLogic.h" 143 | #include "AudioPatterns.h" 144 | //===================================================================================================================================================START EFFECT PLAYLIST 145 | // EFFECTS LISTS // In automatic mode will display in order of the list. 146 | const PatternList patterns = { // remove or add // to enable/disable effects 147 | 148 | Analogous1, 149 | Aurora, 150 | BlackAndWhite, 151 | Calbayo15, 152 | Cloud, 153 | ColorCube, 154 | ColorWaves, 155 | CoralReef, 156 | Curvature, 157 | DeepSea, 158 | Fire2012Rainbow1, 159 | FireElectricBlue, 160 | FireBlue, 161 | FireChemical, 162 | FireGreen, 163 | FireOrange, 164 | FirePurple, 165 | FireRed, 166 | FireWhite, 167 | Forest, 168 | Lava, 169 | LavaLampRainbow, 170 | LavaLampRainbowStripe, 171 | Ocean, 172 | OceanBreeze, 173 | Party, 174 | RampRGB, 175 | Rstcurv, 176 | Shikon22, 177 | Shikon23, 178 | Spectrum, 179 | Temperature, 180 | Vintage49, 181 | 182 | //--Sound-Reactive-Effects-- 183 | // AudioAnalyzerColumns, 184 | // AudioAnalyzerColumnsSolid, 185 | // AudioAnalyzerPixels, 186 | // AudioBlackAndBlue, 187 | // AudioBlackAndWhite, 188 | // AudioCloud, 189 | // AudioFallingSpectrogram, 190 | // AudioFire1, 191 | // AudioFire2, 192 | // AudioFire3, 193 | // AudioForest, 194 | // AudioLava, 195 | // AudioLava2, 196 | // AudioLavaMagenta, 197 | // AudioLavaRainbow, 198 | // AudioOcean, 199 | // AudioParty, 200 | // AudioRainbowStripe, 201 | 202 | //---Additional-Effects--- 203 | // BPM, 204 | // CloudTwinkles, 205 | // Confetti, 206 | // Fire2012WithPalette, 207 | // Fireflies, 208 | // FireNoise, 209 | // HueCycle, 210 | // IncandescentTwinkles, 211 | // Juggle, 212 | // Pride, 213 | // Pulse, 214 | // Rainbow, 215 | // RainbowTwinkles, 216 | // RainbowWithGlitter, 217 | // ShowSolidColor, 218 | // Sinelon, 219 | // SnowTwinkles, 220 | // Wave, 221 | 222 | }; 223 | //===================================================================================================================================================END EFFECT PLAYLIST 224 | const int patternCount = ARRAY_SIZE(patterns); 225 | 226 | void setup() { 227 | delay(1000); // sanity delay 228 | // Serial.begin(9600); 229 | // Serial.println("setup start"); 230 | 231 | loadSettings(); 232 | 233 | FastLED.addLeds(leds, NUM_LEDS); 234 | FastLED.setCorrection(TypicalLEDStrip); 235 | FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_POWER_MILLIAMPS); // Voltage, MAX_POWER_MILLIAMPS 236 | // FastLED.setBrightness(brightness); 237 | // FastLED.setDither(brightness < 255); 238 | 239 | // Initialize the IR receiver 240 | irReceiver.enableIRIn(); 241 | irReceiver.blink13(true); 242 | 243 | pinMode(BUTTON_1_PIN, INPUT_PULLUP); 244 | pinMode(BUTTON_2_PIN, INPUT_PULLUP); 245 | button1.attach(BUTTON_1_PIN); 246 | button2.attach(BUTTON_2_PIN); 247 | button1.interval(5); 248 | button2.interval(5); 249 | 250 | currentPattern = patterns[currentPatternIndex]; 251 | autoPlayTimeout = millis() + (autoPlayDurationSeconds * 1000); 252 | 253 | initializeAudio(); 254 | 255 | // Serial.println("setup end"); 256 | } 257 | 258 | void loop() { 259 | // Add entropy to random number generator; we use a lot of it. 260 | random16_add_entropy(random()); 261 | 262 | EVERY_N_MILLISECONDS(30) { 263 | readAudio(); 264 | } 265 | 266 | uint16_t requestedDelay = currentPattern(); 267 | 268 | FastLED.show(); // display this frame 269 | 270 | handleInput(requestedDelay); 271 | 272 | if (autoplayEnabled && millis() > autoPlayTimeout) { 273 | move(1); 274 | autoPlayTimeout = millis() + (autoPlayDurationSeconds * 1000); 275 | } 276 | 277 | // do some periodic updates 278 | EVERY_N_MILLISECONDS(20) { 279 | gHue++; // slowly cycle the "base color" through the rainbow 280 | } 281 | } 282 | 283 | void loadSettings() { 284 | // load settings from EEPROM 285 | 286 | // brightness 287 | brightness = EEPROM.read(0); 288 | if (brightness < 1) 289 | brightness = 1; 290 | else if (brightness > 255) 291 | brightness = 255; 292 | 293 | // currentPatternIndex 294 | currentPatternIndex = EEPROM.read(1); 295 | if (currentPatternIndex < 0) 296 | currentPatternIndex = 0; 297 | else if (currentPatternIndex >= patternCount) 298 | currentPatternIndex = patternCount - 1; 299 | 300 | // solidColor 301 | solidColor.r = EEPROM.read(2); 302 | solidColor.g = EEPROM.read(3); 303 | solidColor.b = EEPROM.read(4); 304 | 305 | if (solidColor.r == 0 && solidColor.g == 0 && solidColor.b == 0) 306 | solidColor = CRGB::White; 307 | } 308 | 309 | void setSolidColor(CRGB color) { 310 | solidColor = color; 311 | 312 | EEPROM.write(2, solidColor.r); 313 | EEPROM.write(3, solidColor.g); 314 | EEPROM.write(4, solidColor.b); 315 | 316 | moveTo(patternCount - 1); 317 | } 318 | 319 | void powerOff() 320 | { 321 | // clear the display 322 | const uint8_t stepSize = 4; 323 | 324 | for (uint8_t i = 0; i < NUM_LEDS / 2 - stepSize; i += stepSize) { 325 | for (uint8_t j = 0; j < stepSize; j++) { 326 | leds[i + j] = CRGB::Black; 327 | leds[(NUM_LEDS - 1) - (i + j)] = CRGB::Black; 328 | } 329 | FastLED.show(); // display this frame 330 | } 331 | 332 | fill_solid(leds, NUM_LEDS, CRGB::Black); 333 | 334 | FastLED.show(); // display this frame 335 | 336 | while (true) { 337 | // check for physical button input 338 | button1.update(); 339 | button2.update(); 340 | 341 | if (button1.rose() || button2.rose()) { 342 | Serial.println("Button released"); 343 | return; 344 | } 345 | 346 | // check for ir remote input 347 | InputCommand command = readCommand(); 348 | if (command != InputCommand::None) 349 | return; 350 | } 351 | } 352 | 353 | void move(int delta) { 354 | moveTo(currentPatternIndex + delta); 355 | } 356 | 357 | void moveTo(int index) { 358 | currentPatternIndex = index; 359 | 360 | if (currentPatternIndex >= patternCount) 361 | currentPatternIndex = 0; 362 | else if (currentPatternIndex < 0) 363 | currentPatternIndex = patternCount - 1; 364 | 365 | currentPattern = patterns[currentPatternIndex]; 366 | 367 | fill_solid(leds, NUM_LEDS, CRGB::Black); 368 | 369 | EEPROM.write(1, currentPatternIndex); 370 | } 371 | 372 | int getBrightnessLevel() { 373 | int level = 0; 374 | for (int i = 0; i < brightnessCount; i++) { 375 | if (brightnessMap[i] >= brightness) { 376 | level = i; 377 | break; 378 | } 379 | } 380 | return level; 381 | } 382 | 383 | uint8_t cycleBrightness() { 384 | adjustBrightness(1); 385 | 386 | if (brightness == brightnessMap[0]) 387 | return 0; 388 | 389 | return brightness; 390 | } 391 | 392 | void adjustBrightness(int delta) { 393 | int level = getBrightnessLevel(); 394 | 395 | level += delta; 396 | 397 | // don't wrap 398 | if (level < 0) 399 | level = 0; 400 | if (level >= brightnessCount) 401 | level = brightnessCount - 1; 402 | 403 | brightness = brightnessMap[level]; 404 | FastLED.setBrightness(brightness); 405 | FastLED.setDither(brightness < 255); 406 | 407 | EEPROM.write(0, brightness); 408 | } 409 | 410 | void cyclePalette(int delta = 1) { 411 | if (currentPaletteIndex == 0 && delta < 0) 412 | currentPaletteIndex = paletteCount - 1; 413 | else if (currentPaletteIndex >= paletteCount - 1 && delta > 0) 414 | currentPaletteIndex = 0; 415 | else 416 | currentPaletteIndex += delta; 417 | 418 | if (currentPaletteIndex >= paletteCount) 419 | currentPaletteIndex = 0; 420 | 421 | palette = palettes[currentPaletteIndex]; 422 | } 423 | 424 | unsigned long button1PressTimeStamp; 425 | unsigned long button2PressTimeStamp; 426 | 427 | void handleInput(unsigned int requestedDelay) { 428 | unsigned int requestedDelayTimeout = millis() + requestedDelay; 429 | 430 | while (true) { 431 | // check for physical button input 432 | button1.update(); 433 | button2.update(); 434 | 435 | if (button1.fell()) { 436 | Serial.println("Button 1 depressed"); 437 | button1PressTimeStamp = millis(); 438 | } 439 | 440 | if (button2.fell()) { 441 | Serial.println("Button 2 depressed"); 442 | button2PressTimeStamp = millis(); 443 | } 444 | 445 | if (button1.rose()) { 446 | Serial.println("Button 1 released"); 447 | move(1); 448 | } 449 | 450 | if (button2.rose()) { 451 | Serial.println("Button 2 released"); 452 | powerOff(); 453 | break; 454 | } 455 | 456 | command = readCommand(defaultHoldDelay); 457 | 458 | if (command != InputCommand::None) { 459 | // Serial.print("command: "); 460 | // Serial.println((int) command); 461 | } 462 | 463 | if (command == InputCommand::Up) { 464 | move(1); 465 | break; 466 | } 467 | else if (command == InputCommand::Down) { 468 | move(-1); 469 | break; 470 | } 471 | else if (command == InputCommand::Brightness) { 472 | if (isHolding || cycleBrightness() == 0) { 473 | heldButtonHasBeenHandled(); 474 | powerOff(); 475 | break; 476 | } 477 | } 478 | else if (command == InputCommand::Power) { 479 | powerOff(); 480 | break; 481 | } 482 | else if (command == InputCommand::BrightnessUp) { 483 | adjustBrightness(1); 484 | } 485 | else if (command == InputCommand::BrightnessDown) { 486 | adjustBrightness(-1); 487 | } 488 | else if (command == InputCommand::PlayMode) { // toggle pause/play 489 | autoplayEnabled = !autoplayEnabled; 490 | } 491 | else if (command == InputCommand::NextPalette) { // cycle color palette 492 | cyclePalette(1); 493 | } 494 | else if (command == InputCommand::PreviousPalette) { // cycle color palette 495 | cyclePalette(-1); 496 | } 497 | 498 | // pattern buttons 499 | 500 | else if (command == InputCommand::Pattern1) { 501 | moveTo(0); 502 | break; 503 | } 504 | else if (command == InputCommand::Pattern2) { 505 | moveTo(1); 506 | break; 507 | } 508 | else if (command == InputCommand::Pattern3) { 509 | moveTo(2); 510 | break; 511 | } 512 | else if (command == InputCommand::Pattern4) { 513 | moveTo(3); 514 | break; 515 | } 516 | else if (command == InputCommand::Pattern5) { 517 | moveTo(4); 518 | break; 519 | } 520 | else if (command == InputCommand::Pattern6) { 521 | moveTo(5); 522 | break; 523 | } 524 | else if (command == InputCommand::Pattern7) { 525 | moveTo(6); 526 | break; 527 | } 528 | else if (command == InputCommand::Pattern8) { 529 | moveTo(7); 530 | break; 531 | } 532 | else if (command == InputCommand::Pattern9) { 533 | moveTo(8); 534 | break; 535 | } 536 | else if (command == InputCommand::Pattern10) { 537 | moveTo(9); 538 | break; 539 | } 540 | else if (command == InputCommand::Pattern11) { 541 | moveTo(10); 542 | break; 543 | } 544 | else if (command == InputCommand::Pattern12) { 545 | moveTo(11); 546 | break; 547 | } 548 | 549 | // custom color adjustment buttons 550 | 551 | else if (command == InputCommand::RedUp) { 552 | solidColor.red += 1; 553 | setSolidColor(solidColor); 554 | break; 555 | } 556 | else if (command == InputCommand::RedDown) { 557 | solidColor.red -= 1; 558 | setSolidColor(solidColor); 559 | break; 560 | } 561 | else if (command == InputCommand::GreenUp) { 562 | solidColor.green += 1; 563 | setSolidColor(solidColor); \ 564 | break; 565 | } 566 | else if (command == InputCommand::GreenDown) { 567 | solidColor.green -= 1; 568 | setSolidColor(solidColor); 569 | break; 570 | } 571 | else if (command == InputCommand::BlueUp) { 572 | solidColor.blue += 1; 573 | setSolidColor(solidColor); 574 | break; 575 | } 576 | else if (command == InputCommand::BlueDown) { 577 | solidColor.blue -= 1; 578 | setSolidColor(solidColor); 579 | break; 580 | } 581 | 582 | // color buttons 583 | 584 | 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 585 | setSolidColor(CRGB::Red); 586 | break; 587 | } 588 | else if (command == InputCommand::RedOrange) { 589 | setSolidColor(CRGB::OrangeRed); 590 | break; 591 | } 592 | else if (command == InputCommand::Orange) { 593 | setSolidColor(CRGB::Orange); 594 | break; 595 | } 596 | else if (command == InputCommand::YellowOrange) { 597 | setSolidColor(CRGB::Goldenrod); 598 | break; 599 | } 600 | else if (command == InputCommand::Yellow) { 601 | setSolidColor(CRGB::Yellow); 602 | break; 603 | } 604 | 605 | 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 606 | setSolidColor(CRGB::Green); 607 | break; 608 | } 609 | else if (command == InputCommand::Lime) { 610 | setSolidColor(CRGB::Lime); 611 | break; 612 | } 613 | else if (command == InputCommand::Aqua) { 614 | setSolidColor(CRGB::Aqua); 615 | break; 616 | } 617 | else if (command == InputCommand::Teal) { 618 | setSolidColor(CRGB::Teal); 619 | break; 620 | } 621 | else if (command == InputCommand::Navy) { 622 | setSolidColor(CRGB::Navy); 623 | break; 624 | } 625 | 626 | 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 627 | setSolidColor(CRGB::Blue); 628 | break; 629 | } 630 | else if (command == InputCommand::RoyalBlue) { 631 | setSolidColor(CRGB::RoyalBlue); 632 | break; 633 | } 634 | else if (command == InputCommand::Purple) { 635 | setSolidColor(CRGB::Purple); 636 | break; 637 | } 638 | else if (command == InputCommand::Indigo) { 639 | setSolidColor(CRGB::Indigo); 640 | break; 641 | } 642 | else if (command == InputCommand::Magenta) { 643 | setSolidColor(CRGB::Magenta); 644 | break; 645 | } 646 | 647 | else if (command == InputCommand::White && currentPatternIndex != patternCount - 2 && currentPatternIndex != patternCount - 3) { 648 | setSolidColor(CRGB::White); 649 | break; 650 | } 651 | else if (command == InputCommand::Pink) { 652 | setSolidColor(CRGB::Pink); 653 | break; 654 | } 655 | else if (command == InputCommand::LightPink) { 656 | setSolidColor(CRGB::LightPink); 657 | break; 658 | } 659 | else if (command == InputCommand::BabyBlue) { 660 | setSolidColor(CRGB::CornflowerBlue); 661 | break; 662 | } 663 | else if (command == InputCommand::LightBlue) { 664 | setSolidColor(CRGB::LightBlue); 665 | break; 666 | } 667 | 668 | if (millis() >= requestedDelayTimeout) 669 | break; 670 | } 671 | } 672 | 673 | uint16_t XY( uint8_t x, uint8_t y) // maps the matrix to the strip 674 | { 675 | uint16_t i; 676 | i = (y * MATRIX_WIDTH) + (MATRIX_WIDTH - x); 677 | 678 | i = (NUM_LEDS - 1) - i; 679 | 680 | if (i > NUM_LEDS) 681 | i = NUM_LEDS; 682 | 683 | return i; 684 | } 685 | 686 | // scale the brightness of the screenbuffer down 687 | void dimAll(byte value) 688 | { 689 | for (int i = 0; i < NUM_LEDS; i++) { 690 | leds[i].nscale8(value); 691 | } 692 | } 693 | //=============================================== 694 | uint16_t ShowSolidColor() { 695 | fill_solid(leds, NUM_LEDS, solidColor); 696 | 697 | return 60; 698 | } 699 | //=============================================== 700 | uint16_t Rainbow() 701 | { 702 | // FastLED's built-in rainbow generator 703 | fill_rainbow(leds, NUM_LEDS, gHue, 1); 704 | 705 | return 8; 706 | } 707 | //=============================================== 708 | uint16_t RainbowWithGlitter() 709 | { 710 | // built-in FastLED rainbow, plus some random sparkly glitter 711 | Rainbow(); 712 | AddGlitter(80); 713 | return 8; 714 | } 715 | //=============================================== 716 | void AddGlitter(fract8 chanceOfGlitter) 717 | { 718 | if (random8() < chanceOfGlitter) { 719 | leds[random16(NUM_LEDS)] += CRGB::White; 720 | } 721 | } 722 | //=============================================== 723 | uint16_t Confetti() 724 | { 725 | // random colored speckles that blink in and fade smoothly 726 | fadeToBlackBy(leds, NUM_LEDS, 10); 727 | int pos = random16(NUM_LEDS); 728 | leds[pos] += ColorFromPalette(palette, gHue + random8(64), 255); // CHSV(gHue + random8(64), 200, 255); 729 | return 8; 730 | } 731 | //=============================================== 732 | uint16_t BPM() 733 | { 734 | // colored stripes pulsing at a defined Beats-Per-Minute (BPM) 735 | uint8_t BeatsPerMinute = 62; 736 | uint8_t beat = beatsin8(BeatsPerMinute, 64, 255); 737 | for (int i = 0; i < NUM_LEDS; i++) { //9948 738 | leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10)); 739 | } 740 | return 8; 741 | } 742 | //=============================================== 743 | uint16_t Juggle() { 744 | // N colored dots, weaving in and out of sync with each other 745 | fadeToBlackBy(leds, NUM_LEDS, 20); 746 | byte dothue = 1; 747 | byte dotCount = 3; 748 | for (int i = 0; i < dotCount; i++) { 749 | leds[beatsin16(i + dotCount - 1, 0, NUM_LEDS)] |= CHSV(dothue, 200, 255); 750 | dothue += 256 / dotCount; 751 | } 752 | return 0; 753 | } 754 | //=============================================== 755 | // An animation to play while the crowd goes wild after the big performance 756 | uint16_t Applause() 757 | { 758 | static uint16_t lastPixel = 0; 759 | fadeToBlackBy(leds, NUM_LEDS, 32); 760 | leds[lastPixel] = CHSV(random8(HUE_BLUE, HUE_PURPLE), 255, 255); 761 | lastPixel = random16(NUM_LEDS); 762 | leds[lastPixel] = CRGB::White; 763 | return 8; 764 | } 765 | //=============================================== 766 | // An "animation" to just fade to black. Useful as the last track 767 | // in a non-looping performance-oriented playlist. 768 | uint16_t fadeToBlack() 769 | { 770 | fadeToBlackBy(leds, NUM_LEDS, 10); 771 | return 8; 772 | } 773 | //=============================================== 774 | uint16_t Sinelon() 775 | { 776 | // a colored dot sweeping back and forth, with fading trails 777 | fadeToBlackBy( leds, NUM_LEDS, 20); 778 | uint16_t pos = beatsin16(13, 0, NUM_LEDS); 779 | static uint16_t prevpos = 0; 780 | if ( pos < prevpos ) { 781 | fill_solid( leds + pos, (prevpos - pos) + 1, CHSV(gHue, 220, 255)); 782 | } else { 783 | fill_solid( leds + prevpos, (pos - prevpos) + 1, CHSV( gHue, 220, 255)); 784 | } 785 | prevpos = pos; 786 | 787 | return 8; 788 | } 789 | //=============================================== 790 | uint16_t HueCycle() { 791 | fill_solid(leds, NUM_LEDS, CHSV(gHue, 255, 255)); 792 | return 60; 793 | } 794 | //=============================================== 795 | // Pride2015 by Mark Kriegsman 796 | // https://gist.github.com/kriegsman/964de772d64c502760e5 797 | 798 | // This function draws rainbows with an ever-changing, 799 | // widely-varying set of parameters. 800 | uint16_t Pride() 801 | { 802 | static uint16_t sPseudotime = 0; 803 | static uint16_t sLastMillis = 0; 804 | static uint16_t sHue16 = 0; 805 | 806 | uint8_t sat8 = beatsin88(87, 220, 250); 807 | uint8_t brightdepth = beatsin88(341, 96, 224); 808 | uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256)); 809 | uint8_t msmultiplier = beatsin88(147, 23, 60); 810 | 811 | uint16_t hue16 = sHue16;//gHue * 256; 812 | uint16_t hueinc16 = beatsin88(113, 1, 3000); 813 | 814 | uint16_t ms = millis(); 815 | uint16_t deltams = ms - sLastMillis; 816 | sLastMillis = ms; 817 | sPseudotime += deltams * msmultiplier; 818 | sHue16 += deltams * beatsin88(400, 5, 9); 819 | uint16_t brightnesstheta16 = sPseudotime; 820 | 821 | for (int i = 0; i < NUM_LEDS; i++) { 822 | hue16 += hueinc16; 823 | uint8_t hue8 = hue16 / 256; 824 | 825 | brightnesstheta16 += brightnessthetainc16; 826 | uint16_t b16 = sin16(brightnesstheta16) + 32768; 827 | 828 | uint16_t bri16 = (uint32_t) ((uint32_t) b16 * (uint32_t) b16) / 65536; 829 | uint8_t bri8 = (uint32_t) (((uint32_t) bri16) * brightdepth) / 65536; 830 | bri8 += (255 - brightdepth); 831 | 832 | CRGB newcolor = CHSV(hue8, sat8, bri8); 833 | 834 | uint8_t pixelnumber = i; 835 | pixelnumber = (NUM_LEDS - 1) - pixelnumber; 836 | 837 | nblend(leds[pixelnumber], newcolor, 64); 838 | } 839 | 840 | return 0; 841 | } 842 | 843 | /////////////////////////////////////////////////////////////////////// 844 | 845 | // Forward declarations of an array of cpt-city gradient palettes, and 846 | // a count of how many there are. The actual color palette definitions 847 | // are at the bottom of this file. 848 | extern const TProgmemRGBGradientPalettePtr gGradientPalettes[]; 849 | extern const uint8_t gGradientPaletteCount; 850 | 851 | // Current palette number from the 'playlist' of color palettes 852 | uint8_t gCurrentPaletteNumber = 0; 853 | 854 | CRGBPalette16 gCurrentPalette( CRGB::Black); 855 | CRGBPalette16 gTargetPalette( gGradientPalettes[0] ); 856 | 857 | // ten seconds per color palette makes a good demo 858 | // 20-120 is better for deployment 859 | #define SECONDS_PER_PALETTE 10 860 | 861 | uint16_t ColorWaves() 862 | { 863 | EVERY_N_SECONDS( SECONDS_PER_PALETTE ) { 864 | gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount); 865 | gTargetPalette = gGradientPalettes[ gCurrentPaletteNumber ]; 866 | } 867 | 868 | EVERY_N_MILLISECONDS(40) { 869 | nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 16); 870 | } 871 | 872 | Colorwaves( leds, NUM_LEDS, gCurrentPalette); 873 | 874 | return 20; 875 | } 876 | 877 | 878 | // This function draws color waves with an ever-changing, 879 | // widely-varying set of parameters, using a color palette. 880 | void Colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette) 881 | { 882 | static uint16_t sPseudotime = 0; 883 | static uint16_t sLastMillis = 0; 884 | static uint16_t sHue16 = 0; 885 | 886 | // uint8_t sat8 = beatsin88( 87, 220, 250); 887 | uint8_t brightdepth = beatsin88( 341, 96, 224); 888 | uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); 889 | uint8_t msmultiplier = beatsin88(147, 23, 60); 890 | 891 | uint16_t hue16 = sHue16;//gHue * 256; 892 | uint16_t hueinc16 = beatsin88(113, 300, 1500); 893 | 894 | uint16_t ms = millis(); 895 | uint16_t deltams = ms - sLastMillis ; 896 | sLastMillis = ms; 897 | sPseudotime += deltams * msmultiplier; 898 | sHue16 += deltams * beatsin88( 400, 5, 9); 899 | uint16_t brightnesstheta16 = sPseudotime; 900 | 901 | for ( uint16_t i = 0 ; i < numleds; i++) { 902 | hue16 += hueinc16; 903 | uint8_t hue8 = hue16 / 256; 904 | uint16_t h16_128 = hue16 >> 7; 905 | if ( h16_128 & 0x100) { 906 | hue8 = 255 - (h16_128 >> 1); 907 | } else { 908 | hue8 = h16_128 >> 1; 909 | } 910 | 911 | brightnesstheta16 += brightnessthetainc16; 912 | uint16_t b16 = sin16( brightnesstheta16 ) + 32768; 913 | 914 | uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; 915 | uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; 916 | bri8 += (255 - brightdepth); 917 | 918 | uint8_t index = hue8; 919 | //index = triwave8( index); 920 | index = scale8( index, 240); 921 | 922 | CRGB newcolor = ColorFromPalette( palette, index, bri8); 923 | 924 | uint16_t pixelnumber = i; 925 | pixelnumber = (numleds - 1) - pixelnumber; 926 | 927 | nblend( ledarray[pixelnumber], newcolor, 128); 928 | } 929 | } 930 | 931 | // Alternate rendering function just scrolls the current palette 932 | // across the defined LED strip. 933 | void palettetest( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& gCurrentPalette) 934 | { 935 | static uint8_t startindex = 0; 936 | startindex--; 937 | fill_palette( ledarray, numleds, startindex, (256 / NUM_LEDS) + 1, gCurrentPalette, 255, LINEARBLEND); 938 | } 939 | 940 | #define STARTING_BRIGHTNESS 64 941 | #define FADE_IN_SPEED 32 942 | #define FADE_OUT_SPEED 20 943 | uint8_t DENSITY = 255; 944 | //=============================================== 945 | uint16_t CloudTwinkles() 946 | { 947 | DENSITY = 255; 948 | colortwinkles(CloudColors_p); 949 | return 20; 950 | } 951 | //=============================================== 952 | uint16_t RainbowTwinkles() 953 | { 954 | DENSITY = 255; 955 | colortwinkles(RainbowColors_p); 956 | return 20; 957 | } 958 | //=============================================== 959 | uint16_t SnowTwinkles() 960 | { 961 | DENSITY = 255; 962 | colortwinkles(snowColors); 963 | return 20; 964 | } 965 | //=============================================== 966 | uint16_t IncandescentTwinkles() 967 | { 968 | DENSITY = 255; 969 | colortwinkles(incandescentColors); 970 | return 20; 971 | } 972 | //=============================================== 973 | uint16_t Fireflies() 974 | { 975 | DENSITY = 16; 976 | colortwinkles(incandescentColors); 977 | return 20; 978 | } 979 | //=============================================== 980 | enum { GETTING_DARKER = 0, GETTING_BRIGHTER = 1 }; 981 | 982 | void colortwinkles(CRGBPalette16 palette) 983 | { 984 | // Make each pixel brighter or darker, depending on 985 | // its 'direction' flag. 986 | brightenOrDarkenEachPixel( FADE_IN_SPEED, FADE_OUT_SPEED); 987 | 988 | // Now consider adding a new random twinkle 989 | if ( random8() < DENSITY ) { 990 | int pos = random16(NUM_LEDS); 991 | if ( !leds[pos]) { 992 | leds[pos] = ColorFromPalette( palette, random8(), STARTING_BRIGHTNESS, NOBLEND); 993 | setPixelDirection(pos, GETTING_BRIGHTER); 994 | } 995 | } 996 | } 997 | 998 | void brightenOrDarkenEachPixel( fract8 fadeUpAmount, fract8 fadeDownAmount) 999 | { 1000 | for ( uint16_t i = 0; i < NUM_LEDS; i++) { 1001 | if ( getPixelDirection(i) == GETTING_DARKER) { 1002 | // This pixel is getting darker 1003 | leds[i] = makeDarker( leds[i], fadeDownAmount); 1004 | } else { 1005 | // This pixel is getting brighter 1006 | leds[i] = makeBrighter( leds[i], fadeUpAmount); 1007 | // now check to see if we've maxxed out the brightness 1008 | if ( leds[i].r == 255 || leds[i].g == 255 || leds[i].b == 255) { 1009 | // if so, turn around and start getting darker 1010 | setPixelDirection(i, GETTING_DARKER); 1011 | } 1012 | } 1013 | } 1014 | } 1015 | 1016 | CRGB makeBrighter( const CRGB& color, fract8 howMuchBrighter) 1017 | { 1018 | CRGB incrementalColor = color; 1019 | incrementalColor.nscale8( howMuchBrighter); 1020 | return color + incrementalColor; 1021 | } 1022 | 1023 | CRGB makeDarker( const CRGB& color, fract8 howMuchDarker) 1024 | { 1025 | CRGB newcolor = color; 1026 | newcolor.nscale8( 255 - howMuchDarker); 1027 | return newcolor; 1028 | } 1029 | 1030 | // Compact implementation of 1031 | // the directionFlags array, using just one BIT of RAM 1032 | // per pixel. This requires a bunch of bit wrangling, 1033 | // but conserves precious RAM. The cost is a few 1034 | // cycles and about 100 bytes of flash program memory. 1035 | uint8_t directionFlags[ (NUM_LEDS + 7) / 8]; 1036 | 1037 | bool getPixelDirection( uint16_t i) { 1038 | uint16_t index = i / 8; 1039 | uint8_t bitNum = i & 0x07; 1040 | 1041 | uint8_t andMask = 1 << bitNum; 1042 | return (directionFlags[index] & andMask) != 0; 1043 | } 1044 | 1045 | void setPixelDirection( uint16_t i, bool dir) { 1046 | uint16_t index = i / 8; 1047 | uint8_t bitNum = i & 0x07; 1048 | 1049 | uint8_t orMask = 1 << bitNum; 1050 | uint8_t andMask = 255 - orMask; 1051 | uint8_t value = directionFlags[index] & andMask; 1052 | if ( dir ) { 1053 | value += orMask; 1054 | } 1055 | directionFlags[index] = value; 1056 | } 1057 | -------------------------------------------------------------------------------- /Noise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #define MAX_DIMENSION ((MATRIX_WIDTH > MATRIX_HEIGHT) ? MATRIX_WIDTH : MATRIX_HEIGHT) 20 | 21 | // The 16 bit version of our coordinates 22 | static uint16_t noisex; 23 | static uint16_t noisey; 24 | static uint16_t noisez; 25 | 26 | // We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll 27 | // use the z-axis for "time". speed determines how fast time moves forward. Try 28 | // 1 for a very slow moving effect, or 60 for something that ends up looking like 29 | // water. 30 | uint32_t noisespeedx = 1; 31 | uint32_t noisespeedy = 1; 32 | uint32_t noisespeedz = 1; 33 | 34 | // Scale determines how far apart the pixels in our noise matrix are. Try 35 | // changing these values around to see how it affects the motion of the display. The 36 | // higher the value of scale, the more "zoomed out" the noise will be. A value 37 | // of 1 will be so zoomed in, you'll mostly see solid colors. 38 | uint16_t noisescale = 30; // scale is set dynamically once we've started up 39 | 40 | // This is the array that we keep our computed noise values in 41 | uint8_t noise[MAX_DIMENSION][MAX_DIMENSION]; 42 | 43 | uint8_t colorLoop = 0; 44 | 45 | CRGBPalette16 blackAndWhiteStripedPalette; 46 | 47 | // This function sets up a palette of black and white stripes, 48 | // using code. Since the palette is effectively an array of 49 | // sixteen CRGB colors, the various fill_* functions can be used 50 | // to set them up. 51 | void SetupBlackAndWhiteStripedPalette() 52 | { 53 | // 'black out' all 16 palette entries... 54 | fill_solid( blackAndWhiteStripedPalette, 16, CRGB::Black); 55 | // and set every fourth one to white. 56 | blackAndWhiteStripedPalette[0] = CRGB::White; 57 | blackAndWhiteStripedPalette[4] = CRGB::White; 58 | blackAndWhiteStripedPalette[8] = CRGB::White; 59 | blackAndWhiteStripedPalette[12] = CRGB::White; 60 | 61 | } 62 | 63 | CRGBPalette16 blackAndBlueStripedPalette; 64 | 65 | // This function sets up a palette of black and blue stripes, 66 | // using code. Since the palette is effectively an array of 67 | // sixteen CRGB colors, the various fill_* functions can be used 68 | // to set them up. 69 | void SetupBlackAndBlueStripedPalette() 70 | { 71 | // 'black out' all 16 palette entries... 72 | fill_solid( blackAndBlueStripedPalette, 16, CRGB::Black); 73 | 74 | for(uint8_t i = 0; i < 6; i++) { 75 | blackAndBlueStripedPalette[i] = CRGB::Blue; 76 | } 77 | } 78 | 79 | // There are several different palettes of colors demonstrated here. 80 | // 81 | // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p, 82 | // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p. 83 | // 84 | // Additionally, you can manually define your own color palettes, or you can write 85 | // code that creates color palettes on the fly. 86 | 87 | boolean initialized = false; 88 | 89 | // Fill the x/y array of 8-bit noise values using the inoise8 function. 90 | void fillnoise8() { 91 | 92 | if(!initialized) { 93 | initialized = true; 94 | // Initialize our coordinates to some random values 95 | noisex = random16(); 96 | noisey = random16(); 97 | noisez = random16(); 98 | } 99 | 100 | // If we're runing at a low "speed", some 8-bit artifacts become visible 101 | // from frame-to-frame. In order to reduce this, we can do some fast data-smoothing. 102 | // The amount of data smoothing we're doing depends on "speed". 103 | uint8_t dataSmoothing = 0; 104 | uint16_t lowestNoise = noisespeedx < noisespeedy ? noisespeedx : noisespeedy; 105 | lowestNoise = lowestNoise < noisespeedz ? lowestNoise : noisespeedz; 106 | if( lowestNoise < 8) { 107 | dataSmoothing = 200 - (lowestNoise * 4); 108 | } 109 | 110 | for(int i = 0; i < MAX_DIMENSION; i++) { 111 | int ioffset = noisescale * i; 112 | for(int j = 0; j < MAX_DIMENSION; j++) { 113 | int joffset = noisescale * j; 114 | 115 | uint8_t data = inoise8(noisex + ioffset, noisey + joffset, noisez); 116 | 117 | // The range of the inoise8 function is roughly 16-238. 118 | // These two operations expand those values out to roughly 0..255 119 | // You can comment them out if you want the raw noise data. 120 | data = qsub8(data,16); 121 | data = qadd8(data,scale8(data,39)); 122 | 123 | if( dataSmoothing ) { 124 | uint8_t olddata = noise[i][j]; 125 | uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing); 126 | data = newdata; 127 | } 128 | 129 | noise[i][j] = data; 130 | } 131 | } 132 | 133 | noisex += noisespeedx; 134 | noisey += noisespeedy; 135 | noisez += noisespeedz; 136 | } 137 | 138 | void mapNoiseToLEDsUsingPalette(CRGBPalette16 palette, uint8_t hueReduce = 0) 139 | { 140 | static uint8_t ihue=0; 141 | 142 | for(int i = 0; i < MATRIX_WIDTH; i++) { 143 | for(int j = 0; j < MATRIX_HEIGHT; j++) { 144 | // We use the value at the (i,j) coordinate in the noise 145 | // array for our brightness, and the flipped value from (j,i) 146 | // for our pixel's index into the color palette. 147 | 148 | uint8_t index = noise[j][i]; 149 | uint8_t bri = noise[i][j]; 150 | 151 | // if this palette is a 'loop', add a slowly-changing base value 152 | if( colorLoop) { 153 | index += ihue; 154 | } 155 | 156 | // brighten up, as the color palette itself often contains the 157 | // light/dark dynamic range desired 158 | if( bri > 127 ) { 159 | bri = 255; 160 | } else { 161 | bri = dim8_raw( bri * 2); 162 | } 163 | 164 | if(hueReduce > 0) { 165 | if(index < hueReduce) index = 0; 166 | else index -= hueReduce; 167 | } 168 | 169 | CRGB color = ColorFromPalette( palette, index, bri); 170 | uint16_t n = XY(i, j); 171 | 172 | leds[n] = color; 173 | } 174 | } 175 | 176 | ihue+=1; 177 | } 178 | 179 | uint16_t drawNoise(CRGBPalette16 palette,uint8_t hueReduce = 0) { 180 | // generate noise data 181 | fillnoise8(); 182 | 183 | // convert the noise data to colors in the LED array 184 | // using the current palette 185 | mapNoiseToLEDsUsingPalette(palette, hueReduce); 186 | 187 | return 10; 188 | } 189 | //=============================================== 190 | uint16_t LavaLampRainbow() { 191 | noisespeedx = 1; 192 | noisespeedy = 0; 193 | noisespeedz = 0; 194 | noisescale = 10; 195 | colorLoop = 0; 196 | return drawNoise(RainbowColors_p); 197 | } 198 | //=============================================== 199 | uint16_t LavaLampRainbowStripe() { 200 | noisespeedx = 2; 201 | noisespeedy = 0; 202 | noisespeedz = 0; 203 | noisescale = 20; 204 | colorLoop = 0; 205 | return drawNoise(RainbowStripeColors_p); 206 | } 207 | //=============================================== 208 | uint16_t Party() { 209 | noisespeedx = 1; 210 | noisespeedy = 0; 211 | noisespeedz = 0; 212 | noisescale = 50; 213 | colorLoop = 0; 214 | return drawNoise(PartyColors_p); 215 | } 216 | //=============================================== 217 | uint16_t Forest() { 218 | noisespeedx = 9; 219 | noisespeedy = 0; 220 | noisespeedz = 0; 221 | noisescale = 120; 222 | colorLoop = 0; 223 | return drawNoise(ForestColors_p); 224 | } 225 | //=============================================== 226 | uint16_t Cloud() { 227 | noisespeedx = 9; 228 | noisespeedy = 0; 229 | noisespeedz = 0; 230 | noisescale = 30; 231 | colorLoop = 0; 232 | return drawNoise(CloudColors_p); 233 | } 234 | //=============================================== 235 | uint16_t Fire() { 236 | noisespeedx = 8; // 24; 237 | noisespeedy = 0; 238 | noisespeedz = 8; 239 | noisescale = 50; 240 | colorLoop = 0; 241 | return drawNoise(HeatColors_p, 60); 242 | } 243 | //=============================================== 244 | uint16_t FireNoise() { 245 | noisespeedx = 8; // 24; 246 | noisespeedy = 0; 247 | noisespeedz = 8; 248 | noisescale = 50; 249 | colorLoop = 0; 250 | return drawNoise(HeatColors_p, 60); 251 | } 252 | //=============================================== 253 | uint16_t Lava() { 254 | noisespeedx = 2; 255 | noisespeedy = 0; 256 | noisespeedz = 2; 257 | noisescale = 20; 258 | colorLoop = 0; 259 | return drawNoise(LavaColors_p); 260 | } 261 | //=============================================== 262 | uint16_t Ocean() { 263 | noisespeedx = 9; 264 | noisespeedy = 0; 265 | noisespeedz = 0; 266 | noisescale = 90; 267 | colorLoop = 0; 268 | return drawNoise(OceanColors_p); 269 | } 270 | //=============================================== 271 | uint16_t BlackAndWhite() { 272 | SetupBlackAndWhiteStripedPalette(); 273 | noisespeedx = 9; 274 | noisespeedy = 0; 275 | noisespeedz = 0; 276 | noisescale = 30; 277 | colorLoop = 0; 278 | return drawNoise(blackAndWhiteStripedPalette); 279 | } 280 | //=============================================== 281 | uint16_t BlackAndBlue() { 282 | SetupBlackAndBlueStripedPalette(); 283 | noisespeedx = 9; 284 | noisespeedy = 0; 285 | noisespeedz = 0; 286 | noisescale = 30; 287 | colorLoop = 0; 288 | return drawNoise(blackAndBlueStripedPalette); 289 | } 290 | //=============================================== 291 | uint16_t Temperature() { 292 | noisespeedx = 1; 293 | noisespeedy = 0; 294 | noisespeedz = 1; 295 | noisescale = 25; //20 296 | colorLoop = 0; 297 | return drawNoise(temperature_gp); 298 | } 299 | //=============================================== 300 | uint16_t Spectrum() { 301 | noisespeedx = 1; 302 | noisespeedy = 0; 303 | noisespeedz = 1; 304 | noisescale = 25; //20 305 | colorLoop = 0; 306 | return drawNoise(Stripped_Spectrum_gp); 307 | } 308 | //=============================================== 309 | uint16_t OceanBreeze() { 310 | noisespeedx = 1; 311 | noisespeedy = 0; 312 | noisespeedz = 1; 313 | noisescale = 25; //20 314 | colorLoop = 0; 315 | return drawNoise(es_ocean_breeze_026_gp); 316 | } 317 | //=============================================== 318 | uint16_t DeepSea() { 319 | noisespeedx = 1; 320 | noisespeedy = 1; 321 | noisespeedz = 0; 322 | noisescale = 30; //20 323 | colorLoop = 0; 324 | return drawNoise(Deep_Sea_gp); 325 | } 326 | //=============================================== 327 | uint16_t Aurora() { 328 | noisespeedx = 0; 329 | noisespeedy = 1; 330 | noisespeedz = 0; 331 | noisescale = 30; //20 332 | colorLoop = 0; 333 | return drawNoise(ofaurora_gp); 334 | } 335 | //=============================================== 336 | uint16_t Shikon22() { 337 | noisespeedx = 1; 338 | noisespeedy = 1; 339 | noisespeedz = 0; 340 | noisescale = 10; //20 341 | colorLoop = 0; 342 | return drawNoise(shikon_22_gp); 343 | } 344 | //=============================================== 345 | uint16_t Shikon23() { 346 | noisespeedx = 1; 347 | noisespeedy = 1; 348 | noisespeedz = 0; 349 | noisescale = 10; //20 350 | colorLoop = 0; 351 | return drawNoise(shikon_23_gp); 352 | } 353 | //=============================================== 354 | uint16_t ColorCube() { 355 | noisespeedx = 1; 356 | noisespeedy = 1; 357 | noisespeedz = 0; 358 | noisescale = 15; //20 359 | colorLoop = 0; 360 | return drawNoise(colorcube_gp); 361 | } 362 | //=============================================== 363 | uint16_t RampRGB() { 364 | noisespeedx = 0; 365 | noisespeedy = 0; 366 | noisespeedz = 1; 367 | noisescale = 6; //20 368 | colorLoop = 0; 369 | return drawNoise(ramp_gp); 370 | } 371 | //=============================================== 372 | uint16_t Curvature() { 373 | noisespeedx = 0; 374 | noisespeedy = 0; 375 | noisespeedz = 1; 376 | noisescale = 6; //20 377 | colorLoop = 0; 378 | return drawNoise(curvature_gp); 379 | } 380 | //=============================================== 381 | uint16_t Rstcurv() { 382 | noisespeedx = 2; 383 | noisespeedy = 2; 384 | noisespeedz = 1; 385 | noisescale = 50; //20 386 | colorLoop = 0; 387 | return drawNoise(rstcurv_gp); 388 | } 389 | //=============================================== 390 | uint16_t Calbayo15() { 391 | noisespeedx = 0; 392 | noisespeedy = 1; 393 | noisespeedz = 0; 394 | noisescale = 10; //20 395 | colorLoop = 0; 396 | return drawNoise(calbayo_15_gp); 397 | } 398 | //=============================================== 399 | uint16_t CoralReef() { 400 | noisespeedx = 1; 401 | noisespeedy = 0; 402 | noisespeedz = 1; 403 | noisescale = 25; //20 404 | colorLoop = 0; 405 | return drawNoise(Coral_reef_gp); 406 | } 407 | //=============================================== 408 | uint16_t Vintage1() { 409 | noisespeedx = 1; 410 | noisespeedy = 1; 411 | noisespeedz = 0; 412 | noisescale = 12; //20 413 | colorLoop = 0; 414 | return drawNoise(es_vintage_01_gp); 415 | } 416 | //=============================================== 417 | uint16_t Vintage49() { 418 | noisespeedx = 1; 419 | noisespeedy = 1; 420 | noisespeedz = 0; 421 | noisescale = 12; //20 422 | colorLoop = 0; 423 | return drawNoise(es_vintage_49_gp); 424 | } 425 | //=============================================== 426 | uint16_t Analogous1() { 427 | noisespeedx = 1; 428 | noisespeedy = 1; 429 | noisespeedz = 0; 430 | noisescale = 18; //20 431 | colorLoop = 0; 432 | return drawNoise(Analogous_1_gp); 433 | } -------------------------------------------------------------------------------- /Pulse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | uint16_t Pulse() { 20 | // palette = RainbowColors_p; 21 | 22 | static uint8_t hue = 0; 23 | static uint8_t centerX = 0; 24 | static uint8_t centerY = 0; 25 | static uint8_t step = 0; 26 | 27 | static const uint8_t maxSteps = 16; 28 | static const float fadeRate = 0.8; 29 | 30 | dimAll(235); 31 | 32 | if (step == 0) { 33 | centerX = random(32); 34 | centerY = random(32); 35 | hue = random(256); // 170; 36 | 37 | drawCircle(centerX, centerY, step, ColorFromPalette(palette, hue)); 38 | step++; 39 | } 40 | else { 41 | if (step < maxSteps) { 42 | // initial pulse 43 | drawCircle(centerX, centerY, step, ColorFromPalette(palette, hue, pow(fadeRate, step - 2) * 255)); 44 | 45 | // secondary pulse 46 | if (step > 3) { 47 | drawCircle(centerX, centerY, step - 3, ColorFromPalette(palette, hue, pow(fadeRate, step - 2) * 255)); 48 | } 49 | step++; 50 | } 51 | else { 52 | step = 0; 53 | } 54 | } 55 | 56 | return 30; 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LED Effect Lamp For PJRC Teensy / WS2812B Matrix 2 | ### PROJECT HAS BEEN MOVED TO: https://github.com/MakingThingsWithLEDs/FlameAndEffectLampProject 3 | 4 | | Fire Lamp | Lava / Plasma Lamp | Sound Reactive | Other Effects | 5 | | --------------------------------- | ----------------------------- | ------------------------- | --------------------- | 6 | | TorchBlue | BlackAndWhite | AudioAnalyzerColumns | BlackAndWhiteNoise| 7 | | TorchChemical | Cloud | AudioAnalyzerColumnsSolid | BPM| 8 | | TorchGreen | Forest | AudioAnalyzerPixels | CloudTwinkles| 9 | | TorchOrange | Lava | AudioBlackAndBlue | ColorWaves| 10 | | TorchPurple | Ocean | AudioBlackAndWhite | Confetti| 11 | | | Party | AudioCloud | Fire2012WithPalette| 12 | | TorchRed | Rainbow | AudioFallingSpectrogram | Fireflies| 13 | | TorchWhite | RainbowStripe | AudioFire1 | FireNoise| 14 | | | Spectrum | AudioFire2 | HueCycle| 15 | | | | Temperature | AudioFire3 | IncandescentTwinkles| 16 | | | RampRGB | AudioForest | Juggle| 17 | | | ColorCube | AudioLava | Pride| 18 | | | Curvature | AudioLavaMagenta | Pulse| 19 | | | Shikon1 | AudioLavaRainbow | Rainbow| 20 | | | Shikon2 | AudioOcean | RainbowTwinkles| 21 | | | Slope | AudioParty | RainbowWithGlitter| 22 | | | | AudioRainbowStripe | SolidColor| 23 | | | | | Sinelon| 24 | | | | | SnowTwinkles| 25 | | | | | Wave| 26 | 27 | ### Support 28 | **Project:** https://www.youtube.com/playlist?list=PLuTvWrqvrCQGxWSenKpJilgakO-iD05nO 29 | 30 | ![Custom Built Matrix ColorCube](https://github.com/MakingThingsWithLEDs/LEDEffectLampProject/assets/77110859/feb55dd8-526e-4138-854d-6e4be939efe4) 31 | https://youtube.com/shorts/MAVUOS6Amuc?feature=share 32 | -------------------------------------------------------------------------------- /VariableList.txt: -------------------------------------------------------------------------------- 1 | cycle_wait6 2 | flame_min6 3 | flame_max6 4 | random_spark_probability8 5 | spark_min8 6 | spark_max8 7 | spark_tfr8 8 | spark_cap8 9 | up_rad8 10 | side_rad8 11 | heat_cap8 12 | red_bg8 13 | green_bg8 14 | blue_bg8 15 | red_bias8 16 | green_bias8 17 | blue_bias8 18 | red_energy8 19 | green_energy8 20 | blue_energy8 21 | upside_down8 22 | currentEnergy8 23 | nextEnergy8 24 | energyMode8 25 | torch_passive8 26 | torch_nop8 27 | torch_spark8 28 | reduce8 29 | increase8 30 | random8 31 | resetEnergy8 32 | energymap8 33 | injectrandom8 34 | calcNextColors8 -------------------------------------------------------------------------------- /Wave.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Torch: https://github.com/evilgeniuslabs/torch 3 | * Copyright (C) 2015 Jason Coon 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | uint16_t Wave() { 20 | static byte rotation = 3; 21 | 22 | static const uint8_t scaleWidth = 256 / MATRIX_WIDTH; 23 | static const uint8_t scaleHeight = 256 / MATRIX_HEIGHT; 24 | 25 | static const uint8_t maxX = MATRIX_WIDTH - 1; 26 | static const uint8_t maxY = MATRIX_HEIGHT - 1; 27 | 28 | static uint8_t waveCount = 1; 29 | static uint8_t hue = 1; 30 | static uint8_t theta = 0; 31 | 32 | // EVERY_N_SECONDS(10) { 33 | // rotation = random(0, 1); 34 | // waveCount = random(1, 3); 35 | // } 36 | 37 | int n = 0; 38 | 39 | switch (rotation) { 40 | case 0: 41 | for (int x = 0; x < MATRIX_WIDTH; x++) { 42 | n = quadwave8(x * 2 + theta) / scaleHeight; 43 | leds[XY(x, n)] = ColorFromPalette(palette, x + hue); 44 | if (waveCount == 2) 45 | leds[XY(x, maxY - n)] = ColorFromPalette(palette, x + hue); 46 | } 47 | break; 48 | 49 | case 1: 50 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 51 | n = quadwave8(y * 2 + theta) / scaleWidth; 52 | leds[XY(n, y)] = ColorFromPalette(palette, y + hue); 53 | if (waveCount == 2) 54 | leds[XY(maxX - n, y)] = ColorFromPalette(palette, y + hue); 55 | } 56 | break; 57 | 58 | case 2: 59 | for (int x = 0; x < MATRIX_WIDTH; x++) { 60 | n = quadwave8(x * 2 - theta) / scaleHeight; 61 | leds[XY(x, n)] = ColorFromPalette(palette, x + hue); 62 | if (waveCount == 2) 63 | leds[XY(x, maxY - n)] = ColorFromPalette(palette, x + hue); 64 | } 65 | break; 66 | 67 | case 3: 68 | for (int y = 0; y < MATRIX_HEIGHT; y++) { 69 | n = quadwave8(y * 2 - theta) / scaleWidth; 70 | leds[XY(n, y)] = ColorFromPalette(palette, y + hue); 71 | if (waveCount == 2) 72 | leds[XY(maxX - n, y)] = ColorFromPalette(palette, y + hue); 73 | } 74 | break; 75 | } 76 | 77 | dimAll(254); 78 | 79 | EVERY_N_MILLISECONDS(10) { 80 | theta++; 81 | hue++; 82 | } 83 | 84 | return 0; 85 | } 86 | --------------------------------------------------------------------------------