# How to offer directional ambient audio

I'm working on a game side-project that will be heavily audio-based. One feature I'd like to offer are ambient sound zones which correspond to locations of nearby areas.

Say for instance the player is standing on a beach with waves breaking to the right, and a rainforest to the left. Each of these regions has its distinct ambience. If you continue forward, the breaking waves should still be just as loud on your right. Similarly, if you head into the forest, the sound of the waves should slowly be replaced as you move away from the beach. Many games seem to treat ambient sound as either vaguely positional, or as an environmental sound that comes from everywhere at once. What I'm trying for are different areas with different distinct sounds so you can actually orient yourself to them (I.e. you should be able to return to the beach by listening for the breaking waves, they shouldn't just be omnidirectional and faint.)

I don't want to get too deep into architecture, but my system is simple 2-D tile-based. I've thought of several possible approaches and am wondering a) which is best or b) if I've missed one that is better.

• Place distinct, loud ambient sounds in specific locations. This would certainly provide directionality of a sort, but I wonder if the ocean waves might eventually sound ahead or behind and right as you walk down the beach, since all the ambience is coming from a single point. This also wouldn't allow for, say, walking out in the ocean past the breakers and hearing them behind you.
• Placing sound sources throughout the area, spaced a reasonable distance apart. So for instance the breakers might be a single row of wave sounds which you could walk along or past. Similarly, the forest would be a grid of scattered nature sounds. This seems like the best approach, but I wonder if I'd quickly hit some limit for number of sounds that can be mixed. I'm using the web audio API, not sure if that intelligently doesn't render sounds that are too soft to hear. While this seems conceptually simpler, a long beach might have hundreds of distinct sound nodes placed along it.
• Track the player's nearest intersection with a given zone, and play its ambience at those coordinates. So if you're walking along a beach with breaking waves to your right, I'd project out an invisible circle for as far as you can realistically hear, identify the closest intersection with various audio zones, and play their respective ambience. Maybe limit this to the nearest 2-3, since any more would likely be overwhelming. This seems least demanding in that it'd play fewer sounds, but would likely require more collision checks and thus might be impractical.

Thoughts?

• When your game is "simple 2-D tile-based", I assume that the view is not rotating but stays oriented north? In that case don't forget that the players ears can tell the difference between east and west, but not between north and south. – Philipp Apr 24 '15 at 9:39

I'm doing something not entirely dissimilar in my own game (though I don't care about the directionality as such). The approach I've taken is similar to what you say about placing sound sources throughout the area, however with the difference that I don't let each of them be its own actual sound source, but rather just let them contribute volume to an environmental sound, to put it concisely.

Basically, what I'm doing is that, each cycle, I iterate through the various sound sources in the scene and intern all the sources that are "the same sound". So for a given scene, I might find 25 sources that are wind over an open area, 37 that are forest sounds and 5 that are flowing water from the river running through the area. I check the distance of each of the sources from the player and add together their contributing sound volumes, and might then find that I'll be playing open-area wind at 33% of its maximum volume, forest sounds at 50% of its maximum volume and flowing water at 80% (since the player is right next to the river). In the end, I'm just playing 3 sounds, but adapted in volume to the contributions of several sound sources.

I figure it wouldn't be too hard to adapt this method to directional sound -- you should be able to just sum the contributing sound volumes per speaker.

This is a bit late but may help others.

Your ideas are basically sound. Place sound emitters along the ocean edge with reasonable spacing for your needs. If the player can move vertically then you need to place them as a wall rather than a straight line. Limit the number of instances of this type of sound that the player can hear at a time. Select the emitters based on volume. Calculate the volume using the distance to an emitter using whatever falloff formula you like; plain linear should be fine. You set the distance that the volume starts to fade and the distance you hear nothing. You play the n loudest. Any sound engine can do this.

However, if you're rolling your own then there's a simple formula. You have a table of speaker angles for each set of speaker setups you will support for output. If it's headphones, the angles are 90 and 270. The standards for the angles of 5.1 and 7.1 can be found on the web.

For each emitter, calculate it's angle and figure out what speakers it's between and how far. If the sound is at 75° and speakers are 30 and 120 then it's 50% of the way from speaker A to speaker B. You should have a number that is between 0.0 and 1.0. Multiply this by pi/2. This coverts it to an angle between 0 and 90° in radians. Speaker A volume is the cosine of this value and speaker B is the sine of this value. Multiply these by the attenuation volume calculated from the emitter and those are the values you send to each speaker. For the 50% case the start values for each speaker should be 0.707 or you messed up. Many sound engines implement a spill over to adjust the feel but with multiple emitters it wouldn't matter.

So, use an off the shelf sound engine or:

/*
Get distance to emitter.
Within falloff range?
Get the volume V (0.0 to 1.0)
Do this for all emitters, keep the n loudest.

For each remaining emitter:
Get the angle to the emitter
Get the 2 speakers it's between (A & B)
Get the % (P) of how far your angle is from A to B (0.0 to 1.0)
Multiply P by pi/2
SpeakerA = V * cos(P)
SpeakerB = V * sin(P)
*/


If your platform takes something other than a value from 0 to 1 for channel volume you'll need to convert it.