The audio system in XNA makes it possible to reproduce sound effects and music in two different ways. First, we can play audio clips directly from audio files loaded at runtime, with support for the most common audio file formats. Second, we can use Microsoft’s Cross-Platform Audio Creation Tool, also known as XACT, which is more often used for complex games with many audio files. The first approach involves loading and managing audio objects in our own code. The second approach leaves the details largely up to classes provided for working with XACT resources built at compile time and then made available from a container of objects. I’m going to cover the audio system in the Microsoft.Xna.Framework.Audio
namespace in detail, followed by examples showing how to use the simple audio system and the full-blown XACT interface in XNA. These are the likely culprits in this lineup:
Microsoft.Xna.Framework.Audio
reference
Simple audio playback
Cross-Platform Audio Creation Tool (XACT)
The XNA audio system is found in the Microsoft.Xna.Framework.Audio
namespace, and the core class that we use to create audio objects is called AudioEngine
. For simple audio playback, we can use SoundEffect
and SoundEffectInstance
, but for a more comprehensive audio solution we need to look at the rest of the classes. This reference to the audio system will be useful as you consider building the audio component of your own games.
Because every class has common methods like Dispose
and Finalize
involved in object logistics, these common method names are intentionally left out of this reference in order to highlight the more relevant methods. This policy also applies to properties and methods derived from the base Object
class.
Following are the classes found within this namespace.
Represents a 3D audio emitter.
Public Properties | |
| Gets or sets a scalar applied to the level of Doppler effect calculated between this and any |
| Gets or sets the forward orientation vector for this emitter. |
| Gets or sets the position of this emitter. |
| Gets or sets the upward orientation vector for this emitter. |
| Gets or sets the velocity vector of this emitter. |
Represents the audio engine. Applications use the methods of the audio engine to instantiate and manipulate core audio objects.
Public Fields | |
| Specifies the current content version. |
Public Properties | |
| Gets a collection of audio renderers. |
Public Methods | |
| Gets an audio category. |
| Gets the value of a global variable. |
| Sets the value of a global variable. |
| Performs periodic work required by the audio engine. |
Represents a 3D audio listener. This object, used in combination with an AudioEmitter
, can simulate 3D audio effects for a given Cue
or SoundEffect-Instance
.
Public Properties | |
| Gets or sets the forward orientation vector for this listener. |
| Gets or sets the position of this listener. |
| Gets or sets the upward orientation vector for this listener. |
| Gets or sets the velocity vector of this listener. |
Defines methods for managing the playback of sounds. Cues are what programmers use to play sounds. Cues are typically played when certain game events occur, such as footsteps or gunshots. A cue is composed of one or more sounds, so when the cue is triggered, the set of associated sounds is heard. A sound specifies how one or more waves should be played. A sound also has specific properties such as volume and pitch. The sound designer can adjust these properties. The advantage to using the Audio API to reference cues rather than specific sounds is that an audio designer can reassign sounds to a cue in the sound bank without programmer intervention. For example, a sound designer can try various gunshot waves associated with a particular game event without requiring the programmer to change code or rename sounds. Cues and sounds are referenced through SoundBank
objects. The waves that compose a sound are referenced through WaveBank
objects.
Public Properties | |
| Returns whether the cue has been created. |
| Returns whether the cue is currently paused. |
| Returns whether the cue is playing. |
| Returns whether the cue is prepared to play. |
| Returns whether the cue is preparing to play. |
| Returns whether the cue is currently stopped. |
| Returns whether the cue is stopping playback. |
| Returns the friendly name of the cue. |
| Calculates the 3D audio values between an |
| Gets a cue-instance variable value based on its friendly name. |
| Pauses playback. |
| Requests playback of a prepared or preparing |
| Resumes playback of a paused |
| Sets the value of a cue-instance variable based on its friendly name. |
| Stops playback of a |
Provides properties, methods, and events for playback of the audio buffer.
Public Properties | |
| Indicates whether the audio playback of the |
| Returns the number of audio buffers in the queue awaiting playback. |
Public Methods | |
| Returns the sample duration based on the specified size of the audio buffer. |
| Returns the size of the audio buffer required to contain audio samples based on the specified duration. |
| Begins or resumes audio playback. |
| Submits an audio buffer for playback. |
The exception thrown when there is an attempt to concurrently play more than 16 SoundEffectInstance
sounds. All properties and methods are inherited from Exception
and ExternalException
.
Provides properties, methods, and fields and events for capturing audio data with microphones.
| Returns the friendly name of the microphone. |
Public Properties | |
| Returns the collection of all currently available microphones. |
| Gets or sets audio capture buffer duration of the microphone. |
| Returns the default attached microphone. |
| Determines if the microphone is a wired headset or a Bluetooth device. |
| Returns the sample rate at which the microphone is capturing audio data. |
| Returns the recording state of the |
Public Methods | |
| Gets the latest recorded data from the microphone. |
| Returns the duration of audio playback based on the size of the buffer. |
| Returns the size of the byte array required to hold the specified duration of audio for this microphone object. |
| Starts microphone audio capture. |
| Stops microphone audio capture. |
Public Events | |
| Event that occurs when the audio capture buffer is ready to be processed. |
The exception thrown when no audio hardware is present, or when audio hardware is installed but the device drivers for the audio hardware are not present or enabled. All properties and methods are inherited from Exception
and ExternalException
.
The exception thrown when Microphone API calls are made on a disconnected microphone. All properties and methods are inherited from Exception
.
Represents a sound bank, which is a collection of cues.
Public Properties | |
| Returns whether the sound bank is currently in use. |
Public Methods | |
| Gets a cue from the sound bank. |
| Plays a cue. |
Provides a loaded sound resource. A SoundEffect
contains the audio data and metadata (such as wave data and loop information) loaded from a sound file. You can create multiple SoundEffectInstance
objects and play them from a single SoundEffect
. These objects share the resources of that SoundEffect
. You can create a SoundEffect
by calling ContentManager.Load
. When you make that call, use the type SoundEffect
and the asset name of an audio file. The audio file must be part of the content project. Be sure to use the SoundEffect-
XNA Framework content processor. The only limit to the number of loaded Sound-Effect
objects is memory. A loaded SoundEffect
will continue to hold its memory resources throughout its lifetime. All SoundEffectInstance
objects created from a SoundEffect
share memory resources. When a SoundEffect
object is destroyed, all SoundEffectInstance
objects previously created by that SoundEffect
will stop playing and become invalid.
Public Properties | |
| Gets or sets a value that adjusts the effect of distance calculations on the sound (emitter). |
| Gets or sets a value that adjusts the effect of Doppler calculations on the sound (emitter). |
| Gets the duration of the |
| Gets or sets the master volume that affects all |
| Gets or sets the asset name of the |
| Returns the speed of sound: 343.5 meters per second. |
Public Methods | |
| Creates a new |
| Creates a |
| Returns the sample duration based on the specified sample size and sample rate. |
| Returns the size of the audio sample based on duration, sample rate, and audio channels. |
| Plays a sound. |
Provides a single playing, paused, or stopped instance of a SoundEffect
sound. You can create a SoundEffectInstance
by calling SoundEffect.CreateInstance
. Initially, the SoundEffectInstance
is created as stopped, but you can play it by calling Play
. You can modify the volume, panning, and pitch of the SoundEffectInstance
by setting the Volume
, Pitch
, and Pan
properties. On Windows, there is no hard limit, but playing too many instances can lead to performance degradation. On Xbox 360, the limit is 300 sound-effect instances loaded or playing at a time.
Public Properties | |
| Gets a value that indicates whether looping is enabled for the |
| Gets or sets the panning for the |
| Gets or sets the pitch adjustment for the |
| Gets the current state (playing, paused, or stopped) of the |
| Gets or sets the volume of the |
Public Methods | |
| Applies 3D position to the sound. |
| Pauses a |
| Plays or resumes a |
| Resumes playback for a |
| Stops playing a |
Following are the structures found within this namespace.
Represents a particular category of sounds.
Public Properties | |
| Specifies the friendly name of this category. |
Public Methods | |
| Pauses all sounds associated with this category. |
| Resumes all paused sounds associated with this category. |
| Sets the volume of all sounds associated with this category. |
| Stops all sounds associated with this category. |
Following are the enumerations found within this namespace.
Defines the number of channels in the audio data.
| Indicates audio data is contained in one channel. |
| Indicates audio data contains two channels. |
Controls how Cue
objects should stop when Stop
is called.
| Indicates the cue should stop normally, playing any release phase or transition specified in the content. |
| Indicates the cue should stop immediately, ignoring any release phase or transition specified in the content. |
Current state of the Microphone
audio capture (started or stopped).
| The |
| The |
There is one very easy way to get audio to play in an XNA project: by using the SoundEffect
class. There are some drawbacks to using SoundEffect
rather than XACT, however. These include the tendency for the content project to become cluttered with many asset files. Even so, the SoundEffect
class is convenient and easy to use for simple audio playback. (Refer to the reference information on this class earlier in this chapter.)
Before we can play an audio clip, we have to add it to the content system. Right-click Content in Solution Explorer, choose Add, then choose Existing Item, as shown in Figure 4.1. This opens the Add Existing File dialog box. Locate the audio file you want to add to the project.
The following audio file types can be added to an XNA project for use with the SoundEffect
class:
XAP
WAV
WMA
MP3
We can create an instance of the SoundEffect
class with a variable declared in the globals
section at the top of the class as follows:
SoundEffect heartBeat;
The SoundEffect
object is loaded in the LoadContent()
function:
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("Arial");
heartBeat = Content.Load<SoundEffect>("heartbeat");
}
The audio clip can be played back using the SoundEffect.Play()
method. There is a simple version of Play()
and an overloaded version, which gives us control over the Volume
, Pitch
, and Pan
properties. Here is an example:
protected override void Update(GameTime gameTime) { GamePadState gamepad = GamePad.GetState(PlayerIndex.One); KeyboardState keyboard = Keyboard.GetState(); //Escape or Back to end program if (gamepad.Buttons.Back == ButtonState.Pressed) this.Exit(); if (keyboard.IsKeyDown(Keys.Escape)) this.Exit(); //A button or key plays sound effect if (gamepad.Buttons.A == ButtonState.Pressed) heartBeat.Play(); if (Keyboard.GetState().IsKeyDown(Keys.A)) heartBeat.Play(); base.Update(gameTime); }
There is really only one useful property in the SoundEffect
class: Duration
. This property gives us the length of the audio clip in seconds. In the Draw()
function of our sample program (Simple Audio Demo), we can print out the length of the audio clip, as shown in Listing 4.1. In fact, this class is not very helpful at all. What we need is a class with more functionality. Figure 4.2 shows the program running.
Example 4.1. Simple Audio Demo Program
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); string text = "Audio length: " + heartBeat.Duration.ToString(); print(10, 10, text, Color.White); spriteBatch.End(); base.Draw(gameTime); } void print(int x, int y, string text, Color color) { spriteBatch.DrawString(font, text, new Vector2((float)x, (float)y), color); }
The SoundEffectInstance
class enhances the basic functionality of SoundEffect
with additional properties and methods that make it more useful in a real-world game. (Refer to the class reference earlier in the chapter.) After loading the SoundEffect
in LoadContent()
, we can create an instance of the SoundEffect-Instance
class from its CreateInstance()
method:
heartBeat = Content.Load<SoundEffect>("heartbeat"); heartBeatInst = heartBeat.CreateInstance();
This class makes available several useful methods: Play()
, Stop()
, Pause()
, and Resume()
. And, the Volume
, Pitch
, and Pan
properties have been moved from parameters into real class properties, which we can modify outside of the Play()
method. In addition, we can cause an audio clip to loop during playback with the IsLooping
property.
The XACT program is found in the Program Files folder, under XNA Game Studio 4.0, Tools. This is a separate program that runs outside of Visual C# Express or Visual Studio. When you start XACT, it will begin with an empty project. Use the File menu to create a new XACT project with the name of your choice.
To configure a new audio project, follow these steps:
Under XACT Project, right-click Wave Banks and choose New Wave Bank. The default name, “Wave Bank,” works fine for our purposes. If, however, you intend to have multiple groups of sounds, then you would want to rename this to an appropriate name.
Right-click Sound Banks and choose New Sound Bank. Figure 4.3 shows the two windows that have been opened: Wave Bank and Sound Bank.
Locate the audio files (usually just waves) you want to use for your game. You can add the audio files individually and even open up the project at a later time to manipulate the audio collection for a particular project.
Right-click the Wave Bank window and choose Insert Wave File(s). Several wave files are added (see Figure 4.4).
Drag the file(s) from the wave bank into the cue list of the sound bank (the bottom list). The audios will be added to the sound list automatically. (Note: If you manually add them to the sound list and cue list, there will be double entries in the sound list.) Figure 4.5 shows the result.
Save the project by choosing File, Save, or by clicking the Save button in the toolbar. Then, build the project by choosing File, Build, or clicking the Build icon. The resulting file will have an extension of .xap. This file must be added to your XNA project along with the audio files (WAV, MP3, etc.).
Assuming you have built an XACT project into an XAP file, right-click the Content item in your XNA project’s Solution Explorer and choose Add, Existing Item. Then choose the XAP file built from your XACT project. Your XAP file should appear in the list under Content.
You must also add all the audio files themselves into the project. The XAP file is actually just a text file describing what needs to be built, not a compiled binary containing audios. Because the list of assets under Content can become quite messy, I recommend putting audio files into an organizing folder called Audio (see Figure 4.6).
While you’re copying files, grab the three files found inside the .Win folder where your XAP project file is located. XACT creates the .Win and .Xbox folders wherever the XAP project file is located and outputs a global settings file with an .xgs extension and both the sound bank and wave bank files. All three are required by the project in order for it to work, so just copy them all into ContentAudio.
Now, we haven’t written any code yet to work with the XACT project, but if you build it now, you’ll see the C# compiler parse the XAP file, with output something like what appears in Listing 4.2. (Note that lengthy paths and namespaces were truncated for space.) There are two files being processed in this output.
Example 4.2. XAP File Output
Building AudioBrainsucker.wav -> C:. . .ContentAudioBrainsucker.xnb Rebuilding because asset is new Importing AudioBrainsucker.wav with Microsoft.Xna.Framework.Content.Pipeline.WavImporter Processing AudioBrainsucker.wav with Microsoft.Xna.Framework.Content.Pipeline.Processors.SoundEffectProcessor Compiling C:. . .ContentAudioBrainsucker.xnb Building AudioDragon.wav -> C:. . .ContentAudioDragon.xnb Rebuilding because asset is new Importing AudioDragon.wav with Microsoft.Xna.Framework.Content.Pipeline.WavImporter Processing AudioDragon.wav with Microsoft.Xna.Framework.Content.Pipeline.Processors.SoundEffectProcessor Compiling C:. . .ContentAudioDragon.xnb
Once the files have been processed, the intelligent compiler will not rebuild them again unless the source file has changed—just the way it works with source-code files, with a date/time stamp.
Now let’s look at some code to load and play these sound clips out of the XACT project. Create three variables from AudioEngine
, SoundBank
, and WaveBank
:
AudioEngine engine; SoundBank soundBank; WaveBank waveBank;
Create the objects either in Initialize()
or LoadContent()
, making sure of course to use your own filenames:
engine = new AudioEngine("Content\Audio\XACT Project.xgs"); soundBank = new SoundBank(engine, "Content\Audio\Sound Bank.xsb"); waveBank = new WaveBank(engine, "Content\Audio\Wave Bank.xwb");
The SoundBank.PlayCue()
function is used to play sounds built into the XACT project, so we use the same SoundBank
object to play all the sounds by name. I’ve used button and key-press events again to generate the audio effects. Here is the key code, found in Update()
, that triggers the playback of the sounds.
GamePadState gamepad = GamePad.GetState(PlayerIndex.One); KeyboardState keyboard = Keyboard.GetState(); //play sounds with controller buttons if (gamepad.Buttons.A == ButtonState.Pressed) soundBank.PlayCue("Brainsucker"); if (gamepad.Buttons.B == ButtonState.Pressed) soundBank.PlayCue("Dragon"); if (gamepad.Buttons.X == ButtonState.Pressed) soundBank.PlayCue("extralife2"); if (gamepad.Buttons.Y == ButtonState.Pressed) soundBank.PlayCue("heartbeat"); if (gamepad.Buttons.Start == ButtonState.Pressed) soundBank.PlayCue("Slughead 2"); //play sounds with keys if (keyboard.IsKeyDown(Keys.A)) soundBank.PlayCue("Brainsucker"); if (keyboard.IsKeyDown(Keys.B)) soundBank.PlayCue("Dragon"); if (keyboard.IsKeyDown(Keys.X)) soundBank.PlayCue("extralife2"); if (keyboard.IsKeyDown(Keys.Y)) soundBank.PlayCue("heartbeat"); if (keyboard.IsKeyDown(Keys.Enter)) soundBank.PlayCue("Slughead 2");
This example doesn’t display any dynamic data on the screen, just instructions, as shown in Figure 4.7.
We have now fully covered the XNA audio system with not just a quick reference (for future use) but also with two examples. One simple example is for quick or small clips, and a more complex example uses XACT. XACT is more appropriate when a game has a large number of audio clips, especially when both sound effects and music are needed.
18.222.115.120