Manipulating Perceived Position of Sound in Space with an Arduino
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… 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, 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.
The code is in my previous post, 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.
Comment by george — September 3, 2008 at 11:05
Hey, this sounds really cool. I remember reading about a radar based system that used a similar output scheme to depict object’s locations and closure rates. I don’t have a compass module, but I am interested in experimenting with this output mode, like you suggest maybe with a pot, just to get the hang of how this works. could you repost with all the compass code commented out or deleted and a few comment lines to help others see how to implement? Also, are you running the output to a lm386 or other typical audio amp chip over there on the right side of the breadboard? You never mentioned your interface to the headphones. BTW, compliments on your clean and tidy prototype and pictures.
Comment by Penny — September 4, 2008 at 6:01
Your newest obsession, Mathieu?
Hope things are going well!
Comment by Mathieu — September 9, 2008 at 8:01
Hi George, hi Penny!
Yes, definitely an obsession, altho I’ve been going cold turkey for a week while on vacation…
I’ll rework the code into something without the sensor-related stuff, that’s a good idea. I’ll post it here and on the forum.
As for the audio ouput, all I did was bias the signal, filter out the worst of the click from the square waves and voltage-divide it down to 1V peak to peak to avoid blowing out the headphones. No need for an amp.
I’ll post a schematic of the output stage here and on the forum.