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.