Chapter 4. Audio

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)

Microsoft.Xna.Framework.Audio Reference

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.

Note

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.

Classes

Following are the classes found within this namespace.

AudioEmitter

Represents a 3D audio emitter.

Public Properties

 

DopplerScale

Gets or sets a scalar applied to the level of Doppler effect calculated between this and any AudioListener.

Forward

Gets or sets the forward orientation vector for this emitter.

Position

Gets or sets the position of this emitter.

Up

Gets or sets the upward orientation vector for this emitter.

Velocity

Gets or sets the velocity vector of this emitter.

AudioEngine

Represents the audio engine. Applications use the methods of the audio engine to instantiate and manipulate core audio objects.

Public Fields

 

ContentVersion

Specifies the current content version.

Public Properties

 

RendererDetails

Gets a collection of audio renderers.

Public Methods

 

GetCategory

Gets an audio category.

GetGlobalVariable

Gets the value of a global variable.

SetGlobalVariable

Sets the value of a global variable.

Update

Performs periodic work required by the audio engine.

AudioListener

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

 

Forward

Gets or sets the forward orientation vector for this listener.

Position

Gets or sets the position of this listener.

Up

Gets or sets the upward orientation vector for this listener.

Velocity

Gets or sets the velocity vector of this listener.

Cue

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

 

IsCreated

Returns whether the cue has been created.

IsPaused

Returns whether the cue is currently paused.

IsPlaying

Returns whether the cue is playing.

IsPrepared

Returns whether the cue is prepared to play.

IsPreparing

Returns whether the cue is preparing to play.

IsStopped

Returns whether the cue is currently stopped.

IsStopping

Returns whether the cue is stopping playback.

Name

Returns the friendly name of the cue.

Public Methods

 

Apply3D

Calculates the 3D audio values between an AudioEmitter and an AudioListener object, and applies the resulting values to this Cue.

GetVariable

Gets a cue-instance variable value based on its friendly name.

Pause

Pauses playback.

Play

Requests playback of a prepared or preparing Cue.

Resume

Resumes playback of a paused Cue.

SetVariable

Sets the value of a cue-instance variable based on its friendly name.

Stop

Stops playback of a Cue.

DynamicSoundEffectInstance

Provides properties, methods, and events for playback of the audio buffer.

Public Properties

 

IsLooped

Indicates whether the audio playback of the DynamicSoundEffectInstance object is looped.

PendingBufferCount

Returns the number of audio buffers in the queue awaiting playback.

Public Methods

 

GetSampleDuration

Returns the sample duration based on the specified size of the audio buffer.

GetSampleSizeInBytes

Returns the size of the audio buffer required to contain audio samples based on the specified duration.

Play

Begins or resumes audio playback.

SubmitBuffer

Submits an audio buffer for playback.

InstancePlayLimitException

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.

Microphone

Provides properties, methods, and fields and events for capturing audio data with microphones.

Public Fields

 

Name

Returns the friendly name of the microphone.

Public Properties

 

All

Returns the collection of all currently available microphones.

BufferDuration

Gets or sets audio capture buffer duration of the microphone.

Default

Returns the default attached microphone.

IsHeadset

Determines if the microphone is a wired headset or a Bluetooth device.

SampleRate

Returns the sample rate at which the microphone is capturing audio data.

MicrophoneState

Returns the recording state of the Microphone object.

Public Methods

 

GetData

Gets the latest recorded data from the microphone.

GetSampleDuration

Returns the duration of audio playback based on the size of the buffer.

GetSampleSizeInBytes

Returns the size of the byte array required to hold the specified duration of audio for this microphone object.

Start

Starts microphone audio capture.

Stop

Stops microphone audio capture.

Public Events

 

BufferReady

Event that occurs when the audio capture buffer is ready to be processed.

NoAudioHardwareException

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.

NoMicrophoneConnectedException

The exception thrown when Microphone API calls are made on a disconnected microphone. All properties and methods are inherited from Exception.

SoundBank

Represents a sound bank, which is a collection of cues.

Public Properties

 

IsInUse

Returns whether the sound bank is currently in use.

Public Methods

 

GetCue

Gets a cue from the sound bank.

PlayCue

Plays a cue.

SoundEffect

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

 

DistanceScale

Gets or sets a value that adjusts the effect of distance calculations on the sound (emitter).

DopplerScale

Gets or sets a value that adjusts the effect of Doppler calculations on the sound (emitter).

TimeSpan Duration

Gets the duration of the SoundEffect.

MasterVolume

Gets or sets the master volume that affects all SoundEffectInstance sounds.

Name

Gets or sets the asset name of the SoundEffect.

