LED Music Visualizer

Music Visualizer

Connor Burke May 7, 2020

Materials:

 

  • LED Strip (Wheel from Amazon)
  • Milti-core wire
  • Soldering Iron
  • Arduino Circuit Playground
  • Arduino Crickit
  • Single Canvas
  • White Gaff Tape
  • White Card stock Board
  • Thumbtacks

Step 1:

Connect your led strip to the Crickit NeoPixel connector with the soldering iron. Also, make sure the arrow in the LED strip, is facing upwards, away from the Crickit. 

                                         .                                                                 

Step 2:

Solder your wires to the correct placements on the LED strips and follow the purple picture guide. 

 

Step 3:

Use the Arduino NeoPixel library in Arduino and run the “Strandtest” code to make sure the connections are correctly and all the lights being lit up.

 

Step 4:

Use the Gaff Tape to hold doe the wires into the correct spacing on the white cards tock board. The cut slits into the back to full the wires through to make it flush and then tape those down as well.   

           

Step 5:

Attach the Arduino to the back of the card stock board.

Step 6:

Attach the canvas to the front of the card stock board covering the LED strips.

Step 7:

Run Code:

#include <FastLED.h>

#include <Adafruit_CircuitPlayground.h>

#include <Wire.h>

#include <SPI.h>

// Arduino Music Visualizer 0.2

// This music visualizer works off of analog input from a 3.5mm headphone jack

// Just touch jumper wire from A0 to tip of 3.5mm headphone jack

// The code is dynamic and can handle variable amounts of LEDs

// as long as you adjust NUM_LEDS according to the amount of LEDs you are using

// LED LIGHTING SETUP

#define LED_PIN     A1

#define NUM_LEDS    78

#define BRIGHTNESS  200

#define LED_TYPE    WS2811

#define COLOR_ORDER BGR

CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100

//#define ANALOG_INPUT  A4

// AUDIO INPUT SETUP

//int audio = A3;

#define SAMPLE_WINDOW   10  // Sample window for average level

#define PEAK_HANG       24  // Time of pause before peak dot falls

#define PEAK_FALL        4  // Rate of falling peak dot

#define INPUT_FLOOR     56  // Lower range of mic sensitivity in dB SPL

#define INPUT_CEILING  110  // Upper range of mic sensitivity in db SPL

byte peaking = 13;        // Peak level of column; used for falling dots

unsigned int sample;

float mapf(float x, float in_min, float in_max, float out_min, float out_max);

// STANDARD VISUALIZER VARIABLES

int midway = NUM_LEDS / 2; // CENTER MARK FROM DOUBLE LEVEL VISUALIZER

int loop_max = 0;

int k = 255; // COLOR WHEEL POSITION

int decay = 0; // HOW MANY MS BEFORE ONE LIGHT DECAY

int decay_check = 0;

long pre_react = 0; // NEW SPIKE CONVERSION

long react = 0; // NUMBER OF LEDs BEING LIT

long post_react = 0; // OLD SPIKE CONVERSION

uint16_t holder;

//// RAINBOW WAVE SETTINGS

int wheel_speed = 3;

// GLOBAL STUFF ————————————————————

// To keep the display ‘lively,’ an upper and lower range of volume

// levels are dynamically adjusted based on recent audio history, and

// the graph is fit into this range.

#define  FRAMES 8

uint16_t lvl[FRAMES],           // Audio level for the prior #FRAMES frames

         avgLo  = 6,            // Audio volume lower end of range

         avgHi  = 255,          // Audio volume upper end of range

         // avgHi  = 512,          // Audio volume upper end of range

         sum    = 256 * FRAMES; // Sum of lvl[] array

uint8_t  lvlIdx = 0;            // Counter into lvl[] array

int16_t  peak   = 0;            // Falling dot shows recent max

int8_t   peakV  = 0;            // Velocity of peak dot

// RAINBOW WAVE SETTINGS

//int wheel_speed = 3;

void setup()

