In my last post I explained how to control the brightness of multiple light emitting diodes connected to an Arduino with an interface scripted in Processing. The script which I created was great because it just took a series of values sent via USB and lit the LED’s appropriately. This is convenient because it is not specific to any input which might be needed to control the lights. The script to send a value serially along with an indicator character can be added to any Processing script. Naturally one of the first things I had to do with it was create an audio visualizer. With the Arduino programmed as it was all I had to do was use a sound library to break an audio input into frequency bands and send the values down.
The circuit is pretty straight forward. Six LED’s are connected through resistors to the six pins which support PWM (3, 6, 5, 9, 10, 11) and to a ground pin. I have everything crammed onto a tiny breadboard on my proto-sheild cause it’s cute and self contained. That’s just my style. PWM stands for Pulse Width Modulation and is the a way to control the brightness of LED’s as well as some other components. It is a digital output and produces the effect by switching on and off very quickly. The result can be visualized as a square wave. When you send a higher value to a PWM pin it will spend more time on than off. This blinking is faster than we can see so the LED appears to be changing brightness according to the amount of time it spends in the on position.
The Arduino is programmed with a script that interprets the serially transmitted data. It uses an array to store all the data and checks for ‘indicator’ characters. This lets the program know how to interpret the data. Alternatively there could only be one indicator and then the script could take the next six characters and use them as necessary; however, this allows more flexibility. If only a few pins are needed the same script will continue working. The Processing script can just send the needed values with appropriate indicators and all unused pins will remain at zero.
arduino code
code formatterArduino Script
int led0=3; // variables to store the pin numbers int led1=5; int led2=6; int led3=9; int led4=10; int led5=11; int lVal0=0; // variables to store the brightness values int lVal1=0; int lVal2=0; int lVal3=0; int lVal4=0; int lVal5=0; char buff[]= "000000000000"; // array that stores incoming serial data void setup() { Serial.begin(9600); pinMode(led0,OUTPUT); // set up pins pinMode(led1,OUTPUT); pinMode(led2,OUTPUT); pinMode(led3,OUTPUT); pinMode(led4,OUTPUT); pinMode(led5,OUTPUT); } void loop() { analogWrite(led0,lVal0); // write the brightness values to the pins analogWrite(led1,lVal1); analogWrite(led2,lVal2); analogWrite(led3,lVal3); analogWrite(led4,lVal4); analogWrite(led5,lVal5); while (Serial.available()>0) { // if there is incoming data for (int i=0; i<12; i++) { // for each element in the buffer array buff[i]=buff[i+1]; // take the value of the next element } buff[12]=Serial.read(); // place incoming data in last element if (buff[12]=='A') { // if this indicator value is received lVal0=int(buff[11]); // place the previous element in lVal0 } if (buff[12]=='B') { // each value has a different indicator lVal1=int(buff[11]); } if (buff[12]=='C') { lVal2=int(buff[11]); } if (buff[12]=='D') { lVal3=int(buff[11]); } if (buff[12]=='E') { lVal4=int(buff[11]); } if (buff[12]=='F') { lVal5=int(buff[11]); } } delay(10); }
The Processing script is a little bit more involved. To get the audio input I use the ESS library, but there are a few others which also work. ESS works great for this purpose. The code is very similar to an audio visualization script explained in an older post but with the addition of frequency band averages to control each LED as well as some sliders to control scaling and damping and of course the serial writing functions.
processing code
code formatterProcessing Script
import krister.Ess.*; // import audio library import processing.serial.*; // serial communication library FFT myfft; // create new FFT object (audio spectrum) AudioInput myinput; // create input object int bufferSize=256; // variable for number of frequency bands int audioScale; // variable to control scaing slider s1; // create two slider objects slider s2; Serial port; void setup() { size(510,380); frameRate(30); background(255); noStroke(); fill(0); smooth(); Ess.start(this); // start audio myinput=new AudioInput(bufferSize); // define input myfft=new FFT(bufferSize*2); // define fft myinput.start(); myfft.damp(.01); // damping creates smoother motion myfft.equalizer(true); myfft.limits(.005,.01); myfft.averages(6); // controls number of averages println("Available serial ports:"); // define 'port' as first println(Serial.list()); // ...available serial port port = new Serial(this, Serial.list()[0], 9600); s1=new slider(400,70,255, color(200,150,80)); // define slider objects s2=new slider(450,70,255, color(200,150,80)); s1.p=100; // default position of sliders s2.p=200; } void draw() { background(255); pushStyle(); s1.render(); // render sliders s2.render(); popStyle(); audioScale=s1.p*20; // adjust audio scale according to slider myfft.damp(map(s2.p,0,255,.01,.1)); // adjust daming for (int i=0; i<bufferSize;i++) { // draw frequency spectrum rect((i*1)+50,330,1,myfft.spectrum[i]*(-audioScale)); } pushStyle(); for (int i=0; i<6; i++) { // draw averages int a=int(myfft.averages[i]*(-audioScale)); fill(200,150,80,100); rect((i*43)+50,330,43,a); fill(200,150,0); rect((i*43)+50,330+a,43,3); } popStyle(); // write each average to the serial port followed by indicator character // the values are constrained from 0 to 255 so the arduino can handle them // values above 255 would start back at zero port.write(int(constrain(myfft.averages[0]*audioScale,0,255))); port.write('A'); port.write(int(constrain(myfft.averages[1]*audioScale,0,255))); port.write('B'); port.write(int(constrain(myfft.averages[2]*audioScale,0,255))); port.write('C'); port.write(int(constrain(myfft.averages[3]*audioScale,0,255))); port.write('D'); port.write(int(constrain(myfft.averages[4]*audioScale,0,255))); port.write('E'); port.write(int(constrain(myfft.averages[5]*audioScale,0,255))); port.write('F'); } // sets up audio input public void audioInputData(AudioInput theInput) { myfft.getSpectrum(myinput); }
You’ll need to grab the slider class from my last post (at the bottom) for this to work or you can just define the audio damping and scaling within the setup function and take them out all together. You will also need to download the ESS sound library and have it placed in the proper folder. The serial library is included in Processing by default but must be called in order to function.
The result is the brightness if each LED will change according to the volume of the respective frequency in the audio spectrum. As a certain pitch increases that LED will become brighter. Using the averages rather than just specific frequency bands gives more accurate results, allows for any number of outputs, and also allows for a nice visual. The full spectrum with the overlaid averages shows what’s gong on better than just a few chunks.
Ammar Askar
Wow! I just switched out the LEDs for RGB LEDs, attatched them to my roof and instant disco lighting. Thank you for this awesome tutorial.
HellBringer
I have a problem. I made all perfect as it is in the tutorial but the led’s don’t light. can you give me some advice?
Anthony
I’m sorry you’re having some trouble. There is really no way for me to know what the problem is. Debugging is a complex and interactive process. However, there are some great tutorials and examples on the arduino site. Learning some more of the basics might help you spot your error. Good luck.
HellBringer
I’ve uploaded the code to arduino, modefy the processing code with the class you say. the arduino recive data but the leds dosent light. I have an Arduino Mega 2560 and i used the pins 6 to 11 on PWM for the led’s
HellBringer
Man please help me with this one. i will show you all just tell me what… i can upload you pictures conde that i use. just help me make this. i’ve debuged the processin and make it print everi value that is generate. and the numbers show up but no lights
deflame
i have a problem about exportin as an application in windows. everything is perfect if i run the code on processing but when i export it as an application such as asdas.exe this exe file doest work so i tried examples in processing they doing well. can you help me?
Anthony
There’s really no way for me to say without more detail. I also work on a mac so i don’t have any experience there. You might be able to find some answers in the Processing Forum. Post your question with more detail about the system your running and the script and I’m sure someone will be able to help you.
deflame
thank you Anthony for trying to help me.
Samit
Wow! Good job Anthony. You rock! Thanks a zillion for this awesome tutorial.
I used this to light up 2 LED strips and it worked!
@ HellBringer : I had the same problem initially.
The solution :
Step 1 : uploaded the “Arduino code” to arduino
Step 2 : upload the “Processing code” to processing, add the slider class (maybe in a new tab). you will have to change the “+” to “&&” as already mentioned.
Step 3 : (The most important bit) in the processing code scroll down to :
<<<>> and change “”Serial.list()[0],”" to “”Serial.list()[1],”"
This should work.
Usually “COM1″ is 0, My arduino had occupied “COM4″ which was 1. so i changed it to “1″.
Nelson Machupa
Ok, normally im alright with coding and debugging and such, but i simply cannot get what is wrong with this thing…. at
myinput.start();
it has the following debug: http://pastebin.com/1jfnrJ7G
Thanks for any help
Nelson Machupa
Nevermind that last comment… i removed myinput.start(); just to see if it would work, the arduino was flashing so i know it was getting some kinda of data…. and the spectrum window poped up too, but there was no waves. Im kinda lost in the code as to where its getting the audio from? most things like php, html, etc. always define a pathway to get the audio from, yet i cant seem to find anything like that? Maybe im missing something?