Introduction: An LED Panel Controlled by Your Guitar! (or Other Audio Source)

About: I'm a grad student working on autonomous systems at the Georgia Institute of Technology in the Aerospace Systems Design Lab. Before that, I was a music major for a while! C'est la vie...

Ever wanted to have a light show that reacts to what you play through you're favorite electric instrument? This instructable will show you how!

This one is based on an Arduino Uno microcontroller, an Adafruit 16x32 RGB LED matrix panel, and part of this instructable on how to amplify an electric audio source.

Parts list:

(x1) Arduino Uno

(x1) Adafruit 16x32 RGB LED matrix panel (can also use a 32x32 by modifying my Arduino code)

- Note: The LED panel comes with a 16pin ribbon cable and a power cable.

- You also need to download two Arduino libraries for the LED panel, found here.

(x1) breadboard

(x1) mono audio jack

(x3) 2.1mm barrel connectors (female; one for the LED panel, two for the amplifier circuit)

(x2) 9v source (wall wart or battery; can also daisy chain on a single wall wart)

(x1) 5v source (for LED panel)

(x1) 3PDT switch

(x1) 5mm T-1 3/4 LED (this is an on/off indicator)

(x1) TL072 op amp

(x1) 10kOhm potentiometer

(x1) 1kOhm 1/4w resistor

(x1) 1kOhm 1/4w resistor

Additional Materials:

(x1) USB cable (A -> B; male -> male)

(x?) jumper wires

Optional materials:

(x1) Enclosure (I used a BB-sized guitar pedal enclosure from Small Bear Electronics)

(x1) Knob

Step 1: Prepare the Hardware

First, you need to get out your soldering iron and connect some hookup wire to the hardware.

Wire the hot and ground wires to the 2.1mm barrel connectors, making sure to observe proper polarity for your power supply. I had a bunch of guitar pedal power supplies lying around, so mine are center-negative. Be aware, most 9v power supplies are center positive! Next, wire the hot of one barrel connector and the ground of the other to the 3PDT switch as shown in the images. Check your work by testing for continuity when the switch is in each position.

Next, wire the 10kOhm pot as shown in the image, then wire up the mono audio jack. I'm working with a guitar, so mine is a standard 1/4" audio but keep in mind the same principle holds for whatever connection your mono audio source uses.

Step 2: Assemble the Amplifier Circuit

Now we're going to build the circuit on a breadboard. I've modified the non-inverting amplifier section of the circuit from this instructable for this purpose. Check it out if you want, but I'm only going up to Step 3 of that instructable. From there, our paths diverge. They go on to build a DC offset, which is unneeded in this build.

If you're new to electronics, this is a great time to start the practice of color-coding your wires. It will really get messy if you don't!

Start by putting together the connections around the op amp and the on/off LED indicator. I used a TL072 for the op amp, but a TL082/TL071/TL081 will also work). Make sure you get the polarity right on the LED. The long wire is positive.

Next, start connecting the hardware to the breadboard. I tried to take photos of this with one component at a time so it's easy for you to follow.

Finally, connect some longer jumper wires which will go to the Arduino. One wire will go to an analog pin (mine is green). Next, a wire from the virtual ground will go to a ground pin on the Arduino, and the +9v power rail will connect to Vin on the Arduino. Don't actually connect these to the Arduino yet, because it's easier to do after the LED board is connected.

Step 3: Connect the LED Panel to the Arduino

Now we're going to work on connecting the light show to the Arduino through the ribbon cable included with the LED panel. You can find detailed instructions on how to do this here. Go slowly, one pin at a time and if you color-code nothing else, at least color-code the grounds. Adafruit shows you how to connect the ribbon cable to the LED board here.

Next, we're going to power the LED panel. There are many ways of doing this, but note two things. First, the LED panel CANNOT get more than 5v under any circumstances! Second, it may be tempting to try powering the LED panel from the Arduino, but it won't work. The Arduino can only supply up to 1A of current, and the LED panel can easily require more than that (Adafruit says its max draw is 2A). So, connect your power supply (whatever that may be) to the LED panel's power cable. I had a spare 5v wall wart, so I simply soldered the third 2.1mm barrel connector to the power cable.

Step 4: Connect the Amplifier to the Arduino

Remember those three wires hanging off your breadboard? Connect those to the Arduino now. Green goes to an analog pin, red goes to Vin, and black goes to ground.

As an optional step, you can put your assembly in some kind of an enclosure. I got a guitar pedal enclosure from Small Bear Electronics for pretty cheap.

Step 5: Upload the Sketch to the Arduino and Start Playing!

You're almost ready to put on a light show!

Download the Adafruit Arduino libraries to drive the LED panel.

Download my code (or copy it below) and open it in the Arduino IDE. If you don't have the IDE, you can find it here. If you don't know how to use it... it doesn't matter because I wrote code for you! I've commented it pretty thoroughly, so hopefully it'll be easy to understand if you want to make modifications.

/* Author: William Roberts - 07/29/16
 *  
 *  This sketch reads the voltage from an electric audio source
 *  and uses it to control an Adafruit 32x16 RGB LED matrix
 *  panel.
 *  
 *  Note: Some libraries are required for the LED matrix. You can find them here:
 *      https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/downloads
 */

