Before I start, kudos and thanks to Narbotic and others for all the pioneering work on sound generation. I just noticed Narbotic's stereo beat generator: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1219732829... and I'll say right up front that I have not mastered advanced methods, so all I will be doing is bit-banging some low-frequency audio. Think of this as a proof of concept.
Oh, and apologies for my long-winded style. I undercomment my code and overcomment my prose.
I was playing around with Sparkfun's pricey HMC6343 tilt-compensated compass and after the obvious cylon LED array, needed another output method, so decided to play with a stereo beep that would seem to track a fixed azimuth as you rotated the board. Here's the hardware on a breadboard, and mark II on protoboard:
I shamelessly stole code left and right from the trailblazers and kludged together something that uses analogWrite() with a modified PWM frequency on pins 9 and 10 to generate low frequency bit-banged sound with independent volume control on right and left channels. It wasn't pretty, but it worked, after a fashion. Alas, as you panned the audio from side to side, the effect was not as crisp as would have liked in the middle range, so I decided to do some research.
After reading this: http://www.hitl.washington.edu/scivw/EVE/I.B.1.3DSoundSynthesis.html I tried to add some delay between the two audio 'tracks'. It works out that the delay is never greater than about 650us, so if you pick your beep's frequency low enough, the delay can be contained inside a single cycle of your audio frequency, which is rather handy. Now I just needed to figure out how to vary the delay with the heading, and some high school geometry helped:
Turns out that the delay for stereo sound is proportional to sine of that heading (measured from dead ahead). The delay for an echo from a backstop (which I have not implemented yet) is proportional to the cosine of the same angle (with a different base value, unless the backstop is somewhere inside your skull).
So was all this trig and delayMicrosecond() worth the bother? And how!
The effect is so sharp, you can tell the difference between center, ten degrees left of center and ten degrees right of center. I was so surprised, I thought it might be due to wishful thinking, so I turned off the stereo volume adjustments... even with just the delay and no change in the volume between left and right, you can hear the sound move from side to side. What's even weirder is that if you listen to just one side, the sound stays the same.
With both volume and delay adjustments, the stereo sound effect is very noticeable, with a clear distinction around the center mark.
I'll try to post my code here in a reply, or I'll provide a link to it on my blog, but I'd appreciate it if someone tried my code out, perhaps with just a pot and analogRead() to pan left/right? Confirmation from someone else would be great.