Misadventures in microcontrollers.
I've spent my free time over the past couple of days hacking away on my current project-slash-obsession and thus I've been doing a lot of reading up on microcontrollers, or at least the basics of them. Knowing nothing about them as a technology or about sound synthesis for that matter, I find myself having to start from first principles, which are never as easy as they seem to grasp no matter how much experience you have under your belt. I'm trying to design a synthesizer coming at it as a code jockey as well as a musician (or one-time musician, anyway). An A note in the fifth octave is 440 Hz, so you just push the value into a register, set a conditional that runs a few thousand times per second (at today's clock speeds that takes no effort at all) and play if a variable has a value, don't play if it doesn't. Sounds simple, right?
It's not. Playing nifty sounds is something that we take for granted but under the hood there's a lot of math and extra circuitry involved. That's why sound cards hitting the market in the early 90's were so amazing. When you hook a simple piezo speaker up with a pair of wires to a pin on a microprocessor and toggle that pin a few thousand times a second you can create sound with a method called pulse-width modulation, but that will make only one sound at a time. If it's polyphony you want you're going to need more oscillators, and in fact more hardware because PWM requires that the amount of time the pin is 'on' and the amount of time the pin is 'off' be precisely modulated because each note has a different combination of those two variables. You can't stack more than one sound if you're using PWM on a single microprocessor.
Not long after I decided to start working on this, I had the crazy idea of using a SIDuino, a microcontroller programmed to emulate a SID chip to perform the actual sound synthesis in this project. While I'm not yet ready to do anything of the sort I figured that I'd get an ATmega168 ready last night while I was at HacDC by flashing the code, labeling the chip, and putting it aside so it'd be ready when I needed it. So, I swapped the chips in my Arduino, plugged it into Windbringer, and followed the instructions for uploading the code into the 168. And bricked the damned thing doing it.
One of the bits of magick about the Atmega microcontrollers are the fuses, bits in flash memory that control specific functions of the device. Very touchy and low-level functions of the device, such as whether or not to allow new code to be flashed over serial, turning the internal watchdog timer (which detects lockups) on or off, or whether the chip will use its internal or an external clock source to run, like a crystal. The first step in the instructions for flashing the SIDuino code is to disable the internal clock. When I ran the fuse-setting avrdude command it not only disabled the internal clock but made it impossible to flash the binary code into the microcontroller's storage. In fact, it rendered the ATmega unable to do anything other than generate a little waste heat when power was applied. Whoops.
It was Eliott who figured out how to reverse what I'd done. After consulting the AVR fuse value calculator we figured out what values the ATmega168 should have by default, wrote a couple of lines of code that toggled a pin on one of his spare ATmegas as fast as it could go (about eight million times per second), and used that as the clock source for my hosed 168. We then fiddled with avrdude a little to re-set the fuse values to default (for the record, those values are 0x62 0xDF 0xF9), and flashed the code successfully, or apparently so. I'll know for sure when I actually try to use the bloody thing.
After hacking around at the 'space until 0100 EST5EDT last night I think this is going to be a harder project than originally expected. Without a perfect understanding of the principles involved, all of the schematics that I've been scribbling on every flat surface that I can fold up and carry with me are probably useless. Microcontrollers have a limited number of pins, or channels of input and/or output (some pins can be set to act as either inputs or outputs while others can only do one thing). I'm going to need five inputs for the strings/lasers and more than that for the frets (depending on how I choose to go about it). Consequently I can't really spare five pins for output (one for each string/laser), which is the chief reason for not going the PWM route of sound synthesis. What I could do is code a bunch of tables that represent distinct waveforms, one per note, and have the Arduino do a lookup whenever a laser is broken/string is sounded. Each time through the loop, see which strings are still sounding, add the values from the lookup table together (because when mixing sounds you add them together and not, say, multiply or XOR them), and then output each bit of the resultant value to a different pin which is connected to a digital-to-analog converter, and thence to an internal amplifier and speaker or output jack. Or I could build my own D/AC with about $7us worth of components to see what would happen.
In other words, push the work of actually making a noise off of the microcontroller and onto a subsystem that specializes in doing so.
After talking it over with Eliott last night another way to go would be to get a bunch of simpler microcontrollers, like the ATmega8 or maybe PIC, all of which can be bought on the open market for a couple of cents each (Radio Shack rips you the hell off). Rig up one microcontroller per string: let's say by default it'll play a concert A in the fifth octave plus a little more depending on whether or not a particular fret is pressed for that string/laser. The output of each string gets combined into a single sound by tying the outputs together at the speaker or output jack. After all, that's how traditional string instruments work. Then I need to figure out how the frets are going to work; eight frets times five lasers means 40 buttons. To hook that many switches into a single microcontroller would require something like a keyboard controller or keypad encoder. To hook eight switches (or a single linear potentiometer) into a single microprocessor would be easier for implementing frets.
Or maybe I'll just go MIDI, which I know even less about right now. But that's way beyond where I am right now.
Anyway, at the moment all of this is academic. I've got a lot of experimentation to do before I know what direction to go in. I may as well get started.