Sound Activated LED Spectrum Analyzer
by sarahwhatsup in Circuits > LEDs
4342 Views, 17 Favorites, 0 Comments
Sound Activated LED Spectrum Analyzer
This guide will show you how to build an LED spectrum analyzer. I built this as an addition to my arcade cabinet, though you can repurpose this guide and use the light bar anywhere you want a sound-activated light display.
The light bar is using an Arduino with a Vu shield to control the LEDs. The LDP8806 LEDs are individually addressable so they can make some nifty patterns. The audio is fed directly through a 3.5mm audio cable coming from the PC (or other sound source). The frequency of the audio is converted to data through an FFT library which tells the lights how to behave.
This project uses code which describes how to create a spectrum analyzer with an equalizer visualization. Instead of a vertical equalizer, the bars are flipped on their side to create a “horizontal equalizer”. Every two bars are connected at the bottom so it gives the appearance of a single bar adjusting from the middle.
What You Need
- Arduino Uno
- Standard A-B USB Cable
- 3 x LDP8806 LEDs (48 LED coil)
- 2.1mm female DC power adapter
- Shifty Vu Shield
- 2x 5V 2A switching power supply (Purchase only one if you plan on supplying power to the Arduino from your PC)
- 3.5mm Male to 2x 3.5mm Female stereo splitter cable
- 2 x 3.5mm male to male stereo audio cable
- Coloured wire
- Wire stripper
- Soldering iron/solder
Downloads
Test Your LEDs
Get everything laid out on a decent sized working space. Plug in your soldering iron. The first thing you want to do is test your LEDs.
I quickly learned these lights don’t like to respond to power without data. If you jump ahead and try to test them with just power and they don’t work, chill out for a second. They might just need some code pumped through to activate the LEDs. Before cutting the LED strip, follow this guide to connect the strip to the Arduino/power. Then run the sample code found here.
Note: One end does have wires pre-soldered to it. Feel free to try with those. On the reel I received the pre-packaged wired just weren’t working (humbug) so I had to cut off two LEDs and start with a bare end of the reel.
Solder the VU Shield
Grab the Shifty VU shield and the Arduino.
The VU shield comes with a set of header pins to connect to the Arduino. These need to be soldered as the connections are too loose to simply plug in even for testing purposes. For tips on how to solder the shield to the Arduino, see this great guide from Sparkfun.
Cut the LED Strips
For this project I used 3 strips of 38 LEDs each.
You can decide how long you’d like the strips to be. Shorter strips (<10 LEDs) probably won’t give you a great effect, but decide what length works for your project and adjust the steps in this guide accordingly.
The LDP8806 strips come with two LEDs per segment, joined with solder every 16 LEDs. You can cut and connect at any point of the strip, however be sure to desolder if you need to disconnect the strip at a connection point. Check out this video which shows how to split this type of strip.
Prep for Connecting
For this guide I’ll be using black, red, yellow and green wire. You can use whatever colours you want but keep in mind I’ll be referencing the colours in the following steps.
Strip the ends to get a few wires of each of the four colours.
Grab your reel of LEDs. You want to find the end with the arrow pointing away from the cut of the strip. Depending on how they were shipped this can be at either end of the reel.
Carefully cut off the end of the weatherstripping so you can get to the connectors (or just cut it away altogether).
Tin the connectors with solder. This makes it way easier to solder the wires. Again, pay attention to the direction of the arrow; notice how it’s pointing away from the solder. This is the direction data flows, and if you mix them up you could damage the strip.
Just checking, you have the arrow the right way yeah? If not you’ll bust your strip. You’ve been warned.
Connecting the LEDs
These LEDs have four pins; ground, 5v, C (clock) and D (data). Some sections of the strip have values marked on them, some don’t. That’s okay, just be aware of which pin you’re soldering to. Refer to the wiring diagram as you go and double-check the direction your strips are facing.
Solder the strips together, making sure each output connects to its respective input.
Connect to Arduino/power
Grab your 5V power supply and the Arduino.
From the beginning input side of the strip arrangement, connect the green data wire to Pin 2, and the yellow clock wire to Pin 3. The red 5V wire connects directly to the power supply, and both the power and LED strip share a common ground with the Arduino.
Refer to the wiring diagram above and double-check all connections.
Code
Connect the Arduino to your PC. Grab your audio splitter and connect it to your PC. Use one audio cable to connect to the VU shield and the other to connect to a speaker. Connect the power adapter to a power outlet.
Once you have everything connected, run the test program from Step 0 to double-check everything lights up.
Download the project code from Github and add to your Arduino library. Open the Arduino IDE and upload.
#include "fix_fft.h"
#include "HSBColor.h" #include "LPD8806.h" #include "SPI.h" // Choose 2 pins for Arduino output
#define DATA_PIN 2
#define CLOCK_PIN 3
// Defines the number and arrangement of LEDs in the visualizer. For a vertical setup, this will determine the space to light ratio as they wrap
#define NUM_BARS 12
#define BAR_LENGTH 12
// The difference in hue for each bar after the first.
#define BAR_HUE_DIFF 8
// Create a LPD8806 instance to control the strip
LPD8806 strip = LPD8806(NUM_BARS * BAR_LENGTH, DATA_PIN, CLOCK_PIN);
// The current hue of the first strip of the bar
int curHue = 0;
// FFT data storage
char im[NUM_BARS * 2], data[NUM_BARS * 2];
int prev[NUM_BARS];
// HSB/RGB data buffer
int rColor[3];
// Converts a 2d visualizer point to it's location on the strip
int getStripLocation(int col, int row)
{
// Controls the strip in alternating directions. This allows for chaining horizontal bars end-to-end
if (col % 2 == 0)
row = BAR_LENGTH - row - 1;
return col * BAR_LENGTH + row;
}
void setup()
{
analogReference(DEFAULT);
strip.begin();
strip.show();
}
void loop()
{
uint16_t i, j, k;
uint32_t color;
// Read analog input
for (i = 0; i < NUM_BARS * 2; i++)
{
int val = (analogRead(3) + analogRead(2)) / 2;
data[i] = val * 2;
im[i] = 0;
delay(1);
}
// Set the background colour of the LEDs when they are not receiving music data
for (i = 0; i < NUM_BARS * BAR_LENGTH; i++)
strip.setPixelColor(i, 20, 20, 40);
// Set the proper pixels in each bar
for (i = 0; i < NUM_BARS; i++)
{
// Each LED bar has 2 FFT frequencies that are summed together
int fft_start = i * 2;
int fft_count = 2;
// Get a positive data point from the FFT
int curData = 0;
for (k = 0; k < fft_count; k++)
curData += sqrt(data[fft_start + k] * data[fft_start + k] + im[fft_start + k] * im[fft_start + k]);
// Account for the ShiftyVU's filtering
if (i == 0 || i == 7)
curData /= 2;
// Smoothly drop from peaks by only allowing data points to be one LED lower than the previous iteration.
// This prevents seizure-inducing flashes which might be caused by the ShiftyVU's filtering (?)
if (prev[i] > BAR_LENGTH && curData < prev[i] - BAR_LENGTH)
curData = prev[i] - BAR_LENGTH;
// Base color for each bar
H2R_HSBtoRGB((curHue + i * 8) % 360, 99, 99, rColor);
color = strip.Color(rColor[0] / 2, rColor[1] / 2, rColor[2] / 2);
// If only the first LED is lit, but not fully. This is outside the for loop because the subtraction of
// BAR_LENGTH causes the value to wrap around to a very high number.
if (curData < BAR_LENGTH)
{
int brightness = curData * 99 / BAR_LENGTH;
H2R_HSBtoRGB((curHue + i * BAR_HUE_DIFF) % 360, 99, brightness, rColor);
// Colour of the base of each bar. Change this to match the background colour of the LEDs
strip.setPixelColor(i, 20, 20, 40);
}
else
{
for (j = 0; j < BAR_LENGTH; j++)
{
// Light up each fully lit LED the same way.
if (curData - BAR_LENGTH > j * BAR_LENGTH)
strip.setPixelColor(getStripLocation(i, j), color);
else if (curData > j * BAR_LENGTH)
{
// Dims the last LED in the bar based on how close the data point is to the next LED.
int brightness = (j * BAR_LENGTH - curData) * 99 / BAR_LENGTH;
H2R_HSBtoRGB((curHue + i * BAR_HUE_DIFF) % 360, 99, brightness, rColor);
strip.setPixelColor(getStripLocation(i, j), strip.Color(rColor[0] / 2, rColor[1] / 2, rColor[2] / 2));
}
}
}
// Store all of the data points for filtering of the next iteration.
prev[i] = curData;
}
// Cycle through all the colors.
if (curHue == 359)
curHue = 0;
else
curHue++;
// Display the strip.
strip.show();
}
Play Some Music
Once everything is uploaded, play some music! You should now have something like this (mine is covered with a light panel sheet for diffusion).