How to: Apply Basic 3D Positional Effects to a Cue

This example demonstrates how to apply 3D positioning effects to cues.

The XNA Framework audio system contains support for 3D audio positioning effects, using the AudioEmitter and AudioListener classes, and the Cue.Apply3D method. The effects simulate 3D positioning for sound by adjusting speaker mix for cues that use the 3D values.

Note that speaker mix is the only effect that will be automatically applied using this method; attenuation and Doppler-shift pitch modification effects must be applied via creation of runtime parameter controls (RPCs) in the Microsoft Cross-Platform Audio Creation Tool (XACT). See Apply3D for more information.

To apply basic 3D positional effects to a cue

  1. Create an XACT project and add it to a new XNA Game Studio Express project as described in How to: Add a Sound File to Your Game Using XACT. The project should contain at least one cue.
  2. In code, create an AudioEngine, WaveBank, and SoundBank at game start.
  3. Create an AudioEmitter, an AudioListener, and a Vector3 to store the 3D position of the sound entity.
  4. In the Game.Initialize method, load the AudioEngine, WaveBank, and SoundBank. Then, call SoundBank.GetCue to retrieve the Cue you want to play in 3D.
  5. Call Cue.Apply3D on the cue you retrieved in step 4.
  6. Call Cue.Play to begin playback of the cue. Note that you must have called Apply3D on the cue first; otherwise, the next call to Apply3D will throw an exception.
  7. During game update, call the Update method of the AudioEngine to allow the audio engine to process audio data.
  8. Set the Vector3 to the position you want the sound to come from. Set the AudioEmitter.Position property to this vector.
  9. Optionally, set the Vector3 to the position where you want the listener of the 3D sound to be. Set the AudioListener.Position property to this vector.
  10. Call Cue.Apply3D on the cue object you retrieved and played in step 4, passing in the AudioEmitter, an AudioListener.

Note

Calling the Cue.Apply3D method automatically sets the speaker mix for any sound played by this cue to a value calculated by the difference in Position values between listener and emitter. In preparation for the mix, the sound is converted to monoaural. Any stereo information in the sound is discarded.

The following example uses a circular rotation around a stationary AudioListener to emphasize the 3D effect.

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        ContentManager content;

        //Standard audio objects
        AudioEngine engine;
        SoundBank soundBank;
        WaveBank waveBank;

        //Cue to play in 3D
        Cue cue3d;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);
        }
        //3D audio objects
        AudioEmitter emitter = new AudioEmitter();
        AudioListener listener = new AudioListener();
        Vector3 entityPosition;

        protected override void Initialize()
        {
            base.Initialize();

            //Initialize audio objects
            engine = new AudioEngine("Content\\Audio\\3DAudio.xgs");
            soundBank = new SoundBank(engine, "Content\\Audio\\Sound Bank.xsb");
            waveBank = new WaveBank(engine, "Content\\Audio\\Wave Bank.xwb");

            //Can only apply 3d to GetCue, not PlayCue
            cue3d = soundBank.GetCue("cue3d");

            //Must call Apply3D before calling Play
            cue3d.Apply3D(listener, emitter);
            cue3d.Play();
        }
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
            }
        }

        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent)
            {
                content.Unload();
            }
        }
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            //Move the emitter around in a 2d circle
            entityPosition.Z = (float)Math.Sin(gameTime.TotalGameTime.Seconds);
            entityPosition.X = (float)Math.Cos(gameTime.TotalGameTime.Seconds);

            emitter.Position = entityPosition;

            //Now apply the settings to the cue
            cue3d.Apply3D(listener, emitter);

            engine.Update();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);
        }
    }