Miranda HansenJoshua
Published © GPL3+

Translightion Board (Controllable Music Visualizer)

Translate music to a dazzling light show with this customizable light controller project. Great for DJs, parties, and 1:1 shows!

BeginnerFull instructions provided1 hour6,040
Translightion Board (Controllable Music Visualizer)

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Pmod KYPD
Digilent Pmod KYPD
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×2
WS2812 Addressable LED Strip
Digilent WS2812 Addressable LED Strip
×2
Seeed Studio Grove Sound Sensor v1.6
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Code

FinalLEDControllerWithChloePalette.ino

Arduino
#include <FastLED.h>
#include <Keypad.h>

// --------- BEGIN CONFIGURABLE SETTINGS ---------
// PIN MAPPINGS                                  //
//                                               //
#define LED_PIN     11                            //
//                                               //
#define POT_PIN_01  A5 // Brightness             //
#define POT_PIN_02  A4 // Speed                  //
//                                               //

const int pinAdc = A0;
                  
//                                               //
#define PING_PIN    13                            //
#define ECHO_PIN    12                            //
//                                               //
// SETUP CONSTANTS                               //
//                                               //
#define PING_MIN_RANGE 0                         //
#define PING_MAX_RANGE 12                        //
//                                               //
#define LED_MAX_SPEED 60                         //
//                                               //
#define NUM_LEDS    30                           //
#define LED_TYPE    WS2811                       //
#define COLOR_ORDER GRB                          //
//                                               //
#define SOUND_BUMP_THRESHOLD 20                  //
#define AUDIO_UPDATE_FREQ    10000                //

const byte LINE = 4; // 4 lines
const byte COLUMN = 4; // 4 columms

//Declaration of the key of the keypad
char hexaKeys[LINE][COLUMN] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'0', 'F', 'E', 'D'}
};
//Assignement of pin for the keypad
byte line_pin[LINE] = {2, 3, 4, 5};
byte column_pin[COLUMN] = {6, 7, 8, 9};

Keypad clavier = Keypad( makeKeymap(hexaKeys), line_pin, column_pin, LINE, COLUMN); // creation of object keypad
//                                               //
// ---------- END CONFIGURABLE SETTINGS ----------

// Define color offsets
// Basically we are taking the 16 color pallete and reducing it to 4
#define COLOR_01 0
#define COLOR_02 16
#define COLOR_03 32
#define COLOR_04 48

// GLOBAL VARIABLES

CRGB leds[NUM_LEDS];
CRGBPalette16 currentPalette;
uint8_t led_brightness = 100; // Default only, will be overwritten
uint8_t led_speed = 10;       // Default only, will be overwritten
uint8_t visual = 1;
uint8_t palette = 0;

bool btn_01_status = false;
bool btn_02_status = false;
bool btn_03_status = false;
bool btn_04_status = false;
bool btn_05_status = false;
bool btn_06_status = false;
bool btn_07_status = false;
bool btn_08_status = false;
bool btn_09_status = false;
bool btn_10_status = false;
bool btn_11_status = false;
bool btn_12_status = false;


// BEGIN CODE

void setup() {
  //Initialize LED Strip
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(led_brightness);

  //Set pin modes
  pinMode(PING_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  // Initialize pallete to gray
  currentPalette = CRGBPalette16(
                     CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100),
                     CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100),
                     CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100),
                     CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100), CRGB(100, 100, 100) );

  Serial.begin(9600);
}

