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.

arduino led audio visualizer

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.

pulse width modulation graph

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 formatter
Arduino 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.

audio spectrum interface

processing code
code formatter
Processing 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.


11 comments

  • Ammar Askar
    12.09.10

    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
    12.09.10

    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
    12.09.10

    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
    12.10.10

    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
    12.11.10

    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
    01.05.11

    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
    01.07.11

    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
    01.08.11

    thank you Anthony for trying to help me.


  • Samit
    01.23.11

    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
    02.11.11

    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
    02.12.11

    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?