Close

Coding The Animations

A project log for Awesome Mix Vol. 1

Cassette Tape SAO with backlit LED spools and I2C-triggered visualizations animating Fast Forward, Rewind, Play, and Pause.

dustin-johnsonDustin Johnson 10/16/2024 at 09:190 Comments

I enhanced the prototype code to implement animations for PLAY, PAUSE, REWIND, and FASTFORWARD -- video of latest functionality is at the bottom of this project log.

I included an indexing offset to imitate the asymmetric spinning of the rotational indicator on tape spools, as seen here: 

Here is the code:

// neopixel code
// --------------
#include <FastLED.h>
#define LED_PIN 5
#define LED_COUNT 14
#define LED_BRIGHTNESS 5 // max 255 which is blinding
#define LED_CENTER_LEFT 0
#define LED_CENTER_RIGHT 7
CRGB leds[LED_COUNT]; // must be lowercase and this variable name or the compilation fails
int LED_LEFT_CENTER = 0;
int LED_RIGHT_CENTER = 7;
int LED_LEFT_MIN = 1; // exclude center LED (left spool)
int LED_LEFT_MAX = 6; // exclude center LED (left spool)
int LED_RIGHT_MIN = 8; // exclude center LED (right spool)
int LED_RIGHT_MAX = 13; // exclude center LED (right spool)
int LED_LEFT_INDEX = random(LED_LEFT_MIN, LED_LEFT_MAX); // index for rotation animations (left spool)
int LED_RIGHT_INDEX = random(LED_RIGHT_MIN, LED_RIGHT_MAX); // index for rotation animations (right spool)
CRGB FOREGROUND_COLOR = CRGB::Black;
CRGB BACKGROUND_COLOR = CRGB::Orange;
CRGB CENTER_COLOR = CRGB::Red;


// function prototypes
// --------------
void animation_play(int millisDelay = 130); // function prototype to accept optional argument
void animation_rewind(int millisDelay = 50); // function prototype to accept optional argument

// main setup
// --------------
void setup() {
  Serial.begin(9600);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, LED_COUNT);
  FastLED.setBrightness(LED_BRIGHTNESS);
  animation_bootup();
}

// main loop
// --------------
void loop() { 
  
  animation_function_triggered(CRGB::White);
  for (int i=0; i < 20; i++) {
    animation_pause();
  }

  animation_function_triggered(CRGB::White);
  for (int i=0; i < 50; i++) {
    animation_play();
  }

  animation_function_triggered(CRGB::White);
  for (int i=0; i < 150; i++) {
    animation_fastforward();
  }

  animation_function_triggered(CRGB::White);
  for (int i=0; i < 50; i++) {
    animation_play();
  }

  animation_function_triggered(CRGB::White);
  for (int i=0; i < 50; i++) {
    animation_rewind();
  }
}

// blink to indicate function triggered
void animation_function_triggered(CRGB color) {
  // on
  leds[LED_LEFT_CENTER] = color;
  leds[LED_RIGHT_CENTER] = color;
  FastLED.show();
  // sleep
  delay(100);
  // off
  leds[LED_LEFT_CENTER] = CRGB::Black;
  leds[LED_RIGHT_CENTER] = CRGB::Black;
  FastLED.show();
}

void animation_pause() {
  leds[LED_LEFT_INDEX] = BACKGROUND_COLOR;
  leds[LED_RIGHT_INDEX] = BACKGROUND_COLOR;
  FastLED.show();
  delay(100);
}

void animation_bootup() {

  // illuminate left spool
  for (int i = LED_LEFT_MIN; i <= LED_LEFT_MAX; i++) {
    if (i == LED_CENTER_LEFT) { continue; }
    leds[i] = BACKGROUND_COLOR;
    FastLED.show();
    delay(50);
  }

  // illuminate right spool
  for (int i = LED_RIGHT_MIN; i <= LED_RIGHT_MAX; i++) {
    if (i == LED_CENTER_RIGHT) { continue; }
    leds[i] = BACKGROUND_COLOR;
    FastLED.show();
    delay(50);
  }
}


void animation_fastforward() {

  animation_play(40);

}

// speed is delay, so more is slower
void animation_play(int millisDelay) {
 
  // animation: PLAY (left spool)
  if (LED_LEFT_INDEX < LED_LEFT_MAX) {
    leds[LED_LEFT_INDEX] = BACKGROUND_COLOR;
    leds[LED_LEFT_INDEX+1] = FOREGROUND_COLOR;
    LED_LEFT_INDEX++;    
  } else {
    leds[LED_LEFT_MAX] = BACKGROUND_COLOR;
    leds[LED_LEFT_MIN] = FOREGROUND_COLOR;
    LED_LEFT_INDEX = LED_LEFT_MIN;
  }

  // animation: PLAY (right spool)
  if (LED_RIGHT_INDEX < LED_RIGHT_MAX) {
    leds[LED_RIGHT_INDEX] = BACKGROUND_COLOR;
    leds[LED_RIGHT_INDEX+1] = FOREGROUND_COLOR;
    LED_RIGHT_INDEX++;    
  } else {
    leds[LED_RIGHT_MAX] = BACKGROUND_COLOR;
    leds[LED_RIGHT_MIN] = FOREGROUND_COLOR;
    LED_RIGHT_INDEX = LED_RIGHT_MIN;
  }
 
  FastLED.show();  
  delay(millisDelay);
}

// speed is delay, so more is slower
void animation_rewind(int millisDelay) {
 
  // animation: REWIND (left spool)
  if (LED_LEFT_INDEX > LED_LEFT_MIN) {
    leds[LED_LEFT_INDEX] = BACKGROUND_COLOR;
    leds[LED_LEFT_INDEX-1] = FOREGROUND_COLOR;
    LED_LEFT_INDEX--;
    Serial.println("decrement index");
  } else {
    leds[LED_LEFT_MIN] = BACKGROUND_COLOR;
    leds[LED_LEFT_MAX] = FOREGROUND_COLOR;
    LED_LEFT_INDEX = LED_LEFT_MAX;
    Serial.println("restart index");
  }

  // animation: REWIND (right spool)
  if (LED_RIGHT_INDEX > LED_RIGHT_MIN) {
    leds[LED_RIGHT_INDEX] = BACKGROUND_COLOR;
    leds[LED_RIGHT_INDEX-1] = FOREGROUND_COLOR;
    LED_RIGHT_INDEX--;    
  } else {
    leds[LED_RIGHT_MIN] = BACKGROUND_COLOR;
    leds[LED_RIGHT_MAX] = FOREGROUND_COLOR;
    LED_RIGHT_INDEX = LED_RIGHT_MAX;
  }

  Serial.print("LED_LEFT_INDEX: ");
  Serial.print(LED_LEFT_INDEX);
  Serial.println();
  Serial.print("LED_RIGHT_INDEX: ");
  Serial.print(LED_RIGHT_INDEX);
  Serial.println();
 
  FastLED.show();  
  delay(millisDelay);
}

... and the updated animations:

Discussions