void loop()
{
  char key = clavier.getKey();
  Serial.print("Key: ");
  Serial.println(key);
  // Handle button presses
  if (key != 0x00) // if there is not any key, function getKey send NULL character (0x00)
  {
    if (key == '1') {
      if (btn_01_status == false) {
        btn_01_status = true;
        visual = 1;
      }
    } else {
      btn_01_status = false;
    }
    if (key == '2') {
      if (btn_02_status == false) {
        btn_02_status = true;
        visual = 2;
      }
    } else {
      btn_02_status = false;
    }
    if (key == '3') {
      if (btn_03_status == false) {
        btn_03_status = true;
        visual = 3;
      }
    } else {
      btn_03_status = false;
    }
    if (key == '4') {
      if (btn_04_status == false) {
        btn_04_status = true;
        visual = 4;
      }
    } else {
      btn_04_status = false;
    }
    if (key == '5') {
      if (btn_05_status == false) {
        btn_05_status = true;
        visual = 5;
      }
    } else {
      btn_05_status = false;
    }
    if (key == '6') {
      if (btn_06_status == false) {
        btn_06_status = true;
        palette = 1;
      }
    } else {
      btn_06_status = false;
    }
    if (key == '7') {
      if (btn_07_status == false) {
        btn_07_status = true;
        palette = 2;
      }
    } else {
      btn_07_status = false;
    }
    if (key == '8') {
      if (btn_08_status == false) {
        btn_08_status = true;
        palette = 3;
      }
    } else {
      btn_08_status = false;
    }
    if (key == '9') {
      if (btn_09_status == false) {
        btn_09_status = true;
        palette = 4;
      }
    } else {
      btn_09_status = false;
    }
  
     if (key == '0') {
      if (btn_10_status == false) {
        btn_10_status = true;
        visual = 6;
      }
    } else {
      btn_10_status = false;
    }
  
     if (key == 'C') {
      if (btn_11_status == false) {
        btn_11_status = true;
        palette = 5;
      }
    } else {
      btn_11_status = false;
    }
  
     if (key == 'F') {
      if (btn_12_status == false) {
        btn_12_status = true;
        palette = 6;
      }
    } else {
      btn_12_status = false;
    }
  }
  

  Serial.print("Visual: ");
  Serial.print(visual);
  Serial.print(" Palette: ");
  Serial.println(palette);


  // Update variables from potentiometers
  led_brightness = map(analogRead(POT_PIN_01), 0, 1023, 0, 255);
  led_speed = map(analogRead(POT_PIN_02), 0, 1023, 1, LED_MAX_SPEED);

  // Visualizers:
  // runVisualFlow();
  // runVisualPing();
  // runVisualPingBlob();
  // runVisualBounce();
  // runVisualDoubleBounce();
  // runVisualSegments();
  // runVisualSound();

  // Run visual based on visual id number
  // ---------- CHANGE THESE TO CHANGE SELECTED VISUALIZATION ----------
  switch (visual) {
    case 1:
      runVisualFlow();
      break;
    case 2:
      runVisualDoubleBounce();
      break;
    case 3:
      runVisualPing();
      break;
    case 4:
      runVisualPingBlob();
      break;
    case 5:
      runVisualSegments();
      break;
    case 6:
      runVisualSound();
      break;
    default:
      runVisualFlow();
      break;
  }

  // Palettes:
  // setPaletteFire(),
  // setPaletteSynth(),
  // setPaletteParty(),
  // setPaletteBlackWhite()

  // Map Palettes to visual id number
  // ---------- CHANGE THESE TO CHANGE SELECTED PALETTES ----------
  switch (palette) {
    case 1:
      setPaletteFire();
      break;
    case 2:
      setPaletteSynth();
      break;
    case 3:
      setPaletteParty();
      break;
    case 4:
      setPaletteBlackWhite();
      break;
     case 5:
      setChloePalette();
      break;
     case 6:
      setReggaePalette();
      break;
    default:
      break;
  }

  FastLED.show();
  FastLED.delay(1000 / led_speed);
}

// ---------- BEGIN VISUALIZERS ----------

// Turns on leds corresponding to the sound level compared to the last AUDIO_UPDATE_FREQ millisecond period
void runVisualSound() {
  Serial.print("VISUAL SOUND");
  long soundLevel_00 = 0;
  static long soundLevel_01 = 0;
  static long soundLevel_02 = 0;
  static long soundLevel_03 = 0;
  static long soundLevel_04 = 0;

  // Get current sound level
  for (int i = 0; i < 32; i++)
  {
    soundLevel_00 += analogRead(pinAdc);
  }

  soundLevel_00 >>= 5;

  long aveSound = (soundLevel_00 + soundLevel_01 + soundLevel_02 + soundLevel_03 + soundLevel_04) / 5;
  Serial.print("Current Sound: ");
  Serial.print(soundLevel_00);
  Serial.print(" Averaged Sound: ");
  Serial.println(aveSound);
  

  // Map sound level to a value 0 to NUM_LEDs based on long term min/max
  uint8_t ledRange = map(aveSound, 300, 500, 1, NUM_LEDS);
Serial.println(ledRange);
  // Light LEDs based on the sound level
  for ( int i = 0; i < NUM_LEDS; i++) {
    if (i < ledRange) {
      leds[i] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);
    } else {
      leds[i] = ColorFromPalette( currentPalette, COLOR_04, led_brightness, LINEARBLEND);
    }
  }
 soundLevel_04 = soundLevel_03;
  soundLevel_03 = soundLevel_02;
  soundLevel_02 = soundLevel_01;
  soundLevel_01 = soundLevel_00;

}

