FastLED 3.9.15
Loading...
Searching...
No Matches
NoisePlusPalette.h
Go to the documentation of this file.
1
10
11#include <FastLED.h> // Main FastLED library for controlling LEDs
12
13#if !SKETCH_HAS_LOTS_OF_MEMORY
14// Don't compile this for AVR microcontrollers (like Arduino Uno) because they typically
15// don't have enough memory to handle this complex animation.
16// Instead, we provide empty setup/loop functions so the sketch will compile but do nothing.
17void setup() {}
18void loop() {}
19#else // For all other platforms with more memory (ESP32, Teensy, etc.)
20
21// LED hardware configuration
22#define LED_PIN 3 // Data pin connected to the LED strip
23#define BRIGHTNESS 96 // Default brightness level (0-255)
24#define LED_TYPE WS2811 // Type of LED strip being used
25#define COLOR_ORDER GRB // Color order of the LEDs (varies by strip type)
26
27// Matrix dimensions - defines the size of our virtual LED grid
28const uint8_t kMatrixWidth = 16; // Number of columns in the matrix
29const uint8_t kMatrixHeight = 16; // Number of rows in the matrix
30
31// LED strip layout configuration
32const bool kMatrixSerpentineLayout = true; // If true, every other row runs backwards
33 // This is common in matrix setups to allow
34 // for easier wiring
35
36
37// HOW THIS EXAMPLE WORKS:
38//
39// This example combines two features of FastLED to produce a remarkable range of
40// effects from a relatively small amount of code. This example combines FastLED's
41// color palette lookup functions with FastLED's Perlin noise generator, and
42// the combination is extremely powerful.
43//
44// You might want to look at the "ColorPalette" and "Noise" examples separately
45// if this example code seems daunting.
46//
47//
48// The basic setup here is that for each frame, we generate a new array of
49// 'noise' data, and then map it onto the LED matrix through a color palette.
50//
51// Periodically, the color palette is changed, and new noise-generation parameters
52// are chosen at the same time. In this example, specific noise-generation
53// values have been selected to match the given color palettes; some are faster,
54// or slower, or larger, or smaller than others, but there's no reason these
55// parameters can't be freely mixed-and-matched.
56//
57// In addition, this example includes some fast automatic 'data smoothing' at
58// lower noise speeds to help produce smoother animations in those cases.
59//
60// The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
61// used, as well as some 'hand-defined' ones, and some procedurally generated
62// palettes.
63
64
65// Calculate the total number of LEDs in our matrix
66#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
67
68// Find the larger dimension (width or height) for our noise array size
69#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
70
71// Array to hold all LED color values - one CRGB struct per LED
73
74// The 16-bit version of our coordinates for the noise function
75// Using 16 bits gives us more resolution and smoother animations
76static uint16_t x; // x-coordinate in the noise space
77static uint16_t y; // y-coordinate in the noise space
78static uint16_t z; // z-coordinate (time dimension) in the noise space
79
80// ANIMATION PARAMETERS:
81
82// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll
83// use the z-axis for "time". speed determines how fast time moves forward. Try
84// 1 for a very slow moving effect, or 60 for something that ends up looking like
85// water.
86uint16_t speed = 20; // Speed is set dynamically once we've started up
87 // Higher values = faster animation
88
89// Scale determines how far apart the pixels in our noise matrix are. Try
90// changing these values around to see how it affects the motion of the display. The
91// higher the value of scale, the more "zoomed out" the noise will be. A value
92// of 1 will be so zoomed in, you'll mostly see solid colors.
93uint16_t scale = 30; // Scale is set dynamically once we've started up
94 // Higher values = more "zoomed out" pattern
95
96// This is the array that we keep our computed noise values in
97// Each position stores an 8-bit (0-255) noise value
99
100// The current color palette we're using to map noise values to colors
101CRGBPalette16 currentPalette( PartyColors_p ); // Start with party colors
102
103// If colorLoop is set to 1, we'll cycle through the colors in the palette
104// This creates an additional animation effect on top of the noise movement
105uint8_t colorLoop = 1; // 0 = no color cycling, 1 = cycle colors
106
107
108// Forward declare our functions so that we have maximum compatibility
109// with other build tools outside of ArduinoIDE. The *.ino files are
110// special in that Arduino will generate function prototypes for you.
111// For non-Arduino environments, we need these declarations.
112void SetupRandomPalette(); // Creates a random color palette
113void SetupPurpleAndGreenPalette(); // Creates a purple and green striped palette
114void SetupBlackAndWhiteStripedPalette(); // Creates a black and white striped palette
115void ChangePaletteAndSettingsPeriodically(); // Changes palettes and settings over time
116void mapNoiseToLEDsUsingPalette(); // Maps noise data to LED colors using the palette
117uint16_t XY( uint8_t x, uint8_t y); // Converts x,y coordinates to LED array index
118
119void setup() {
120 delay(3000); // 3 second delay for recovery and to give time for the serial monitor to open
121
122 // Initialize the LED strip:
123 // - LED_TYPE specifies the chipset (WS2811, WS2812B, etc.)
124 // - LED_PIN is the data pin number
125 // - COLOR_ORDER specifies the RGB color ordering for your strip
127 // NOTE - This does NOT have a ScreenMap (because it's a legacy sketch)
128 // so it won't look that good on the web-compiler. But adding it is ONE LINE!
129
130 // Set the overall brightness level (0-255)
131 FastLED.setBrightness(BRIGHTNESS);
132
133 // Initialize our noise coordinates to random values
134 // This ensures the pattern starts from a different position each time
135 x = random16(); // Random x starting position
136 y = random16(); // Random y starting position
137 z = random16(); // Random time starting position
138}
139
140
141
142// Fill the x/y array of 8-bit noise values using the inoise8 function.
143void fillnoise8() {
144 // If we're running at a low "speed", some 8-bit artifacts become visible
145 // from frame-to-frame. In order to reduce this, we can do some fast data-smoothing.
146 // The amount of data smoothing we're doing depends on "speed".
147 uint8_t dataSmoothing = 0;
148 if( speed < 50) {
149 // At lower speeds, apply more smoothing
150 // This formula creates more smoothing at lower speeds:
151 // speed=10 → smoothing=160, speed=30 → smoothing=80
152 dataSmoothing = 200 - (speed * 4);
153 }
154
155 // Loop through each pixel in our noise array
156 for(int i = 0; i < MAX_DIMENSION; i++) {
157 // Calculate the offset for this pixel in the x dimension
158 int ioffset = scale * i;
159
160 for(int j = 0; j < MAX_DIMENSION; j++) {
161 // Calculate the offset for this pixel in the y dimension
162 int joffset = scale * j;
163
164 // Generate the noise value for this pixel using 3D Perlin noise
165 // The noise function takes x, y, and z (time) coordinates
166 uint8_t data = inoise8(x + ioffset, y + joffset, z);
167
168 // The range of the inoise8 function is roughly 16-238.
169 // These two operations expand those values out to roughly 0..255
170 // You can comment them out if you want the raw noise data.
171 data = qsub8(data, 16); // Subtract 16 (with underflow protection)
172 data = qadd8(data, scale8(data, 39)); // Add a scaled version of the data to itself
173
174 // Apply data smoothing if enabled
175 if( dataSmoothing ) {
176 uint8_t olddata = noise[i][j]; // Get the previous frame's value
177
178 // Blend between old and new data based on smoothing amount
179 // Higher dataSmoothing = more of the old value is kept
180 uint8_t newdata = scale8(olddata, dataSmoothing) +
181 scale8(data, 256 - dataSmoothing);
182 data = newdata;
183 }
184
185 // Store the final noise value in our array
186 noise[i][j] = data;
187 }
188 }
189
190 // Increment z to move through the noise space over time
191 z += speed;
192
193 // Apply slow drift to X and Y, just for visual variation
194 // This creates a gentle shifting of the entire pattern
195 x += speed / 8; // X drifts at 1/8 the speed of z
196 y -= speed / 16; // Y drifts at 1/16 the speed of z in the opposite direction
197}
198
199
200
201// Map the noise data to LED colors using the current color palette
202void mapNoiseToLEDsUsingPalette()
203{
204 // Static variable that slowly increases to cycle through colors when colorLoop is enabled
205 static uint8_t ihue=0;
206
207 // Loop through each pixel in our LED matrix
208 for(int i = 0; i < kMatrixWidth; i++) {
209 for(int j = 0; j < kMatrixHeight; j++) {
210 // We use the value at the (i,j) coordinate in the noise
211 // array for our brightness, and the flipped value from (j,i)
212 // for our pixel's index into the color palette.
213 // This creates interesting patterns with two different noise mappings.
214
215 uint8_t index = noise[j][i]; // Color index from the flipped coordinate
216 uint8_t bri = noise[i][j]; // Brightness from the normal coordinate
217
218 // If color cycling is enabled, add a slowly-changing base value to the index
219 // This makes the colors shift/rotate through the palette over time
220 if( colorLoop) {
221 index += ihue; // Add the slowly increasing hue offset
222 }
223
224 // Brighten up the colors, as the color palette itself often contains the
225 // light/dark dynamic range desired
226 if( bri > 127 ) {
227 // If brightness is in the upper half, make it full brightness
228 bri = 255;
229 } else {
230 // Otherwise, scale it to the full range (0-127 becomes 0-254)
231 bri = dim8_raw( bri * 2);
232 }
233
234 // Get the final color by looking up the palette color at our index
235 // and applying the brightness value
236 CRGB color = ColorFromPalette( currentPalette, index, bri);
237
238 // Set the LED color in our array, using the XY mapping function
239 // to convert from x,y coordinates to the 1D array index
240 leds[XY(i,j)] = color;
241 }
242 }
243
244 // Increment the hue value for the next frame (for color cycling)
245 ihue+=1;
246}
247
248void loop() {
249 // The main program loop that runs continuously
250
251 // Periodically choose a new palette, speed, and scale
252 // This creates variety in the animation over time
253 ChangePaletteAndSettingsPeriodically();
254
255 // Generate new noise data for this frame
256 fillnoise8();
257
258 // Convert the noise data to colors in the LED array
259 // using the current palette
260 mapNoiseToLEDsUsingPalette();
261
262 // Send the color data to the actual LEDs
263 FastLED.show();
264
265 // No delay is needed here as the calculations already take some time
266 // Adding a delay would slow down the animation
267 // delay(10);
268}
269
270
271
272// PALETTE MANAGEMENT:
273//
274// There are several different palettes of colors demonstrated here.
275//
276// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
277// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
278//
279// Additionally, you can manually define your own color palettes, or you can write
280// code that creates color palettes on the fly.
281
282// This controls how long each palette is displayed before changing
283// 1 = 5 sec per palette
284// 2 = 10 sec per palette
285// etc.
286#define HOLD_PALETTES_X_TIMES_AS_LONG 1 // Multiplier for palette duration
287
288// Periodically change the palette, speed, and scale settings
289void ChangePaletteAndSettingsPeriodically()
290{
291 // Calculate which "second hand" we're on (0-59) based on elapsed time
292 // We divide by HOLD_PALETTES_X_TIMES_AS_LONG to slow down the changes
293 uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
294 static uint8_t lastSecond = 99; // Track the last second to detect changes
295
296 // Only update when the second hand changes
297 if( lastSecond != secondHand) {
298 lastSecond = secondHand;
299
300 // Every 5 seconds, change to a different palette and settings
301 // Each palette has specific speed and scale settings that work well with it
302
303 if( secondHand == 0) { currentPalette = RainbowColors_p; speed = 20; scale = 30; colorLoop = 1; }
304 if( secondHand == 5) { SetupPurpleAndGreenPalette(); speed = 10; scale = 50; colorLoop = 1; }
305 if( secondHand == 10) { SetupBlackAndWhiteStripedPalette(); speed = 20; scale = 30; colorLoop = 1; }
306 if( secondHand == 15) { currentPalette = ForestColors_p; speed = 8; scale =120; colorLoop = 0; }
307 if( secondHand == 20) { currentPalette = CloudColors_p; speed = 4; scale = 30; colorLoop = 0; }
308 if( secondHand == 25) { currentPalette = LavaColors_p; speed = 8; scale = 50; colorLoop = 0; }
309 if( secondHand == 30) { currentPalette = OceanColors_p; speed = 20; scale = 90; colorLoop = 0; }
310 if( secondHand == 35) { currentPalette = PartyColors_p; speed = 20; scale = 30; colorLoop = 1; }
311 if( secondHand == 40) { SetupRandomPalette(); speed = 20; scale = 20; colorLoop = 1; }
312 if( secondHand == 45) { SetupRandomPalette(); speed = 50; scale = 50; colorLoop = 1; }
313 if( secondHand == 50) { SetupRandomPalette(); speed = 90; scale = 90; colorLoop = 1; }
314 if( secondHand == 55) { currentPalette = RainbowStripeColors_p; speed = 30; scale = 20; colorLoop = 1; }
315 }
316}
317
318
319
320// This function generates a random palette that's a gradient
321// between four different colors. The first is a dim hue, the second is
322// a bright hue, the third is a bright pastel, and the last is
323// another bright hue. This gives some visual bright/dark variation
324// which is more interesting than just a gradient of different hues.
325void SetupRandomPalette()
326{
327 // Create a new palette with 4 random colors that blend together
328 currentPalette = CRGBPalette16(
329 CHSV( random8(), 255, 32), // Random dim hue (low value)
330 CHSV( random8(), 255, 255), // Random bright hue (full saturation & value)
331 CHSV( random8(), 128, 255), // Random pastel (medium saturation, full value)
332 CHSV( random8(), 255, 255)); // Another random bright hue
333
334 // The CRGBPalette16 constructor automatically creates a 16-color gradient
335 // between these four colors, evenly distributed
336}
337
338
339// This function sets up a palette of black and white stripes,
340// using code. Since the palette is effectively an array of
341// sixteen CRGB colors, the various fill_* functions can be used
342// to set them up.
344{
345 // 'black out' all 16 palette entries...
347
348 // and set every fourth one to white to create stripes
349 // Positions 0, 4, 8, and 12 in the 16-color palette
354
355 // The palette interpolation will create smooth transitions between these colors
356}
357
358// This function sets up a palette of purple and green stripes.
360{
361 // Define our colors using HSV color space for consistency
362 CRGB purple = CHSV( HUE_PURPLE, 255, 255); // Bright purple
363 CRGB green = CHSV( HUE_GREEN, 255, 255); // Bright green
364 CRGB black = CRGB::Black; // Black
365
366 // Create a 16-color palette with a specific pattern:
367 // green-green-black-black-purple-purple-black-black, repeated twice
368 // This creates alternating green and purple stripes with black in between
369 currentPalette = CRGBPalette16(
370 green, green, black, black, // First 4 colors
371 purple, purple, black, black, // Next 4 colors
372 green, green, black, black, // Repeat the pattern
373 purple, purple, black, black ); // Last 4 colors
374}
375
376
377//
378// Mark's xy coordinate mapping code. See the XYMatrix for more information on it.
379//
380// This function converts x,y coordinates to a single array index
381// It handles both regular and serpentine matrix layouts
382uint16_t XY( uint8_t x, uint8_t y)
383{
384 uint16_t i;
385
386 // For a regular/sequential layout, it's just y * width + x
387 if( kMatrixSerpentineLayout == false) {
388 i = (y * kMatrixWidth) + x;
389 }
390
391 // For a serpentine layout (zigzag), odd rows run backwards
392 if( kMatrixSerpentineLayout == true) {
393 if( y & 0x01) { // Check if y is odd (bitwise AND with 1)
394 // Odd rows run backwards
395 uint8_t reverseX = (kMatrixWidth - 1) - x;
396 i = (y * kMatrixWidth) + reverseX;
397 } else {
398 // Even rows run forwards
399 i = (y * kMatrixWidth) + x;
400 }
401 }
402
403 return i;
404}
405
406
407#endif // End of the non-AVR code section
CRGB leds[NUM_LEDS]
Definition Apa102.ino:11
#define NUM_LEDS
Definition Apa102.ino:6
#define BRIGHTNESS
Definition Blur.ino:8
#define COLOR_ORDER
#define LED_TYPE
#define LED_PIN
CRGBPalette16 currentPalette
void SetupPurpleAndGreenPalette()
void SetupBlackAndWhiteStripedPalette()
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
Definition FastLED.cpp:62
central include file for FastLED, defines the CFastLED class/object
uint8_t noise[NUM_LAYERS][WIDTH][HEIGHT]
Definition Fire2023.ino:88
uint32_t z[NUM_LAYERS]
Definition Fire2023.ino:84
uint8_t XY(uint8_t x, uint8_t y)
Definition Fire2023.ino:210
uint32_t x[NUM_LAYERS]
Definition Fire2023.ino:82
uint32_t y[NUM_LAYERS]
Definition Fire2023.ino:83
#define kMatrixSerpentineLayout
void setup()
void loop()
#define kMatrixHeight
#define kMatrixWidth
CRGB ColorFromPalette(const CRGBPalette16 &pal, uint8_t index, uint8_t brightness, TBlendType blendType)
void fill_solid(struct CRGB *targetArray, int numToFill, const struct CRGB &color)
Fill a range of LEDs with a solid color.
Definition fill.cpp:9
uint16_t speed
Definition funky.cpp:82
void fillnoise8()
Definition funky.cpp:1000
#define MAX_DIMENSION
Definition funky.cpp:87
uint16_t scale
Definition funky.cpp:83
LIB8STATIC uint8_t dim8_raw(uint8_t x)
Adjust a scaling value for dimming.
Definition scale8.h:709
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8(uint8_t i, uint8_t j)
Add one byte to another, saturating at 0xFF.
Definition math8.h:31
LIB8STATIC_ALWAYS_INLINE uint8_t qsub8(uint8_t i, uint8_t j)
Subtract one byte from another, saturating at 0x00.
Definition math8.h:103
uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z)
8-Bit, fixed point implementation of Perlin's noise.
Definition noise.cpp:590
@ HUE_PURPLE
Purple (270°)
Definition chsv.h:104
@ HUE_GREEN
Green (135°)
Definition chsv.h:101
const TProgmemRGBPalette16 RainbowStripeColors_p
HSV Rainbow colors with alternatating stripes of black.
const TProgmemRGBPalette16 OceanColors_p
Ocean colors, blues and whites.
const TProgmemRGBPalette16 CloudColors_p
Cloudy color palette.
const TProgmemRGBPalette16 ForestColors_p
Forest colors, greens.
const TProgmemRGBPalette16 LavaColors_p
Lava color palette.
const TProgmemRGBPalette16 PartyColors_p
HSV color ramp: blue, purple, pink, red, orange, yellow (and back).
const TProgmemRGBPalette16 RainbowColors_p
HSV Rainbow.
LIB8STATIC uint16_t random16()
Generate a 16-bit random number.
Definition random8.h:56
LIB8STATIC uint8_t random8()
Generate an 8-bit random number.
Definition random8.h:46
LIB8STATIC_ALWAYS_INLINE uint8_t scale8(uint8_t i, fract8 scale)
Scale one byte by a second one, which is treated as the numerator of a fraction whose denominator is ...
Definition scale8.h:40
Representation of an HSV pixel (hue, saturation, value (aka brightness)).
Definition chsv.h:16
@ White
<div style='background:#FFFFFF;width:4em;height:4em;'></div>
Definition crgb.h:640
@ Black
<div style='background:#000000;width:4em;height:4em;'></div>
Definition crgb.h:504
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:55