Skip to content

Instantly share code, notes, and snippets.

@kriegsman
Last active January 8, 2025 18:23
Show Gist options
  • Select an option

  • Save kriegsman/36a1e277f5b4084258d9af1eae29bac4 to your computer and use it in GitHub Desktop.

Select an option

Save kriegsman/36a1e277f5b4084258d9af1eae29bac4 to your computer and use it in GitHub Desktop.

Revisions

  1. kriegsman revised this gist Jan 14, 2020. 1 changed file with 74 additions and 35 deletions.
    109 changes: 74 additions & 35 deletions Pacifica.ino
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,18 @@
    //
    // "Pacifica"
    // Gentle, blue-green ocean waves.
    // December 2019, Mark Kriegsman and Mary Corey March.
    // December 2019, Mark Kriegsman and Mary Corey March.
    // For Dan.
    //

    #define FASTLED_ALLOW_INTERRUPTS 0
    #include <FastLED.h>
    FASTLED_USING_NAMESPACE

    #define DATA_PIN 3
    #define DATA_PIN 13
    #define NUM_LEDS 60
    #define MAX_POWER_MILLIAMPS 500
    #define LED_TYPE WS2811
    #define LED_TYPE WS2812B
    #define COLOR_ORDER GRB

    //////////////////////////////////////////////////////////////////////////
    @@ -22,22 +22,43 @@ CRGB leds[NUM_LEDS];
    void setup() {
    delay( 3000); // 3 second delay for boot recovery, and a moment of silence
    FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
    .setCorrection( CRGB( 255, 145, 145) ); //color balance for deep blues
    .setCorrection( TypicalLEDStrip );
    FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);
    }

    void loop()
    {
    pacifica_loop();

    FastLED.show();
    delay(10);
    EVERY_N_MILLISECONDS( 20) {
    pacifica_loop();
    FastLED.show();
    }
    }

    //////////////////////////////////////////////////////////////////////////

    // Three custom blue-green color palettes inspired by the colors found in
    //
    // The code for this animation is more complicated than other examples, and
    // while it is "ready to run", and documented in general, it is probably not
    // the best starting point for learning. Nevertheless, it does illustrate some
    // useful techniques.
    //
    //////////////////////////////////////////////////////////////////////////
    //
    // In this animation, there are four "layers" of waves of light.
    //
    // Each layer moves independently, and each is scaled separately.
    //
    // All four wave layers are added together on top of each other, and then
    // another filter is applied that adds "whitecaps" of brightness where the
    // waves line up with each other more. Finally, another pass is taken
    // over the led array to 'deepen' (dim) the blues and greens.
    //
    // The speed and scale and motion each layer varies slowly within independent
    // hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
    // with a lot of oddly specific numeric ranges.
    //
    // These three custom blue-green color palettes were inspired by the colors found in
    // the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7
    //
    CRGBPalette16 pacifica_palette_1 =
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
    0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
    @@ -48,52 +69,61 @@ CRGBPalette16 pacifica_palette_3 =
    { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
    0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };


    void pacifica_loop()
    {
    static uint16_t cistart1, cistart2, cistart3, cistart4;

    static uint32_t lastms = 0;
    uint32_t ms = millis();
    uint32_t deltams = ms - lastms;
    uint32_t dms = deltams;
    // 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;
    lastms = ms;
    sCIStart1 += (deltams1 * beatsin88(1011,10,13));
    sCIStart2 -= (deltams21 * beatsin88(777,8,11));
    sCIStart3 -= (deltams1 * beatsin88(501,5,7));
    sCIStart4 -= (deltams2 * beatsin88(257,4,6));

    cistart1 += (deltams1 * beatsin8(4,10,13));
    cistart2 -= (deltams21 * beatsin8(3,8,11));
    cistart3 -= (deltams1 * beatsin8(2,5,7));
    cistart4 -= (deltams2 * beatsin8(1,4,6));
    // Clear out the LED array to a dim background blue-green
    fill_solid( leds, NUM_LEDS, CRGB( 2, 6, 10));

    fill_solid( leds, NUM_LEDS, CRGB( 2, 10, 10));

    pacifica_one_layer( pacifica_palette_1, cistart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130));
    pacifica_one_layer( pacifica_palette_2, cistart2, beatsin16( 4, 6 * 256, 9 * 256), beatsin8( 17, 40, 80));
    pacifica_one_layer( pacifica_palette_3, cistart3, 6 * 256, beatsin8( 9, 10,38));
    pacifica_one_layer( pacifica_palette_3, cistart4, 5 * 256, beatsin8( 8, 10,28));
    // 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();
    }

    void pacifica_one_layer( CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri)
    // 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 cs;

    uint16_t waveangle = ioff;
    uint16_t wavescale_half = (wavescale / 2) + 20;
    for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint16_t s16 = sin16( i * 256) + 32768;
    cs = scale16( s16 , wavescale ) + 20;
    waveangle += 250;
    uint16_t s16 = sin16( waveangle ) + 32768;
    uint16_t cs = scale16( s16 , wavescale_half ) + wavescale_half;
    ci += cs;
    uint8_t ci8 = ci / 256;
    uint16_t sindex16 = sin16( ci) + 32768;
    CRGB c = ColorFromPalette( p, scale16(sindex16,240), bri, LINEARBLEND);
    uint8_t sindex8 = scale16( sindex16, 240);
    CRGB c = ColorFromPalette( p, sindex8, bri, LINEARBLEND);
    leds[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);
    @@ -102,7 +132,6 @@ void pacifica_add_whitecaps()
    for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
    wave += 7;

    uint8_t l = leds[i].getAverageLight();
    if( l > threshold) {
    uint8_t overage = l - threshold;
    @@ -111,3 +140,13 @@ void pacifica_add_whitecaps()
    }
    }
    }

    // Deepen the blues and greens
    void pacifica_deepen_colors()
    {
    for( uint16_t i = 0; i < NUM_LEDS; i++) {
    leds[i].blue = scale8( leds[i].blue, 145);
    leds[i].green= scale8( leds[i].green, 200);
    leds[i] |= CRGB( 2, 5, 7);
    }
    }
  2. kriegsman created this gist Jan 3, 2020.
    113 changes: 113 additions & 0 deletions Pacifica.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,113 @@
    //
    // "Pacifica"
    // Gentle, blue-green ocean waves.
    // December 2019, Mark Kriegsman and Mary Corey March.
    // For Dan.
    //

    #define FASTLED_ALLOW_INTERRUPTS 0
    #include <FastLED.h>
    FASTLED_USING_NAMESPACE

    #define DATA_PIN 3
    #define NUM_LEDS 60
    #define MAX_POWER_MILLIAMPS 500
    #define LED_TYPE WS2811
    #define COLOR_ORDER GRB

    //////////////////////////////////////////////////////////////////////////

    CRGB leds[NUM_LEDS];

    void setup() {
    delay( 3000); // 3 second delay for boot recovery, and a moment of silence
    FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
    .setCorrection( CRGB( 255, 145, 145) ); //color balance for deep blues
    FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);
    }

    void loop()
    {
    pacifica_loop();

    FastLED.show();
    delay(10);
    }

    //////////////////////////////////////////////////////////////////////////

    // Three custom blue-green color palettes inspired by the colors found in
    // the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7
    CRGBPalette16 pacifica_palette_1 =
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
    0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
    CRGBPalette16 pacifica_palette_2 =
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
    0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F };
    CRGBPalette16 pacifica_palette_3 =
    { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
    0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };

    void pacifica_loop()
    {
    static uint16_t cistart1, cistart2, cistart3, cistart4;

    static uint32_t lastms = 0;
    uint32_t ms = millis();
    uint32_t deltams = ms - lastms;
    uint32_t dms = deltams;
    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;
    lastms = ms;

    cistart1 += (deltams1 * beatsin8(4,10,13));
    cistart2 -= (deltams21 * beatsin8(3,8,11));
    cistart3 -= (deltams1 * beatsin8(2,5,7));
    cistart4 -= (deltams2 * beatsin8(1,4,6));

    fill_solid( leds, NUM_LEDS, CRGB( 2, 10, 10));

    pacifica_one_layer( pacifica_palette_1, cistart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130));
    pacifica_one_layer( pacifica_palette_2, cistart2, beatsin16( 4, 6 * 256, 9 * 256), beatsin8( 17, 40, 80));
    pacifica_one_layer( pacifica_palette_3, cistart3, 6 * 256, beatsin8( 9, 10,38));
    pacifica_one_layer( pacifica_palette_3, cistart4, 5 * 256, beatsin8( 8, 10,28));

    pacifica_add_whitecaps();
    }

    void pacifica_one_layer( CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri)
    {
    uint16_t ci = cistart;
    uint16_t cs;

    for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint16_t s16 = sin16( i * 256) + 32768;
    cs = scale16( s16 , wavescale ) + 20;
    ci += cs;
    uint8_t ci8 = ci / 256;
    uint16_t sindex16 = sin16( ci) + 32768;
    CRGB c = ColorFromPalette( p, scale16(sindex16,240), bri, LINEARBLEND);
    leds[i] += c;
    }
    }

    void pacifica_add_whitecaps()
    {
    uint8_t basethreshold = beatsin8( 9, 55, 65);
    uint8_t wave = beat8( 7 );

    for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
    wave += 7;

    uint8_t l = leds[i].getAverageLight();
    if( l > threshold) {
    uint8_t overage = l - threshold;
    uint8_t overage2 = qadd8( overage, overage);
    leds[i] += CRGB( overage, overage2, qadd8( overage2, overage2));
    }
    }
    }