Playing audio into an XNA application
By Giulia Costantini
Introduction
In this tutorial we will learn how to load and play sounds in our XNA applications. The tool we are going to use is XACT (Cross-platform Audio Creation Tool), a multiplatform tool (works for both Windows and Xbox360) to create audio. This program is installed with XNA Game Studio, so if you have already installed XNA you are good to go! You can find XACT following this path: “all programs” –> “Microsoft XNA Game Studio 2.0” –> “tools” –> “Microsoft Cross-Platform Audio Creation Tool”. If you want to be able to listen to sounds within XACT (instead of having to open another player) you will have to open the following program (installed with XNA too): “all programs” –> “Microsoft XNA Game Studio 2.0” –> “tools” –> ”XACT Auditioning Utility”.
Basic XACT notions
Let’s start by getting acquainted with the XACT and XNA sounds terminology.
A wave is an audio data buffer, that is a file which contains audio. The XACT supported formats are wav, aiff and xma.
A sound is instead a set of tracks played at the same time; for each track we can set various properties, such as the wave that track plays, its volume, etc…
The term cue refers to the logical sound, that is what is actually used in your source code to play a sound. Each cue can be made up of one or more sounds; if it’s made up of many sounds, when the cue is played one of its sounds is chosen. With XACT we can decide how the choice (of which sound to play) is carried out: for example we can make the choice random, or we can decide that the sounds have to be played sequentially in the order we put them, and so on.
A wave bank is a wave collection, that is a collection of audio files. A wave bank is represented by a file with .xwb extension. For each wave bank we can set various properties, such as the compression method for the audio files, if the execution is carried out in streaming or by storing the entire file, etc…
A sound bank is a collection of sounds and cues. A sound bank is represented by a file with .xsb extension.
We are going to see that a XACT project can be viewed as the whole of three files:
- a .xgs file which contains the global settings of the project;
- a .xwb file, that is the wave bank which contains our wave files;
- a .xsb file, that is the sound bank which contains all the sounds and cues.
How to create a XACT project
First of all we are going to create an XNA 2.0 project with Visual Studio (“file” –> “new” –> “project” –> “windows game 2.0”) and we will add a new folder named “Sound” (but you can call it how you want) to the Content project (right click on Content –> “add” –> “new folder”).
Now we can create our XACT project. After having opened XACT, click on “file” –> “new project” and set the path to “your_xna_project_path\Content\sound”. Let’s call our XACT project myFirstXACTProject.
Now we will have to create a new wave bank and a new sound bank, by right clicking respectively on “Wave Banks” and on “Sound Banks” and select respectively “New Wave Bank” and “New Sound Bank”.
Our banks (which by default are named “Wave Bank” e “Sound Bank” but we can change the name by clicking F2 on each of them and inserting the new name) are now on the right of the screen.
Adding audio files to the wave bank couldn’t be easier: we have to select our audio files and drag them
on
to the wave bank. Remember that the XACT supported formats are wav, aiff and xma.
We imported in our wave bank two files, named “industry.wav” and “menu.wav”. The result is the following:
Let’s move on to the sound bank; we said that a sound bank contains a collection of sounds and cues; if you look at the sound bank window you’ll notice that it is made up of two separate parts, one for the sounds and one for the cues:
To create a new sound you have to drag a wave from the wave bank into the “sounds part” of the sound bank. Dragging the “industry” wave we obtain:
This way we created the “industry” sound (but we can change the sound name) which is made up of only one track, that is the “industry.wav” wave. We can add other tracks to the sounds (by dragging another wave on the sound name), but remember that the tracks of a sound are executed simultaneously.
We can create another sound, linked to the “menu” wav file, by dragging the “menu” wave from the wave bank to the sound bank:
At this point we have two sounds, each one linked to only one wave. In order to create a cue we will have to drag a sound into the cues part. Dragging the “industry” sound into the cues we obtain:
We created a cue named “industry” (we can change this name too) linked to the “industry” sound.
Remember to save your XACT project when you are done!
Loading a XACT project in XNA
Let’s go back to Visual Studio, precisely in our XNA project. We have to include the just created XACT project into the Content project. To do so, click on Content project, then click on “Show all files” in order to see the XACT file project
and now right click on the newly appeared.xap file (“myFirstXACTProject.xap”).
and finally select “Include in Project”. Compiling our project we can see in the output window:
that the XNA Content Pipeline (which you saw in a previous tutorial) produced 3 files, the one I mentioned at the beginning of this tutorial: a general settings file (.xgs), a w
ave bank file (.xwb) and a sound bank file (.xsb).
Playing sounds into the application
The time has arrived for us to write some code J We’ll start by creating 3 objects (in the Game class):
AudioEngine engine;
WaveBank waveBank;
SoundBank soundBank;
and we’ll initialize them in the“LoadContent” function:
engine = new AudioEngine("Content\\sound\\myFirstXACTProject.xgs");
waveBank = new WaveBank(engine, "Content\\sound\\Wave Bank.xwb");
soundBank = new SoundBank(engine, "Content\\sound\\Sound Bank.xsb");
We have loaded the 3 files our XACT project is made of, that is
1. the settings file .xgs (which goes into the AudioEngine),
2. the wave bank .xwb (which goes into the WaveBank object)
3. the sound bank .xsb (which goes into the SoundBank object).
The waveBank and soundBank need also the engine to be initialized properly.
Now we have two possible way to play a sound. The first one is the following:
soundBank.PlayCue("industry");
which makes use of the sound bank to directly play the cue, identified by its name (we reproduced the “industry” cue). If we insert this line of code into the LoadContent function (just after the creation of the three object engine, waveBank and soundBank) we’ll obtain that the sound linked to the “industry” cue will be played once when the application starts.
The second possibility is to define another object
Cue cue;
of Cue type, and to write in the LoadContent function:
cue = soundBank.GetCue("industry");
cue.Play();
What did we just do? We took the “industry” cue from the sound bank, we stored it into a Cue object and we played it. The results is just the same, which is the “industry” cue is executed at the application launch.
What if we wanted to play some sound only when a certain key is pressed? We will have to write the following code in the “Update” function:
if (Keyboard.GetState().IsKeyDown(Keys.Space))
{
cue = soundBank.GetCue("industry");
cue.Play();
}
This way, when space is pressed the desired cue will be played.
But we encounter a problem: we know that the function Update is invoked many times per second. So, during our space key pressure the Update function will be called many times and each one of them the execution of the “industry” cue will be started again. The result is that our sound is executed many times, each one some thousandth of second after the previous. Moreover if we press space again (after some seconds) while the executing sound has yet to stop, another instance of the sound will start and it will be overlapped to the first one. How can we avoid this unpleasant situation? Thanks to the isPlaying property of the Cue object! Such property tells us if the cue is being executed; this way we can begin the execution of a cue only when such cue is not already playing. Source code:
if (cue != null && cue.IsPlaying == false)
cue = null;
if (Keyboard.GetState().IsKeyDown(Keys.Space) && cue == null)
{
cue = soundBank.GetCue("industry");
cue.Play();
}
In this code we decided that a cue is null when it isn’t being executed. In fact, if the cue isn’t null and it’s executing a sound and this sound ends, the cue isPlaying property will become false and the cue will be set to null. Pressing space has some effect only if the cue is null, that is if the cue isn’t being executed.
We solved our problem: our cue will be executed if and only if space is pressed and if it wasn’t already executing (which is exactly what we wanted)!
NB: the cue obtained with GetCue can be played only one time; after that the cue has been “consumed” and it’s not valid anymore. Because of this, before each “cue.Play()” we have to obtain again the cue from the sound bank with GetCue.
(Quite) advanced XACT notions
The XACT tool makes the sound technician totally independent from the programmers. Why is that? We saw that we use the cues by name (for example we played the cue named “industry”). If the sound technician modifies only the waves and the sounds linked to the cues, but she leaves the cues names unchanged, she can work on her own and our source code will continue to work. So the sound technician can improve and modify the cues with XACT, and with only a simple recompilation of our XNA project (during which the 3 files xgs, xwb and xsb will be re-created, if necessary) we will have the updated sounds without having to change even a single line of code.
But what can a sound technician exactly do with XACT?
We saw that a sound can be made of more tracks (dragging the name of each wave on the sound name): these tracks will be however executed simultaneously. We can also delete a track from a sound by clicking on the track and then clicking “del”. In the following image you can see a sound (“industry”) which is made of two tracks (the “industry” and the “menu” waves):
In a sound bank there can be many sounds, each one linked to certain tracks:
Each cue can be linked to many sounds, simply draggin them on the cue name. In the following image we can see the “cue1” cue which is made of both the sounds in the so
und bank, that is “industry” and “menu”.
If a cue contains many sounds, we can set how the choice of which sound to play is carried out.
In this picture you can see the drop-down menu with which you can set such property: the possibilities are many.
You can find here the source code of this tutorial and here the high-res webcast in which Alessandro Piva explains XACT and shows the code writing on-the-fly. An embedded version (lower res) can be found below:
thanks for your share!
I can learn more knowledge about computer from your space.
let’s be friends,ok?