Saturday, August 25, 2012

All Together Now!

My last big step was to combine my signal conditioning circuit, my audio capture functions, and my DSP functions and get them to play nicely together.  This was very, very surprisingly easy.  I expected to spend days, possibly weeks debugging the integrated code, but surprisingly, that never happened.

First, I grabbed an audio splitter from Fry's so I could hear the signal going into my conditioning circuit via my headphones.  Next, I modified the main loop of the project that was running my audio capture code to include a signal processing function.  This function would check to see if the uDMA interrupt had set the "data ready" flag, and if so, process the data using the method described in my last post, then update my debug UART to display the frequency range of the current peak.

Once this was compiled and running, I used a java based web applet (found at http://web.mit.edu/jorloff/www/beats/beats.html ) to play a sine wave at a frequency I could specify.  Much to my amazement, my integration required very little debugging, and in about an hour's time, I was able to see my code properly responding to signals ranging from 40 Hz to 20 kHz.  Next, I found a youtube video that contained a frequency sweep, and verified that as the pitch got higher, the observed peak increased as well.  Success!

The remainder of the necessary code was pretty easy.  The shift registers on the Olimex booster pack communicated over SPI, and a coworker of mine already had code running on that board to display an arbitrary character array (each array element is a column, each bit of the char is the row).  I copied his code into my project with some minor modifications, and got it working without much issue.

The final hurdle was figuring out what data should go into the display matrix.  My previous audio experience was extensive enough for me to realize that the frequency should be displayed on a logarithmic scale.  I wrote another program in C to calculate which fft frequency bins would correspond to which LED based on the minimum and maximum display frequency, then stored these frequency breakpoints in a static array.  I then used the statistics portion of the CMSIS DSP library to find the average power in each LED range.

I modified my debug UART to keep track of the maximum magnitude I observed for a frequency bin when running the frequency sweep youtube video, and used that to determine what the maximum "loudness" value would be.  I figured I'd display power on a logarithmic scale as well, so I calculated power breakpoints using the value I observed when no audio was being played as the minimum power to display, and the maximum loudness value as the maximum power to display.  This gave me an array of power breakpoints.  So each time I went through my signal processing loop, I compared the average power observed in each LED range to these power breakpoints, and updated the display array based on that value.

The result was a far cry from ideal, but it was good enough to get me very excited.  My LED array flickered,  the middle and high bands didn't look like they were responding right, but I was able to play a random song and see the lower frequency LEDs light up whenever the kick drum or bass guitar hit.  It wasn't good enough to show off yet, but it was certainly good enough for me to call it a finished proof of concept.

No comments:

Post a Comment