/*
Arduino | coding-help
Error message "in expansion of macro" within FastLED library
IronEnder17 July 11, 2025 — 8:12 PM
Here is a link to the code
*/
#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
//bussard setup
#define DATA_PIN1 3
#define NUM_LEDS1 8
CRGBArray<NUM_LEDS1> leds1;
#define TWINKLE_SPEED 5
#define TWINKLE_DENSITY 8
#define SECONDS_PER_PALETTE 30
CRGB gBackgroundColor = CRGB::Black;
#define AUTO_SELECT_BACKGROUND_COLOR 0
#define COOL_LIKE_INCANDESCENT 1
CRGBPalette16 gCurrentPalette;
CRGBPalette16 gTargetPalette;
//warp setup
#define DATA_PIN2 5
#define NUM_LEDS2 30
#define MAX_POWER_MILLIAMPS 500
#define FASTLED_ALLOW_INTERRUPTS 0
FASTLED_USING_NAMESPACE
//deflector setup
//////////////////////////////////////////////////////////////////////////
CRGB leds2[NUM_LEDS2];
void setup() {
//bussard
delay(3000); //safety startup delay
FastLED.addLeds<LED_TYPE, DATA_PIN1, COLOR_ORDER>(leds1, NUM_LEDS1)
.setCorrection(TypicalLEDStrip);
chooseNextColorPalette(gTargetPalette);
//warp
FastLED.addLeds<LED_TYPE, DATA_PIN2, COLOR_ORDER>(leds2, NUM_LEDS2)
.setCorrection(TypicalLEDStrip);
FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_POWER_MILLIAMPS);
}
void loop()
{
EVERY_N_SECONDS(SECONDS_PER_PALETTE) {
chooseNextColorPalette(gTargetPalette);
}
EVERY_N_MILLISECONDS(10) {
nblendPaletteTowardPalette(gCurrentPalette, gTargetPalette, 12);
}
drawTwinkles(leds1);
FastLED.show();
}
void drawTwinkles(CRGBSet& L) {
uint16_t PRNG16 = 11337;
uint32_t clock32 = millis();
CRGB bg;
if ((AUTO_SELECT_BACKGROUND_COLOR == 1) && (gCurrentPalette[0] == gCurrentPalette[1])) {
bg = gCurrentPalette[0];
uint8_t bglight = bg.getAverageLight();
if (bglight > 64) {
bg.nscale8_video(16); // very bright, so scale to 1/16th
} else if (bglight > 16) {
bg.nscale8_video(64); // not that bright, so scale to 1/4th
} else {
bg.nscale8_video(86); // dim, scale to 1/3rd.
}
} else {
bg = gBackgroundColor; // just use the explicitly defined background color
}
uint8_t backgroundBrightness = bg.getAverageLight();
for (CRGB& pixel : L) {
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
uint16_t myclockoffset16 = PRNG16; // use that number as clock offset
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
// use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF) >> 4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
// We now have the adjusted 'clock' for this pixel, now we call
// the function that computes what color the pixel should be based
// on the "brightness = f( time )" idea.
CRGB c = computeOneTwinkle(myclock30, myunique8);
uint8_t cbright = c.getAverageLight();
int16_t deltabright = cbright - backgroundBrightness;
if (deltabright >= 32 || (!bg)) {
// If the new pixel is significantly brighter than the background color,
// use the new color.
pixel = c;
} else if (deltabright > 0) {
// If the new pixel is just slightly brighter than the background color,
// mix a blend of the new color and the background color
pixel = blend(bg, c, deltabright * 8);
} else {
// if the new pixel is not at all brighter than the background color,
// just use the background color.
pixel = bg;
}
}
}
CRGB computeOneTwinkle(uint32_t ms, uint8_t salt) {
uint16_t ticks = ms >> (8 - TWINKLE_SPEED);
uint8_t fastcycle8 = ticks;
uint16_t slowcycle16 = (ticks >> 8) + salt;
slowcycle16 += sin8(slowcycle16);
slowcycle16 = (slowcycle16 * 2053) + 1384;
uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
uint8_t bright = 0;
if (((slowcycle8 & 0x0E) / 2) < TWINKLE_DENSITY) {
bright = attackDecayWave8(fastcycle8);
}
uint8_t hue = slowcycle8 - salt;
CRGB c;
if (bright > 0) {
c = ColorFromPalette(gCurrentPalette, hue, bright, NOBLEND);
if (COOL_LIKE_INCANDESCENT == 1) {
coolLikeIncandescent(c, fastcycle8);
}
} else {
c = CRGB::Black;
}
return c;
}
uint8_t attackDecayWave8(uint8_t i) {
if (i < 86) {
return i * 3;
} else {
i -= 86;
return 255 - (i + (i / 2));
}
}
void coolLikeIncandescent(CRGB& c, uint8_t phase) {
if (phase < 128) return;
uint8_t cooling = (phase - 128) >> 4;
c.g = qsub8(c.g, cooling);
c.b = qsub8(c.b, cooling * 2);
}
// A mostly red palette with green accents and white trim.
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM = { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
CRGB::Green, CRGB::Green, CRGB::Green, CRGB::Green
};
// A mostly (dark) green palette with red berries.
#define Holly_Green 0x00580c
#define Holly_Red 0xB00402
const TProgmemRGBPalette16 Holly_p FL_PROGMEM = { Holly_Green, Holly_Green, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Red
};
// A red and white striped palette
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM = { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray,
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray
};
// A mostly blue palette with white accents.
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM = { CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Gray, CRGB::Gray, CRGB::Gray
};
// A pure "fairy light" palette with some brightness variations
#define HALFFAIRY ((CRGB::FairyLight & 0xFEFEFE) / 2)
#define QUARTERFAIRY ((CRGB::FairyLight & 0xFCFCFC) / 4)
const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM = { CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight,
HALFFAIRY, HALFFAIRY, CRGB::FairyLight, CRGB::FairyLight,
QUARTERFAIRY, QUARTERFAIRY, CRGB::FairyLight, CRGB::FairyLight,
CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight
};
// A palette of soft snowflakes with the occasional bright one
const TProgmemRGBPalette16 Snow_p FL_PROGMEM = { 0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0xE0F0FF
};
// A palette reminiscent of large 'old-school' C9-size tree lights
// in the five classic colors: red, orange, green, blue, and white.
#define C9_Red 0xB80400
#define C9_Orange 0x902C02
#define C9_Green 0x046002
#define C9_Blue 0x070758
#define C9_White 0x606820
const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM = { C9_Red, C9_Orange, C9_Red, C9_Orange,
C9_Orange, C9_Red, C9_Orange, C9_Red,
C9_Green, C9_Green, C9_Green, C9_Green,
C9_Blue, C9_Blue, C9_Blue,
C9_White
};
// A cold, icy pale blue palette
#define Ice_Blue1 0x0C1040
#define Ice_Blue2 0x182080
#define Ice_Blue3 0x5080C0
const TProgmemRGBPalette16 Ice_p FL_PROGMEM = {
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue2, Ice_Blue2, Ice_Blue2, Ice_Blue3
};
// Add or remove palette names from this list to control which color
// palettes are used, and in what order.
const TProgmemRGBPalette16* ActivePaletteList[] = {
&FairyLight_p,
};
// Advance to the next color palette in the list (above).
void chooseNextColorPalette(CRGBPalette16& pal) {
const uint8_t numberOfPalettes = sizeof(ActivePaletteList) / sizeof(ActivePaletteList[0]);
static uint8_t whichPalette = -1;
whichPalette = addmod8(whichPalette, 1, numberOfPalettes);
pal = *(ActivePaletteList[whichPalette]);
}
/*
//warp
EVERY_N_MILLISECONDS(20) {
pacifica_loop();
FastLED.show();
}
*/
CRGBPalette16 pacifica_palette_1 = { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50
};
CRGBPalette16 pacifica_palette_2 = { 0x000007, 0x000009, 0x00000B, 0x00000D, 0x000010, 0x000012, 0x000014, 0x000017,
0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F
};
CRGBPalette16 pacifica_palette_3 = { 0x010018, 0x030025, 0x020014, 0x03001A, 0x100020, 0x050027, 0x010020, 0x010030,
0x090039, 0x030040, 0x050050, 0x000060, 0x000070, 0x030380, 0x101010, 0x100510
};
void pacifica_loop() {
// Increment the four "color index start" counters, one for each wave layer.
// Each is incremented at a different speed, and the speeds vary over time.
static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
static uint32_t sLastms = 0;
uint32_t ms = GET_MILLIS();
uint32_t deltams = ms - sLastms;
sLastms = ms;
uint16_t speedfactor1 = beatsin16(3, 179, 269);
uint16_t speedfactor2 = beatsin16(4, 179, 269);
uint32_t deltams1 = (deltams * speedfactor1) / 256;
uint32_t deltams2 = (deltams * speedfactor2) / 256;
uint32_t deltams21 = (deltams1 + deltams2) / 2;
sCIStart1 += (deltams1 * beatsin88(1011, 10, 13));
sCIStart2 -= (deltams21 * beatsin88(777, 8, 11));
sCIStart3 -= (deltams1 * beatsin88(501, 5, 7));
sCIStart4 -= (deltams2 * beatsin88(257, 4, 6));
// Clear out the LED array to a dim background blue-green
fill_solid(leds2, NUM_LEDS2, CRGB(2, 6, 10));
// Render each of four layers, with different scales and speeds, that vary over time
pacifica_one_layer(pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0 - beat16(301));
pacifica_one_layer(pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401));
pacifica_one_layer(pacifica_palette_3, sCIStart3, 6 * 256, beatsin8(9, 10, 38), 0 - beat16(503));
pacifica_one_layer(pacifica_palette_3, sCIStart4, 5 * 256, beatsin8(8, 10, 28), beat16(601));
// Add brighter 'whitecaps' where the waves lines up more
pacifica_add_whitecaps();
// Deepen the blues and greens a bit
pacifica_deepen_colors();
}
// Add one layer of waves into the led array
void pacifica_one_layer(CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) {
uint16_t ci = cistart;
uint16_t waveangle = ioff;
uint16_t wavescale_half = (wavescale / 2) + 20;
for (uint16_t i = 0; i < NUM_LEDS2; i++) {
waveangle += 250;
uint16_t s16 = sin16(waveangle) + 32768;
uint16_t cs = scale16(s16, wavescale_half) + wavescale_half;
ci += cs;
uint16_t sindex16 = sin16(ci) + 32768;
uint8_t sindex8 = scale16(sindex16, 240);
CRGB c = ColorFromPalette(p, sindex8, bri, LINEARBLEND);
leds2[i] += c;
}
}
// Add extra 'white' to areas where the four layers of light have lined up brightly
void pacifica_add_whitecaps() {
uint8_t basethreshold = beatsin8(9, 55, 65);
uint8_t wave = beat8(7);
for (uint16_t i = 0; i < NUM_LEDS2; i++) {
uint8_t threshold = scale8(sin8(wave), 20) + basethreshold;
wave += 7;
uint8_t l = leds2[i].getAverageLight();
if (l > threshold) {
uint8_t overage = l - threshold;
uint8_t overage2 = qadd8(overage, overage);
leds2[i] += CRGB(overage, overage2, qadd8(overage2, overage2));
}
}
}
// Deepen the blues and greens
void pacifica_deepen_colors() {
for (uint16_t i = 0; i < NUM_LEDS2; i++) {
leds2[i].blue = scale8(leds2[i].blue, 200);
leds2[i].green = scale8(leds2[i].green, 100);
leds2[i] |= CRGB(5, 0, 15);
}
}