Controlling RGB LEDs with Music

I’ve always wanted to do create something audio/visual like a laser show, or audio processing.  After finally getting some spare time to sit down and play around, I decided that making some lighting that responded to music was a great way to get something up and running fairly fast. My vision was to have music playing, and the lights in my room change based on the beat. After some research, it was clear that there was lots of material about getting an Arduino to change the RGB LED lighting that you can get from many sources. So I bought a 5m LED strip off the internet and started putting things together. There were many ways I could’ve gone about controlling the LED strip. These were:

  1. Through the IR remote that came with the control.
    1. I wanted this to happen because of the wireless aspect. However, it would be difficult to get the Arduino to send the right IR sequences to the receiver without an oscilloscope to debug and deconstruct the initial IR code. Also (after more digging), this would limit the output to the preset 16 colours on the remote, something not that desirable.
  2. Through a microphone.
    1. This is the ideal way in my opinion. The Arduino listening and responding to make the LEDs change from any audio source.
  3. Through an AUX cable.
    1. This was the way I used to design and test it. It’s easy to get started, but it limits my wireless capability and it’s difficult to get an audio source playing through both AUX and the main speaker (need splitter, etc).

I decided to break down the strip system into 4 modules. These were Audio source, amplifier, controller and LED lighting (with external power supply).

2015-03-15 12.17.03

  1. Audio Source
    1. This was easy enough. To start, I used an aux cable plugged into my ipod, which split the signal to headphones so I could listen to the music, as well as to the amplifier itself.
  2. Amplifier
    1. I built an (inverting) amplifier using an op-amp circuit I modified from this post. However, I note that with sampling, there would be several issues relating to the signal. The signal is not rectified (but Arduino can’t read -ve voltages anyway, so this is fine)  but, as I was using a change-LED-on-amplitude approach (as opposed to FFT or something else), the waveform (sinusoid shape) gets small before going negative. This is a problem because if sampled at this time, while the music may be loud and have a large amplitude, it would be shown to be deceptively small (seen in image).AM_signalThis can be solved with a circuit piece consisting of a single diode and capacitor (smooth + rectify) known as an ‘envelope detector’, which  is exactly what I needed: this keeps the voltage like a changing DC voltage rather than total analog AC. Unfortunately, late into my design I found this great website detailing a circuit design that I almost could’ve totally used for this module. It has given me good ideas for the future though (I revised and learnt a lot about electronics in this project).
  3. Controller
    1. This is the Arduino. It takes the analog amplified signal and processes it to output a PWM signal to 3 output pins, R, G and B. PWM is used to change the intensity of the colour. An issue I also encountered designing the code for this was the actual colour transition, how would I transition from red (low) to blue (loud) while crossing total green in the middle somewhere? I found out that there are many, many ways to do this, but I used a method that is a sort of piece-wise step function that I adapted from the ones shown here. The code that I used was fairly simple and can be found at the bottom of this post. As the LED strips needed currents way higher than what the Arduino could tolerate, I needed to create some ‘isolation’ between the Arduino outputs and the LED inputs, this was done with the MOSFET circuit shown here. (Lots of this has been done before, that post is great!)

As of yet, the whole system works great. I’ve only tested it with music and a 15cm LED strip, but I’m sure it will work with a larger one. Overall, this was a great project that had me looking at lots of aspects of electronics, going back to basics on some things, and using knowledge fresh in my head on others.


/* Converting sound to changes in an RGB LED strip */
// Josip Simunic
// Colour wheel based on the second image at http://academe.co.uk/225512/2554/arduino-cycling-through-colours-of-the-rainbow/

#define sensorPin A0 
#define red 11 
#define green 10
#define blue 9

int maximum = 845; // Used for calibration
int volume;
int minimum = 5;

/* Seperating the volume into 6 levels and adjusting RGB based on this */
int level6 = maximum; // This is the highest reading the Arduino can read through analog.
int level5 = minimum + (level6/6*5);
int level4 = minimum + (level6/6*4);
int level3 = minimum + (level6/6*3);
int level2 = minimum + (level6/6*2);
int level1 = minimum + (level6/6);

void setup() {
 pinMode(red, OUTPUT); 
 pinMode(green, OUTPUT); 
 pinMode(blue, OUTPUT);
 Serial.begin(9600);
}

/* Note that the pins are inverted - They're HIGH when they're off and LOW when they're on */

void loop() {
 /* Read the music volume. Note, this is an analog reading from 0-1023. Based on a reading of 0-5V*/
 volume = analogRead(sensorPin);
 if (volume > maximum){
 maximum = volume;
 }
 if (volume > minimum){
 Serial.println(volume);
 Serial.println(maximum);
 Serial.println();
 }
 
 /* Mapping the volume to suitable RGB colours, starting at RED and ending at BLUE with GREEN in the middle */
 if (volume < minimum){
 // DO nothing
 } else if (volume <= level1){
 analogWrite(red, map(volume, minimum, level1, 255, 0)); // red rises
 analogWrite(green, 0); // no green
 analogWrite(blue, 0); // no blue
 } else if (volume <= level2){
 analogWrite(red, 255); // max red
 analogWrite(green, map(volume, level1, level2, 255, 0)); // green rises
 analogWrite(blue, 0); // no blue
 } else if (volume <= level3){ 
 analogWrite(red, map(volume, level3, level2, 255, 0)); // red falls
 analogWrite(green, 255); // max green
 analogWrite(blue, 0); // no blue
 } else if (volume <= level4){
 analogWrite(red, 0); // no red
 analogWrite(green, 255); // max green
 analogWrite(blue, map(volume, level3, level4, 255, 0)); // blue rises
 } else if (volume <= level5){
 analogWrite(red, 0); // no red
 analogWrite(green, map(volume, level5, level4, 255, 0)); // green falls
 analogWrite(blue, 255); // max blue
 } else {
 analogWrite(red, 0); // no red
 analogWrite(green, 0); // no green
 analogWrite(blue, 255); // max blue
 }
 
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s