#include <Adafruit_GFX.h>   // Core graphics library
#include <RGBmatrixPanel.h> // Hardware-specific library

#define CLK 8  // MUST be on PORTB! (Use pin 11 on Arduino Mega)
#define LAT A3
#define OE  9
#define A   A0
#define B   A1
#define C   A2

RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);

// Panel dimensions
uint8_t height = 32;
uint8_t width = 16;     // Change if you are using the 32x32 panel.

uint8_t r;
uint8_t g;
uint8_t b;

int analogPin = 4;      // Input from audio source
int voltage = 0;

float factor = 0;
float peakFactor = 0;
int noiseThresh = 10;   // Adjust as needed. Any voltage below this value is ignored.
int maxVoltage = 1023;  
float decayFrac = 0.9;  // Adjust as needed. Sets the sensitivity of the display.
                        // Higher -> less sensitive. Values: 0 <= decayFrac <= 1.


void setup() {
  matrix.begin();
  Serial.begin(9600);
  r=0, g=0, b=0;
}



void loop() {
  
  while (true) {

    /* Here's how this part works:
     *  
     *  Every time the Arduino reads the voltage from the analog pin. It gets assigned 
     *  an integer value between 0 and 1023. Now, the Arduino samples that pin at 
     *  10,000Hz. That's way too fast to get a smooth, nice-looking light show from most 
     *  audio sources (a piano's frequency range is 27.5Hz - 4,186Hz).  So the sampling 
     *  rate needs to appear slower than it really is.
     *  
     *  That's what the variable 'decayFrac' is for. When the Arduino reads a signal, 
     *  it retains that reading and compares it to the next voltage it reads. If the new
     *  voltage is lower, it multiplies the old one by the decay fraction and discards
     *  the new reading. It keeps multiplying the old signal by the decay fraction until
     *  it reads a voltage higher than the decayed signal. This happens at 10kHz, so it 
     *  looks pretty smooth with decay fractions even as high as 0.99. A good starting 
     *  value is 0.9, and I wouldn't go lower than 0.7 or so.
     *  
     *  Variables:
     *    factor        ->  the current voltage reading (normalized)
     *    peakFactor    ->  the decayed voltage reading (normalized)
     *  
     */
    voltage = analogRead(analogPin);
    //Serial.println(voltage);

    if (voltage < noiseThresh) {

      // Anthing below the noise threshold gets ignored
      
      voltage = 0;
      factor = peakFactor * decayFrac;
      peakFactor = factor;
      
    } else {

      // Normalize the voltage reading
      factor = (float) voltage / maxVoltage;
      
      if (factor > peakFactor) {

        // Keep the new reading if it's higher than the decayed signal
        peakFactor = factor;
        
      } else {

        // Decay the old signal
        factor = peakFactor * decayFrac;
        peakFactor = factor;
      }
      //Serial.println(voltage);  
    }
    
    drawPanel(r, g, b);
  }
}



void drawPanel(uint8_t r, uint8_t g, uint8_t b) {
  
  for (uint8_t row=0; row < height; row++) { 
    
    /* The variable 'mult' scales the color on each row of the LED display according the
     *  current row number, 'y'. So the bottom rows are always blue, and the top rows 
     *  progress from green to red as you play louder. There is a smooth color 
     *  transition from top to bottom.
     */

     /* I've scaled the RGB color transition like this:
      *  
      *   7 |\                   / \                   /
      *     |  \               /     \               /
      *     |    \ B       G /         \ G         / R
      *     |      \       /             \       /
      *     |        \   /                 \   /
      *     |          X                     X
      *     |        /   \                 /   \
      *     |      /       \             /       \
      *     |  G /           \ B       / R         \ G
      *     |  /               \     /               \
      *     |/________R=0________\|/________B=0________\_
      *    0                     0.5                   1.0
      *                          Mult
      */
     
    float mult = 2 * factor * ((float)row / (float)height);
    
    /*Serial.print(factor);
    Serial.print(" ");
    Serial.print(mult);
    Serial.print(" ");
    Serial.println(x);*/
    
    if (mult == 0) {
      r = 0;
      g = 0;
      b = 7; 
    }
    
    if (0 < mult && mult < 0.42) {
      r = 0;
      g = (uint8_t) 7*(2*mult - 1);
      b = (uint8_t) 7 - 7*(2*mult - 1);
    }

    if (0.42 <= mult && mult < 0.58) {
      r = 0;
      g = 7;
      b = 0;
    }
    
    if (0.58 <= mult && mult <= 1) {
      r = (uint8_t) 7*(2*mult - 1);
      g = (uint8_t) 7 - 7*(2*mult - 1);
      b = 0;
    }

    if (mult > 1) {
      r = 7;
      g = 0;
      b = 0;
    }
         
    for (uint8_t col=0; col < width; col++) {  
      matrix.drawPixel(row, col, matrix.Color333(r, g, b));
    }
  }
}

One final note: The potentiometer controls the gain of your audio signal. When you turn on the circuit for the first time, have the potentiometer turned all the way to the right. Then start slowly increasing the gain until you're loudest note starts to clip. You can see the clipping on the LED panel. When playing louder no longer makes any noticeable change on the LED panel, back off the gain a little bit. You've amplified the signal as much as the circuit can handle.

Have fun! Let me know if you have any questions or comments.