{

  CircuitPlayground.begin();

  // LED LIGHTING SETUP

  delay( 30 ); // power-up safety delay

  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );

  FastLED.setBrightness(  BRIGHTNESS );

  // CLEAR LEDS

  //

  // SERIAL AND INPUT SETUP

  Serial.begin(115200);

  // pinMode(audio, INPUT);

  // Serial.println(“\nListening…”);

}

// FUNCTION TO GENERATE COLOR BASED ON VIRTUAL WHEEL

// https://github.com/NeverPlayLegit/Rainbow-Fader-FastLED/blob/master/rainbow.ino

CRGB Scroll(int pos) {

  CRGB color (0, 0, 0);

  if (pos < 85) {

    color.g = 0;

    color.r = ((float)pos / 85.0f) * 255.0f;

    color.b = 255 – color.r;

  } else if (pos < 170) {

    color.g = ((float)(pos – 85) / 85.0f) * 255.0f;

    color.r = 255 – color.g;

    color.b = 0;

  } else if (pos < 256) {

    color.b = ((float)(pos – 170) / 85.0f) * 255.0f;

    color.g = 255 – color.b;

    color.r = 1;

  }

  return color;

}

void convertDouble() {

  if (holder > 80)

    pre_react = ((long)midway * (long)holder) / 1023L; // TRANSLATE AUDIO LEVEL TO NUMBER OF LEDs

  if (pre_react > react) {// ONLY ADJUST LEVEL OF LED IF LEVEL HIGHER THAN CURRENT LEVEL

    react = pre_react;

    Serial.print(holder);

    Serial.print(” -> “);

    Serial.println(pre_react);

  }

}

void loop()

{

  uint8_t  i, r, g, b;

  uint16_t minLvl, maxLvl, a, scaled;

  int16_t  p;

  p           = CircuitPlayground.mic.soundPressureLevel(10); // 10 ms

Serial.println(p);

  p           = map(p, 60, 130, 0, 1024); // Scale to 0-350 (may overflow) // was 350

  a           = constrain(p, 0, 1024);    // Clip to 0-350 range

  sum        -= lvl[lvlIdx];

  lvl[lvlIdx] = a;

  sum        += a;                              // Sum of lvl[] array

  minLvl = maxLvl = lvl[0];                     // Calc min, max of lvl[]…

  for (i = 1; i < FRAMES; i++) {

    if (lvl[i] < minLvl)      minLvl = lvl[i];

    else if (lvl[i] > maxLvl)     maxLvl = lvl[i];

  }

  // Keep some minimum distance between min & max levels,

  // else the display gets “jumpy.”

  //  if ((maxLvl – minLvl) < 23) {

  //      maxLvl = (minLvl < (255 – 23)) ? minLvl + 23 : 255;

  //    }

  if ((maxLvl – minLvl) < 40) {

    maxLvl = (minLvl < (255 – 40)) ? minLvl + 40 : 255;

    // maxLvl = (minLvl < (512 – 40)) ? minLvl + 40 : 512;

  }

  avgLo = (avgLo * 7 + minLvl + 2) / 8; // Dampen min/max levels

  avgHi = (maxLvl >= avgHi) ?           // (fake rolling averages)

          (avgHi *  3 + maxLvl + 1) /  4 :    // Fast rise

          (avgHi * 31 + maxLvl + 8) / 32;     // Slow decay

  // holder = map(avgHi, 0, 200, 0, 250);

  holder = avgHi – 45;

   Serial.print(“a = “);

  Serial.println(holder );

  

  if (++lvlIdx >= FRAMES) lvlIdx = 0;

  delay (1);

  if ( holder > 80)

  {

    pre_react = ((long)NUM_LEDS * (long)holder+2) / 1023L; // TRANSLATE AUDIO LEVEL TO NUMBER OF LEDs

    if (pre_react > react) // ONLY ADJUST LEVEL OF LED IF LEVEL HIGHER THAN CURRENT LEVEL

      react = pre_react;

    //

    Serial.print(a);

    Serial.print(” -> “);

    Serial.println(pre_react);

  }

  //singleLevel();

  doubleLevel();

  delay(1);

}

