Playing with Music and Lights

Yesterday I was experimenting with my Music and Lights system and trying out different algorithms to sync lights to Music. For this purpose I had integrated a ATmega328p microcontroller (MCU) when I designed the Music and Lights PCB.

Three of the MCU analog input pins are connected to the outputs of the bass, mid and treble filters. This allows the MCU to read the bass, mid and treble levels of the audio signal at any instance of time. The MCU can then process the inputs and drive the RGB strip according to a pre-programmed algorithm.

To program the MCU in-system, I have included a 5-pin header on the PCB, which connects to the respective programming pins of the MCU.  If you want to know the details this is a good tutorial that explains how to upload a program to a stand-alone ATmega328p.

The ATmega328p on board the Music and Lights PCB can be programmed via the 5-pin programming header, which connects to an Arduino board

The ATmega328p on board the Music and Lights PCB can be programmed via the 5-pin programming header, which connects to an Arduino board

Calibrating the bass, mid and treble filter outputs

Before experimenting with algorithms, I calibrated the bass, mid and treble filters to the same level. There are three pots on the PCB that can be used to adjust the input audio level to the three filters. The filters are of type multiple feedback active bandpass filter, which has a very narrow pass band. The center frequencies are 224 Hz, 1057 Hz and 3202 Hz for bass, mid and treble respectively. Please read my previous post if you want to know how these types of filters are constructed.

I used this handy online tone generator tool to generate an audio signal with the center frequency for each of the filters. Then with the pots turned to maximum input signal, I read the output value of each of the filters using the RGB strip with the number of lit LEDs proportional to the signal level. The number of lit LEDs was 15, 13 and 11 for bass, mid and treble filters respectively. Since the treble filter had the smallest output signal level I adjusted the pots for the bass and mid filters to the level of the treble filter.

Now with all the filters calibrated, I set out to experiment! So far I came up with three algorithms that I liked. Let’s see them in action first and then I’ll explain the algorithms.

Algorithm 1

This algorithm is very similar to the one I had originally, but with only three colours instead of the full RGB spectrum. The audio levels are sampled every 50 ms. It then compares the bass, mid and treble levels and selects the LED colour depending on the largest value; Red if bass, green if mid or blue if treble. The number of LEDs lit is proportional to the signal level.

I like this better than having the full RGB spectrum since it is easy to see whether the bass, mid or the treble is the largest.

Algorithm 2

Very similar to Algorithm 1 except the zeroth LED is at the center of the strip. The bass level is indicated on the right side (red) while the treble level is indicated on the left side (blue). The mid level is indicated on the center (green). Again the sample rate is set to 50 ms, and for each sample only the largest level is displayed.

Algorithm 3

This one is my favourite so far. It is more smoother and eye pleasing than the previous two. To make this happen I created two virtual shift registers of size 16 bits (or an int) each; one for the LEDs on the right side of the strip and the other for the LEDs on the left side of the strip. The bits in the shift registers determine whether a particular LED is supposed to be on or off in each cycle.

How this works is better explained with the actual code, and here it is

 Algorithm3

These are a few examples that showcase the capabilities of the Music and Lights system. My idea with this project is to develop a system that can sync lights to music in real time, but one that performs better than a simple light organ.  I will continue to experiment  and improve it with new and more complex algorithms until I run out of memory of the MCU, and an upgrade becomes necessary.

Thanks for reading!

Music and Lights – RGB strip driver

First of all, I made some changes to my project objectives. The music and lights system I am building will not be attached to my bicycle. This is because I don’t think it will be used that often if it is just on my bicycle. So instead I am gonna set it up on my room, so that I can make the most out of it.

So far I have build an amplifier for the speakers and a triple channel audio filter for the lights (see previous posts). The next step is to read the output values of the triple channel audio filter and drive the TM1809 RGB strip to represent those values. For this I am using an Arduino. I have several Arduino boards hanging around and they are great for when you need to write a simple program to read sensor data and do something with it. Also there is a fantastic library for Arduino called FastLED that makes driving LED strips a breeze.

So I wrote a simple program to read the output values of the triple channel filter and drive the RGB strip with the red, green and blue values representing bass, mid and treble levels.

/**
   RGBdriver.ino
   Purpose: Read three analog values and drive a TM1809 RGB strip with the red,
   green and blue levels representing the analog values. 

   @author Kasun Somaratne
   @version 1 06/07/14
 */

#include <stdio.h>
#include <FastLED.h>

#define NUM_LEDS      30
#define DATA_PIN       7
#define BASS_PIN      A0
#define MID_PIN       A1
#define TREBLE_PIN    A2

//create an array of RGB values for the number of leds on the strip.
CRGB leds[NUM_LEDS];

void setup()
{
  //Specify the led strip type and the data pin used to send data to the led strip
  FastLED.addLeds<TM1809, DATA_PIN>(leds, NUM_LEDS);

  //Initially turn all leds off
  for(int i = 0; i < sizeof(CRGB); i++)
  {
     leds[i] = CRGB(0,0,0);
  }
  FastLED.show();
}

void loop()
{
  // read the bass, mid and treble values. These values will be between 0-1023.
  int bass = analogRead(BASS_PIN);
  int mid = analogRead(MID_PIN);
  int treble = analogRead(TREBLE_PIN);

  //calculate the number of LEDs to be lit using the bass value
  int litLEDCount = map(bass, 0, 1023, 0, NUM_LEDS);

  //map the bass, mid and treble values to red, green and blue values. The rgb values can only be from 0-255
  int rVal = map(bass, 0, 1023, 0, 255);
  int gVal = map(mid, 0, 1023, 0, 255);
  int bVal = map(treble, 0, 1023, 0, 255);

  //turn off all the LEDs on the array
  FastLED.clear();
  //update the LED strip with calculated red, green and blue values
  for(int i = 0; i < litLEDCount; i++)
  {
    leds[i] = CRGB(bVal,rVal,gVal);
  }
  //display the LEDs
  FastLED.show();

  delay(50);
}

Finally, It is time to test the entire setup. Here’s a short video showing how it looks at the moment:

Not bad for the first try, right? However, it has several issues:

  1. There is a high frequency noise that seems to be proportional to how many LEDs are lit on the strip.
  2. There is a low frequency noise (~25Hz) whenever the Arduino board is connected to the system.

Next step is to identify the sources of these noises and eliminate them. But so far I am satisfied with the progress.