// Creates sets of 7 LEDs colored in order from the palette and shifts them 1 each cycle
void runVisualFlow() {
  // Create static var to hand current position
  static uint8_t start_position = 0;

  // Update start position to "move" LEDs. In this case just a simple shift
  if (start_position > NUM_LEDS) {
    start_position = getSafeIndex(start_position);
  } else {
    start_position += 1;
  }
  uint8_t current_color = COLOR_01;

  // The visualizer logic goes here
  for ( int i = 0; i < NUM_LEDS; i += 7) {
    leds[getSafeIndex(i + start_position)] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 1)] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 2)] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 3)] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 4)] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 5)] = ColorFromPalette( currentPalette, COLOR_04, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_position + 6)] = ColorFromPalette( currentPalette, COLOR_04, led_brightness, LINEARBLEND);
  }
}

// Sets a back drop of the "base" color 4 and moves an LED of "primary" color 1 up and down the string
void runVisualBounce() {
  // Create static var to hand current position
  static uint8_t start_position = 0;
  static bool move_direction = true;

  // Update start position to "move" LEDs, changing direction when we hit the ends
  if (move_direction) {
    if (++start_position == NUM_LEDS - 1) {
      move_direction = false;
    }
  } else {
    if (--start_position == 0) {
      move_direction = true;
    }
  }

  uint8_t current_color = COLOR_01;

  // Set all LEDs to "base" color 4
  for ( int i = 0; i < NUM_LEDS; i += 1) {
    // Added a bit of randomness to make it less static looking
    // Mostly makes it flash a bit
    leds[i] = ColorFromPalette( currentPalette, COLOR_04 + random(0, 5), led_brightness, LINEARBLEND);
  }

  // Set lead LED to primary color
  leds[start_position] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);

  // Set first trailer LED
  if (move_direction) {
    if (start_position - 1 > 0) {
      leds[start_position - 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position + 1 < NUM_LEDS) {
      leds[start_position + 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  }

  // Set the second trailer LED
  if (move_direction) {
    if (start_position - 2 > 0) {
      leds[start_position - 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position + 2 < NUM_LEDS) {
      leds[start_position + 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  }
}

// Sets a back drop of the "base" color 4 and moves an LED of "primary" color 1 up and down the string
void runVisualDoubleBounce() {
  // Create static var to hand current position
  static uint8_t start_position_1 = 0;
  static bool move_direction_1 = true;
  static uint8_t start_position_2 = NUM_LEDS;
  static bool move_direction_2 = false;

  // Update start position to "move" LEDs, changing direction when we hit the ends
  if (move_direction_1) {
    if (++start_position_1 == NUM_LEDS - 1) {
      move_direction_1 = false;
    }
  } else {
    if (--start_position_1 == 0) {
      move_direction_1 = true;
    }
  }
  if (move_direction_2) {
    if (++start_position_2 == NUM_LEDS - 1) {
      move_direction_2 = false;
    }
  } else {
    if (--start_position_2 == 0) {
      move_direction_2 = true;
    }
  }

  uint8_t current_color = COLOR_01;

  // Set all LEDs to "base" color 4
  for ( int i = 0; i < NUM_LEDS; i += 1) {
    // Added a bit of randomness to make it less static looking
    // Mostly makes it flash a bit
    leds[i] = ColorFromPalette( currentPalette, COLOR_04 + random(0, 5), led_brightness, LINEARBLEND);
  }

  // Set lead LED to primary color
  leds[start_position_1] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);
  leds[start_position_2] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);

  // Set first trailer LED
  if (move_direction_1) {
    if (start_position_1 - 1 > 0) {
      leds[start_position_1 - 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position_1 + 1 < NUM_LEDS) {
      leds[start_position_1 + 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  }
  if (move_direction_2) {
    if (start_position_2 - 1 > 0) {
      leds[start_position_2 - 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position_2 + 1 < NUM_LEDS) {
      leds[start_position_2 + 1] = ColorFromPalette( currentPalette, COLOR_02, led_brightness, LINEARBLEND);
    }
  }

  // Set the second trailer LED
  if (move_direction_1) {
    if (start_position_1 - 2 > 0) {
      leds[start_position_1 - 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position_1 + 2 < NUM_LEDS) {
      leds[start_position_1 + 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  }
  if (move_direction_2) {
    if (start_position_2 - 2 > 0) {
      leds[start_position_2 - 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  } else {
    if (start_position_2 + 2 < NUM_LEDS) {
      leds[start_position_2 + 2] = ColorFromPalette( currentPalette, COLOR_03, led_brightness, LINEARBLEND);
    }
  }
}

// Creates segments of 6 LEDs color from the palette randomly and updates them (and their position) every cycle
void runVisualSegments() {

  // Create random start position to begin our segments at so they don't always appear in the same place
  uint8_t start_pos = random(0, NUM_LEDS + 1);

  for ( int i = 0; i < NUM_LEDS; i += 6) {
    // Pick a random color from our color palette
    // Remember we are effectively limiting it to 4 colors, which have a gap of 16
    uint8_t current_color_offset = random(0, 4) * 16;

    leds[getSafeIndex(i + start_pos)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_pos + 1)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_pos + 2)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_pos + 3)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_pos + 4)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);
    leds[getSafeIndex(i + start_pos + 5)] = ColorFromPalette( currentPalette, current_color_offset, led_brightness, LINEARBLEND);

  }
}

// Sets the "base" color to palette color 4 and lights up all LEDs lower than the ping distance to the "primary" color 1
void runVisualPing() {
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(PING_PIN, LOW);
  long inches = pulseIn(ECHO_PIN, HIGH) / 74 / 2;
  Serial.print("Distance: ");
  Serial.println(inches);

  // Translate distance to a value in the ping control range
  uint8_t ledRange = constrain(inches, PING_MIN_RANGE, PING_MAX_RANGE);
  ledRange = map(ledRange, PING_MIN_RANGE, PING_MAX_RANGE, 0, NUM_LEDS);

  for ( int i = 0; i < NUM_LEDS; i++) {

    if (i < ledRange) {
      leds[i] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);
    } else {
      leds[i] = ColorFromPalette( currentPalette, COLOR_04, led_brightness, LINEARBLEND);
    }
  }
}

// Sets the "base" color to palette color 4 and light up 5 LEDs around the location of the
void runVisualPingBlob() {
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(PING_PIN, LOW);
  long inches = pulseIn(ECHO_PIN, HIGH) / 74 / 2;
  Serial.print("Distance: ");
  Serial.println(inches);

  // Translate distance to a value in the ping control range
  uint8_t ledRange = constrain(inches, PING_MIN_RANGE, PING_MAX_RANGE);
  ledRange = map(ledRange, PING_MIN_RANGE, PING_MAX_RANGE, 0, NUM_LEDS);

  for ( int i = 0; i < NUM_LEDS; i++) {
    if (i <= ledRange + 2 && i >= ledRange - 2) {
      leds[i] = ColorFromPalette( currentPalette, COLOR_01, led_brightness, LINEARBLEND);
    } else {
      leds[i] = ColorFromPalette( currentPalette, COLOR_04, led_brightness, LINEARBLEND);
    }
  }
}

// Gets an index we can safely assign to the led array, makes overflow "wrap" around
uint8_t getSafeIndex(uint8_t index) {
  return (index % NUM_LEDS);
}
// ---------- END VISUALIZERS ----------


// ---------- BEGIN PALETTES ----------

void setPaletteFire()
{
  CRGB color4 = CRGB(180, 0, 0);
  CRGB color3 = CRGB(255, 77, 0);
  CRGB color2 = CRGB(255, 116, 0);
  CRGB color1 = CRGB(255, 154, 0);

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}
void setPaletteSynth()
{
  CRGB color1 = CRGB(212, 0, 120);
  CRGB color2 = CRGB(146, 0, 117);
  CRGB color3 = CRGB(20, 75, 156);
  CRGB color4 = CRGB(0, 0, 0);

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}
void setPaletteParty()
{
  CRGB color1 = CRGB(255, 0, 102);
  CRGB color2 = CRGB(255, 235, 0);
  CRGB color3 = CRGB(0, 152, 195);
  CRGB color4 = CRGB(0, 220, 110);

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}
void setPaletteBlackWhite()
{
  CRGB color1 = CRGB(255, 255, 255);
  CRGB color2 = CRGB(200, 200, 200);
  CRGB color3 = CRGB(150, 150, 150);
  CRGB color4 = CRGB(0, 0, 0);

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}

void setChloePalette()
{
  CRGB color1 = CRGB(148, 0, 211);  //148, 0, 211
  CRGB color2 = CRGB(255, 105, 180);
  CRGB color3 = CRGB(160, 32, 240);
  CRGB color4 = CRGB(255, 69, 0); //255, 69, 0

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}


void setReggaePalette()
{
  CRGB color1 = CRGB(255, 0, 0);  //148, 0, 211
  CRGB color2 = CRGB(255, 215, 0);
  CRGB color3 = CRGB(255, 255, 0);
  CRGB color4 = CRGB(0, 128, 0); //255, 69, 0

  currentPalette = CRGBPalette16(
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4,
                     color1, color2, color3, color4);
}
// ---------- END PALETTES ----------

Credits

Miranda Hansen

Miranda Hansen

3 projects • 7 followers
Joshua

Joshua

2 projects • 1 follower

Comments