SpeedOfSound

Returns the speed of sound: 343.5 meters per second.

Public Methods

 

CreateInstance

Creates a new SoundEffectInstance for this SoundEffect.

FromStream

Creates a SoundEffect object based on the specified data stream.

GetSampleDuration

Returns the sample duration based on the specified sample size and sample rate.

GetSampleSizeInBytes

Returns the size of the audio sample based on duration, sample rate, and audio channels.

Play

Plays a sound.

SoundEffectInstance

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

 

IsLooped

Gets a value that indicates whether looping is enabled for the SoundEffectInstance.

Pan

Gets or sets the panning for the SoundEffectInstance.

Pitch

Gets or sets the pitch adjustment for the SoundEffectInstance.

State

Gets the current state (playing, paused, or stopped) of the SoundEffectInstance.

Volume

Gets or sets the volume of the SoundEffectInstance.

Public Methods

 

Apply3D

Applies 3D position to the sound.

Pause

Pauses a SoundEffectInstance.

Play

Plays or resumes a SoundEffectInstance.

Resume

Resumes playback for a SoundEffectInstance.

Stop

Stops playing a SoundEffectInstance.

WaveBank

Represents a wave bank, which is a collection of wave files.

Public Properties

 

IsInUse

Returns whether the wave bank is currently in use.

IsPrepared

Returns whether the wave bank is prepared to play.

Structures

Following are the structures found within this namespace.

AudioCategory

Represents a particular category of sounds.

Public Properties

 

Name

Specifies the friendly name of this category.

Public Methods

 

Pause

Pauses all sounds associated with this category.

Resume

Resumes all paused sounds associated with this category.

SetVolume

Sets the volume of all sounds associated with this category.

Stop

Stops all sounds associated with this category.

RendererDetail

Represents an audio renderer, which is a device that can render audio to a user.

Public Properties

 

FriendlyName

Gets the human-readable name for the renderer.

RendererId

Specifies the string that identifies the renderer.

Enumerations

Following are the enumerations found within this namespace.

AudioChannels

Defines the number of channels in the audio data.

Mono

Indicates audio data is contained in one channel.

Stereo

Indicates audio data contains two channels.

AudioStopOptions

Controls how Cue objects should stop when Stop is called.

AsAuthored

Indicates the cue should stop normally, playing any release phase or transition specified in the content.

Immediate

Indicates the cue should stop immediately, ignoring any release phase or transition specified in the content.

MicrophoneState

Current state of the Microphone audio capture (started or stopped).

Started

The Microphone audio capture has started.

Stopped

The Microphone audio capture has stopped.

SoundState

Current state (playing, paused, or stopped) of a SoundEffectInstance.

Paused

The SoundEffectInstance is paused.

Playing

The SoundEffectInstance is playing.

Stopped

The SoundEffectInstance is stopped.

Simple Audio Playback

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.)

Adding Audio Content to the Project

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.

Adding an existing audio file to the project via the content system.

Figure 4.1. Adding an existing audio file to the project via the content system.

The following audio file types can be added to an XNA project for use with the SoundEffect class:

  • XAP

  • WAV

  • WMA

  • MP3

Loading the Audio Clip

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");
}

Note

When you add content to one platform project (such as Windows), the content item is also automatically added to the other platform projects (such as Xbox 360). You do not need to manage assets individually—a real time saver.

Playing the Audio Clip

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);
}

Audio Clip Length

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.

The Simple Audio Demo program.

Figure 4.2. The Simple Audio Demo program.

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);
}

SoundEffectInstance

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.

Cross-Platform Audio Creation Tool (XACT)

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.

Creating a New Audio Project

To configure a new audio project, follow these steps:

  1. 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.

  2. 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.

    A new XACT project showing the wave banks and sound banks.

    Figure 4.3. A new XACT project showing the wave banks and sound banks.

  3. 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.

  4. Right-click the Wave Bank window and choose Insert Wave File(s). Several wave files are added (see Figure 4.4).

    Adding audio files to the wave bank.

    Figure 4.4. Adding audio files to the wave bank.

  5. 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.

Creating cues and sounds from the audio files in the wave bank.

Figure 4.5. Creating cues and sounds from the audio files in the wave bank.

Building the Audio Project

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.).

Note

If the Build Project dialog box appears, just leave the Report option on None and click Finish.

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).

The audio files and XACT project file have been added.

Figure 4.6. The audio files and XACT project file have been added.

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.

Playing Sounds from an XACT Project

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.

The XACT Audio Demo plays five different sounds.

Figure 4.7. The XACT Audio Demo plays five different sounds.

Summary

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.115.120