The code for the Music Box is available on github.
1 - LED control
There are 12 RGB LEDs that can each be set individually using 3 16-channel PWM drivers. This means that 36 of the 48 channels are wired directly to the LEDs, and each controls the brightness of a single color of a single LED. I've used TLC5940 drivers for this project, which basically act as shift registers. The output value of each channel is set by an internal 12-bit register that is filled by shifting values through each channel register sequentially. The drivers are daisy-chained together so that only one long string of bits needs to be shifted out to set the value for every LED.
The brightness of an LED is logarithmically related to the current running through it. This means that the increase in brightness per increase in PWM value actually decreases as you move up in value. While you may think this only matters if you plan on linearly dimming LEDs back and forth, it actually has a profound effect on color mixing. With only a narrow range of PWM values that cause an LED to appear dimmed, linearly sliding through PWM values will cause each color of an RGB LED to mostly appear on or off. Without correcting for this logarithmic response, sliding through hue on an RGB LED will look more like cycling through the primary and secondary colors (red-yellow-green-cyan-blue-magenta-) with little mixing in between.
To correct for this, I used a pre-computed 12-bit look-up table for each value in [0-255] that would approximately linearize the brightness. While I could only set the color values with 8 bits per channel, the output to the PWM drivers was 12 bit to maintain precision at the low end of the look-up table.
There are a few inputs on the drivers that need to be toggled while shifting data in, but this is well documented elsewhere.The only tricky part is getting the overall PWM frequency right. The grayscale clock (GSCLK) pin needs to be toggled 4096 times to complete one pulse cycle in our PWM setup. In order to have LEDs appear continuously on, the pulse frequency needs to be at least 60Hz or so. This means the GSCLK line needs to be toggled at 4096*60Hz = 246kHz or higher.
When the music box is powered up, it begins by testing the LEDs and drivers by displaying a simple pattern. Then it jumps into Ambient Mode, where the value of each LED is set based on some simple math.
The pattern cycles itself randomly forever, creating an endless sequence of new color patterns. After letting the music box sit around in ambient mode for a few hours, I've decided I should really make more of these. Someday..
2 - Sound Reactive
To react to music, first the software must be able to react to what the microphone picks up. The microphone is hooked up to one of the analog input pins of the Teensy3, so I just need an analogRead() to grab the current state. In order to sample at a constant rate, I used an interrupt that would force the code to take a microphone measurement every few microseconds. After a measurement is made in the software interrupt, the sound reactive algorithms perform some incremental calculations to update the frequency-dependent output.
Since the microphone-sampling interrupt occurs every few microseconds (~350us), any computing that is done using a new microphone reading needs to complete in a very small amount of time.
The following video shows the Party Mode. Six different frequency bins are updated as the microphone samples come in and the amplitude of these bins are displayed on the LED circle. This mode acts as a simple graphic equalizer.
I'm not 100% happy with how it acts, but I think it's a great start.
The final mode is Tuner Mode, which keeps track of 36 different frequency bins that are spaced much closer in frequency. This is the mode I originally designed the music box to run, and much of the math and theory for it was covered in my last post. Unfortunately this mode is also the least impressive right now, so I don't have a video at this point. I think it needs some careful adjustments in the code and possibly some circuit modifications to deal with electromagnetic interference (EMI) produced by the LED drivers. If I can get it working satisfactorily, I will update with a third video!