// FUNCTION TO VISUALIZE WITH MIRRORED LEVELS

void doubleLevel()

{

  convertDouble();

  doubleRainbow();

  k = k – wheel_speed; // SPEED OF COLOR WHEEL

  if (k < 0) // RESET COLOR WHEEL

    k = 255;

  // REMOVE LEDs

  decay_check++;

  if (decay_check > decay)

  {

    decay_check = 0;

    if (react > 0)

      react–;

  }

}

// FUNCTION TO GET AND SET COLOR

// THE ORIGINAL FUNCTION WENT BACKWARDS

// THE MODIFIED FUNCTION SENDS WAVES OUT FROM FIRST LED

// https://github.com/NeverPlayLegit/Rainbow-Fader-FastLED/blob/master/rainbow.ino

void singleRainbow()

{

  for (int i = NUM_LEDS – 1; i >= 0; i–) {

    if (i < react)

      leds[i] = Scroll((i * 256 / 50 + k) % 256);

    else

      leds[i] = CRGB(0, 0, 0);

  }

  FastLED.show();

}

// FUNCTION TO GET AND SET COLOR

// THE ORIGINAL FUNCTION WENT BACKWARDS

// THE MODIFIED FUNCTION SENDS WAVES OUT FROM FIRST LED

// https://github.com/NeverPlayLegit/Rainbow-Fader-FastLED/blob/master/rainbow.ino

void rainbow()

{

  for (int j = 0; j < 256; j++) {

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

      if (i < holder)

        //if (i < react)

        leds[i] = Scroll((i * 256 / NUM_LEDS + j) % 256);

      else

        leds[i] = CRGB(0, 0, 0);

    }

    FastLED.show();

    delay(1);

    //  for (int i = NUM_LEDS – 1; i >= 0; i–) {

    //    if (i < react)

    //      leds[i] = Scroll((i * 256 / 50 + k) % 256);

    //    else

    //      leds[i] = CRGB(0, 0, 0);

    //  }

    //  FastLED.show();

  }

}

// FUNCTION TO MIRRORED VISUALIZER

void doubleRainbow()

{

  for (int i = NUM_LEDS – 1; i >= midway; i–) {

    if (i < react + midway) {

      //Serial.print(i);

      //Serial.print(” -> “);

      leds[i] = Scroll((i * 256 / 50 + k) % 256);

      //leds[i] = Scroll((i * 256 / NUM_LEDS + k) % 256);

      //Serial.print(i);

      //Serial.print(” -> “);

      leds[(midway – i) + midway] = Scroll((i * 256 / 50 + k) % 256);

      //      Serial.print(“midway: “);

      //      Serial.println(midway);

    }

    else

      leds[i] = CRGB(0, 0, 0);

    leds[midway – react] = CRGB(0, 0, 0);

  }

  FastLED.show();

}

void convertSingle()

{

  if (holder > 80)

  {

    pre_react = ((long)NUM_LEDS * (long)holder) / 1023L; // TRANSLATE AUDIO LEVEL TO NUMBER OF LEDs

    if (pre_react > react) // ONLY ADJUST LEVEL OF LED IF LEVEL HIGHER THAN CURRENT LEVEL

      react = pre_react;

    Serial.print(holder);

    Serial.print(” -> “);

    Serial.println(pre_react);

  }

}

// FUNCTION TO VISUALIZE WITH A SINGLE LEVEL

void singleLevel()

{

  convertSingle();

  singleRainbow(); // APPLY COLOR

  k = k – wheel_speed; // SPEED OF COLOR WHEEL

  if (k < 0) // RESET COLOR WHEEL

    k = 255;

  // REMOVE LEDs

  decay_check++;

  if (decay_check > decay)

  {

    decay_check = 0;

    if (react > 0)

      react–;

  }

}

Adjust the number of LEDs you have and the amount of brightness you would prefer.

Step 8:

Enjoy by playing your favorite music through a bluetooth speaker to watch your music come to life.

Leave a Reply