XNA provides a fair amount of flexibility for playing
sound effects inside your games. It can play multiple sounds
simultaneously (including multiple instances of the same sound) and
offers control over volume levels, stereo panning, and pitch shifting.
It can loop sounds or play them just once and also offers controls to
allow sounds to be paused and resumed.
Note that sound effects are
really intended just for sounds that take place as your game is
playing. Microsoft's certification requirements (that your games will be
required to meet when you want to distribute them through the Windows
Phone Marketplace) stipulate that sound effects are not to be used for playing background music.
1. Adding Sound Effects to your Project
Sound effects are created as
part of the Content project, as has been the case with all the other
resource data (textures and sprite fonts) . They are added in just the same way: by right-clicking the
main Content project node inside Solution Explorer and then selecting
Add / Existing Item. The sound file can then be located and added to the
project.
You will see after adding a sound file that the content item's Content Importer is set to WAV Audio File, and the Content Processor is set to Sound Effect, as shown in Figure 1.
All sound effects must be
created from WAV files. WAV (short for Waveform Audio File Format) files
are one of the oldest sound formats used by Microsoft. They usually
store sound in an uncompressed format, making them easy to read and
write, but result in large file sizes.
On desktop PCs, WAV files
have largely been replaced by formats offering higher levels of
compression such as MP3, but XNA unfortunately cannot use MP3 files for
sound effects . As a result, we find ourselves with no
choice but to use WAV files for our sounds.
NOTE
It is possible to use MP3 or WMA files as sound effects by adding them and then changing the Content Processor from the initial value of Song back to Sound Effect(refer to Figure 5-1). Although this changewill provide access to the sound from within your game, unfortunately during compilation the Sound Effect
content processor will silently convert your MP3 or WMA file into a WAV
file for the compiled game, resulting in the same large file that would
have resulted from adding a WAV file in the first place.
Once the file has been added,
we are ready to load it into our game. Once again, this is handled in
the same way as with other resources that we have loaded from the
Content project: using the Content.Load method. Listing 1 shows a piece of code that declares a SoundEffect object and loads it from the Content project. Just as before, we provide the Load method with the type of object that is being loaded.
Example 1. Loading a sound effect from the Content project
SoundEffect mySound;
mySound = Content.Load<SoundEffect>("Piano");
|
NOTE
The desktop versions of XNA can take advantage of an application called XACT (which is short for cross-platform audio creation tool),
which can organize sound effects for easier playback within a game.
XACT is only supported for Windows and Xbox360 XNA games, however, so
cannot be used for Windows Phone 7 games.
2. Playing the Sound Effects
With a sound effect loaded, we are now ready to play it by simply calling the Play method of the SoundEffect object.
Two overloads of this
method are available. The first takes no parameters and simply plays the
sound at full volume. The second overload provides some additional
control, allowing us to provide values for the volume level, the pitch,
and the stereo panning of the sample:
Volume is a float that specifies the playback volume level from 0 (silent) to 1 (full volume).
Pitch is a float
that controls the frequency of the sound playback. It is specified as a
value between - 1 (an octave lower than its native pitch) through 0
(its native pitch) to 1 (an octave higher than its native pitch). Values
outside of this range will result in an exception, so if you need to
play a sound using a larger range of pitches, you will need to load
multiple differentlypitched samples into your game.
Pan is a float
that controls the stereo position of the played sound. Values range
from - 1 (fully to the left) through 0 (centered) to 1 (fully right).
NOTE
Sound effect volume
is always played relative to the volume setting of the device, so a
volume level of 1 actually means to play at the configured device volume
level. When using the emulator, you can press F9 to increase the device
volume level or press F10 to decrease it. Press the key repeatedly to
reach full volume or to silence the emulated device.
Play is asynchronous and returns to your game immediately, leaving the sound playing in the background. If you call Play
again before an earlier call has completed, the new sound will play
alongside the older sound. Options to stop the earlier sound are
provided via the SoundEffectInstance object, which we'll discuss in a moment.
3. Integrating Sound Effects into the Game Framework
Just as we have added GameFramework support for textures and fonts, so we will add support for sound effects too. This support is implemented using another Dictionary within the GameHost class, this time named SoundEffects. The declaration of the dictionary is shown in Listing 2.
Example 2. The SoundEffects dictionary present within the GameFramework.GameHost class
// A dictionary of loaded sound effects.
public Dictionary<string, SoundEffect> SoundEffects { get; set; }
|
We can then use the dictionary
to load sound effects in the same way as we do for textures and fonts,
and can access the dictionary items anywhere within the game.
The SoundEffects
example project shows how sound effects
can be loaded into the game engine and then played back. It loads four
different samples (named EnergySound, Piano, MagicSpell, and Motorbike)
and divides the screen into four regions to allow each to be played.
Experiment with the project and with playing multiple sounds together.
The example project also sets
the sound effect's panning based on the horizontal position of the
screen tap. Tapping the left side of the screen will pan to the left;
tapping the right will pan to the right.
Try experimenting with changing the source code to produce different volume levels and different pitches, too.
4. Sound Effect Instances
Calling the Play method on a SoundEffect
object provides a very easy way to get a sound playing, and in many
cases this will be sufficient. For gunfire, explosions, player
achievement sounds and all sorts of other one-off effects, this is
likely to be all that you need.
In other places, however, you
might find that a greater level of control is needed over the sounds
that you play. The ability to loop a sound, for example, can be very
useful, but the functions provided by the SoundEffect
class alone cannot offer this ability. The main reason is that we would
have no way to stop the sound; we don't obtain a sound ID value or
anything similar, so once several sounds were active we would be unable
to tell the class which one it should stop.
This problem is resolved by the inclusion of the SoundEffectInstance class. Instances of this class are created by calling the CreateInstance method of a SoundEffect object.
SoundEffectInstance objects are very similar to SoundEffect objects, with the following key differences:
Each instance can play only one sound at a time. Calling Play
multiple times will have no effect. To play multiple sounds
simultaneously using sound effect instances, multiple instance objects
would need to be created from the underlying SoundEffect.
The Volume, Pitch, and Pan of an instance are specified using class properties rather than as parameters to the Play method. This allows the properties to be easily altered after the sound has started playing.
SoundEffectInstance objects contain a property named IsLooped that can be set to true to instruct the sound to loop.
In addition to the Play method, effect instances also have methods to Pause and Stop
the sound. They don't need to be used at all if the sound is not
looping, but if it is looping one or other will likely be useful to stop
the sound from playing. Pause will remember how much of the sound has been played and will resume from this point the next time Play is called. Stop will reset the sound so that it plays from the beginning when Play is next called. To find out whether a sound effect instance is stopped, paused, or playing, query its State property.
The SoundEffectInstances example project demonstrates the use of this class. It looks just the same as the SoundEffects
example, but works in a different way. When you press and hold your
finger on one of the sound panels, the sound will play and will loop
endlessly. When you release your finger, the sound will pause. When the
panel is touched again, playback resumes from where it left off (this is
most noticeable with the Piano and Motorbike sounds). This behavior
couldn't have been accomplished with just the SoundEffect class.
Additionally, if you slide
your finger to the left and right as the sound is playing, the pitch of
the sound will change in response. Once again, only the SoundEffectInstance allows this change to be made because the SoundEffect class only allows the pitch (as well as the volume and panning) to be set when the sound playback is first initiated.
The code that plays, repitches, and pauses the sounds, taken from the example project's Update method, is shown in Listing 3.
Example 3. Playing, setting the pitch, and pausing SoundEffectInstances
TouchCollection tc = TouchPanel.GetState();
if (tc.Count > 0)
{
// Find the region of the screen that has been touched
screenRegion = (int)(tc[0].Position.Y * 4 / Window.ClientBounds.Height);
// Ensure we have a region between 0 and 3
if (screenRegion >= 0 && screenRegion <= 3)
{
// What type of touch event do we have?
switch (tc[0].State)
{
case TouchLocationState.Pressed:
// Set the pitch based on the horizontal touch position
_soundInstances[screenRegion].Pitch =
(tc[0].Position.X / this.Window.ClientBounds.Width) * 2 - 1;
// Start the sound for this region
_soundInstances[screenRegion].Play();
break;
case TouchLocationState.Moved:
// Is the sound for this region currently playing?
if (_soundInstances[screenRegion].State == SoundState.Playing)
{
// Yes, so set the pitch based on the horizontal touch position
_soundInstances[screenRegion].Pitch =
(tc[0].Position.X / this.Window.ClientBounds.Width) * 2 - 1;
}
break;
case TouchLocationState.Released:
// Pause all of the sounds
for (int i = 0; i < _soundInstances.Length; i++)
{
_soundInstances[i].Pause();
}
break;
}
}
}
|
Try changing the code when the touch point is released so that it calls the Stop method of the SoundEffectInstance objects rather than Pause.
You will then see that each time the sound is played, it restarts from
the beginning rather than resuming from where it was interrupted.
5. Other Sound Effect Properties
Among the other properties exposed by the SoundEffect class are two that we will briefly look at.
The first is the Duration property, which returns a TimeSpan
indicating exactly how long the sample will take to play at its default
pitch. This property can be useful for queueing up sounds to play one
after another.
The second is the MasterVolume property, which is actually a static property called against the SoundEffect
class rather than on an instance. It controls the overall volume of all
sound effects, subsequently played or already playing, so it is a great
way to fade up or down the sound from or to silence.
Just like the volume of individual sounds, MasterVolume is set in the range of 0 (silence) to 1 (full volume, based on the current device volume level). It defaults to 1.
6. Obtaining Sound Effects for your Game
Although you mightwant to
create your own sound effects, there are many thousands available on
the Internet that you can use in your game instead. It is generally much
easier to get hold of quality sounds this way because you can search
through the libraries playing each sound you find until you locate one
that will fit into your game.
The main issue to be aware of
with downloaded sounds is licensing. Just as with everything else in
life, it is hard to find good things for free—particularly if you intend
to sell your game. An organization called Creative Commons has made
this particular area easier to deal with, however, and this is extremely
helpful for getting good sound effects.
A number of
different Creative Commons licenses are available, many of which permit
the material that they cover to be used in free or commercial products,
and some of which also allow modifications to be made to the licensed
items. The only general requirement is that you include attribution for
the source of the material in your game. Soif you include the details of
the sound author and a link to the site from which it was downloaded,
all such licensed sounds can be freely used within your games. Do check
the license of each individual sound that you want to use, however,
because some licenses forbid commercial use.
A couple of great sites for finding Creative Commons licensed sound effects are the following:
Both of these sites
clearly describe the license applied to each sound and have search
facilities and online previews of each sound in their database. Many
other sound sites exist, too, and can be found via your search engine of
choice.
Selecting a sound can be
tricky, and it is essential to try out each sound that you like and see
how it fits in with the game environment. Sometimes sounds that
initially seem ideal just don't work well inside a game, so spend some
time experimenting to get things sounding just right. Don't forget that
altering the volume or pitch can help with getting your sounds to fit
in, too.
To manipulate sounds that
you have downloaded or to convert them between different formats, a
sound editing application is essential. This application will let you
cut out or exclude sections of a sound, fade its volume up or down, add
echo and distortion, anddo dozens of other useful things.
Lots of commercial
applications are available for this task, but if you are looking to keep
your costs down, a free application called Audacity is well worth a
look. It has a large range of sound processing effects, has flexible
editing features, and supports saving to numerous file formats
(including WAV and MP3). Visit audacity.sourceforge.net to download a copy.
7. An Interactive Example
Three different popping
sounds are included to make the sound a little more varied, and as each
sound is played it is also given a slightly randomized pitch as well as
being panned to match the balloon position on the screen. This makes
for an entirely more satisfying balloon-popping experience!