Demonstrates how to apply attenuation and Doppler 3D positioning effects in code.
Introduction
This topic builds on How To: Apply Basic 3D Positional Effects to a Cue, which discusses the steps required to add 3D audio to your game. This topic introduces concepts such as XACT projects, the audio engine, cues, and emitter and listener positions.
3D game audio typically implements at least three effects: speaker positioning, volume attenuation over distance, and Doppler pitch shifting. The basic 3D audio how-to discusses speaker positioning. This topic explains how to add attenuation and Doppler effects to 3D audio.
At design time, the sound designer defines the attenuation and Doppler effects and applies them to specific sounds. The designer uses XACT Runtime Parameter Controls (RPC) to specify the relationships between game information, exposed as XACT variables, and resulting sound effects. To determine final attentuation and Doppler effects at run time, the XACT engine combines the designer’s effects with calculations based on position and velocity of the audio source and listener.
Sound designers can add attenuation without requiring any additional code changes by the developer (assuming that the game already sets the emitter and listener positions). However, Doppler effect requires that XACT know the velocity of the emitter and listener. Therefore, the game must set the AudioEmitter.Velocity and AudioListener.Velocity properties.
The Complete Sample
The code in the topic shows you the technique. You can download a complete code sample for this topic, including full source code and any additional supporting files required by the sample.
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace Advanced3DAudio { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; // Audio objects AudioEngine engine; SoundBank soundBank; WaveBank waveBank; // 3D audio objects AudioEmitter emitter = new AudioEmitter(); AudioListener listener = new AudioListener(); Cue cue; float maxEmitterDistance = 150.0f; float maxVelocity = 30.0f; public Game1() { graphics = new GraphicsDeviceManager(this); } protected override void Initialize() { base.Initialize(); // Initialize audio objects. engine = new AudioEngine("Content\\Audio\\Advanced3DAudio.xgs"); soundBank = new SoundBank(engine, "Content\\Audio\\Sound Bank.xsb"); waveBank = new WaveBank(engine, "Content\\Audio\\Wave Bank.xwb"); // Set emitter and listener position. emitter.Position = Vector3.Backward; listener.Position = Vector3.Zero; // Get the cue and play it. // For 3D cues, you must call Apply3D before calling Play. cue = soundBank.GetCue("buzz"); cue.Apply3D(listener, emitter); cue.Play(); } protected override void LoadContent() { } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { // Allow the game to exit. if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState. Pressed) this.Exit(); // Move the sound left and right out to maximum distance. emitter.Position = new Vector3( (float)Math.Cos(gameTime.TotalGameTime.TotalSeconds / 5.0f) * maxEmitterDistance, 0.0f, 1.0f); // Add velocity with left or right triggers. emitter.Velocity = new Vector3(maxVelocity * GamePad.GetState(PlayerIndex.One).Triggers.Left, 0.0f, 0.0f); listener.Velocity = new Vector3(-maxVelocity * GamePad.GetState(PlayerIndex.One).Triggers.Right, 0.0f, 0.0f); // Apply 3D settings to the cue. cue.Apply3D(listener, emitter); // Update the audio engine. engine.Update(); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); } } }