Chapter 5. Sounding Out with Game Audio

Our worlds have been very quiet so far; apart from the occasional sound of the screen being tapped, everything has moved in complete silence. That's no way for a game to be, so in this chapter, we'll make some noise by adding sound effects and music to our games.

Game audio plays a significant role in the experience that a player has when playing a game. A game with little or no sound feels hollow and empty, whereas distinctive and characteristic sound effects and music can really draw a player into the game and make it a much more absorbing event.

Mobile devices typically have less opportunity to impress in this regard than desktop PCs or game consoles because they are usually limited to smaller speakers, whereas PCs or consoles might well be hooked up to powerful surround sound systems. Headphones are likely to be commonly used with mobile devices, however, and they can provide very effective sound to your players.

Regardless of the way that the device is producing sound, you should still ensure that your games sound as good as possible. In this chapter, we'll explore just how you can go about achieving that goal.

Sound Effects and Music

XNA makes a distinction between two types of sound that it can play: sound effects and music. Sound effects are ideal for sounds that correspond to the actions taking place within your game, while music can be played on a loop in the background to accompany your game the whole time it is playing.

Each of these has certain requirements that must be taken into account, and various options that can affect the sound playback.

Let's start with looking at sound effects.

Playing Sound Effects

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, as we will discuss in Chapter 15)stipulate that sound effects are not to be used for playing background music.

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) that we used in previous chapters. 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 5-1.

The properties for a WAV file added to an XNA Content project

Figure 5.1. The properties for a WAV file added to an XNA Content project

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 (though it does use them for background music, as you will see later in this chapter). 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 5-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 5.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.

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.

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

Example 5.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 that accompanies this chapter 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.

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

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

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.

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:

  • http://www.freesound.org

  • http://www.soundbible.com

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.

An Interactive Example

Recall the Balloons project that we created in Chapter 4 to illustrate mapping input coordinates to objects on the screen. To bring a little more life to the example, an updated version of Balloons is included with this chapter with some sound effects added.

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!

Playing Music

We have already discussed the fact that the SoundEffect class is not to be used for playing music, but that doesn't mean that we can't provide backing tracks for our games. XNA provides separate functionality for playing music, but in the context of Windows Phone 7 there are some things that we need to be aware of in order for our game to meet Microsoft's certification requirements.

Let's look at how (and when) you can play music within your games.

To Play or Not To Play

The certification requirement complication for Windows Phone 7 games revolves around the fact that one of the other primary uses for the device is as a media player. The operating system has a flexible media library that allows music and other audio content to be played on the device, even when the media library has been moved to the background.

As a result, it is entirely possible that, when the user launches your game, music is already playing in the background. Microsoft has decided that this existing music should take priority over your game music and that you must not stop it from playing without either directly asking the user for permission (by displaying a dialog box, for example, asking if the user wants to play the game music instead of the current audio track) or by providing a configuration option that allows it to be configured on a more permanent basis (in which case the option must default to not interrupting the existing media playback). Without observing this requirement, your game will be rejected when you submit it to the Windows Phone Marketplace.

We will look at how to perform this check (and how to pause the background music if appropriate) in a moment, but for now please bear in mind the need to do this.

Note that this check applies only to playing music with the MediaPlayer class, which is the class that provides access to the music player functionality. Sound effect playback is permitted even if the device is already playing music, so no special checking needs to be performed for sound effects. The certification requirements state that sound effect objects should not be used for playing background music, however, so this isn't a way to bypass the requirement.

Adding Music to your Project

Music is also added to the Content project. Unlike sound effects, music is expected to be in either MP3 or WMA format. This is a good thing because such formats produce much smaller files than WAV files due to the way they are compressed. Because music is likely to be much longer in duration than a sound effect, having compression applied is essential for keeping the size of your finished game under control.

MP3 files have taken over the world during the last decade and must surely form one of the most widely known file formats in existence. Sound files encoded using MP3 are compressed using a lossy compression algorithm. Although this means that there is some degradation of the audio when it is played back (just as there is a loss of image quality with JPG images), in most cases the quality loss is virtually or completely unnoticeable.

MP3 can compress audio data to different degrees, and the higher the compression the greater the quality loss on playback. The compression level is set when the MP3 is created by specifying a bit rate, which controls how many kilobits of data can be used to store each second of compressed audio. Compressing files at a bit rate of 128 kilobits per second will typically reduce CD quality audio to about 9 percent of its original file size—a massive saving.

Windows Media Audio (WMA) files are similar in approach to MP3s, also using a proprietary Microsoft compress to provide lossy compression (although a lossless variation is available). Microsoft claims that WMA files can be created that have the same quality level as an MP3 while using only half the storage space, though there are those who dispute this claim. Nevertheless, it is still a capable format and certainly worth considering as a format for your game music.

Note

Audacity is capable of exporting sounds in both MP3 and WMA format.

When you add a music file to the content, the properties show the Content Processor as Song, as shown in Figure 5-2.

The properties for an MP3 file added to an XNA Content project

Figure 5.2. The properties for an MP3 file added to an XNA Content project

"Song" is in fact the term that XNA uses to refer to a piece of music, and its class names reflect this. To load a song, we use the Song class along with the usual Content.Load call. In the game framework, we store a collection of songs within the GameHost class inside a Dictionary named Songs. Listing 5-4 shows the instruction within a project's LoadContent function that loads a song into the framework.

Example 5.4. Loading a song into the game framework from the Content project

// Load our song
        Songs.Add("2020", Content.Load<Song>("Breadcrumbs_2020"));

Playing the Music

Playing a song is very easy: just call the static MediaPlayer.Play function, passing in the Song object that you have loaded. Only one song can play at a time; trying to play a second song will stop the first song from playing.

However, we have the tricky issue of whether we are allowed to play music or not because, if the device is already playing background music, we must leave it alone.

This is determined using the MediaPlayer.GameHasControl property. If it returns true, we have full access to playing music; if it returns false, there is music already playing; and unless the user has explicitly confirmed that they want for our game to take control, we must allow it to continue. Listing 5-5 shows some code from the LoadContent function of the BackgroundMusic example project that accompanies this chapter. If it detects that media are already playing, it doesn't even attempt to load the song; otherwise, the song is loaded and played.

Example 5.5. Checking whether the game is allowed to play music and then loading and starting playback

// Load songs
        if (MediaPlayer.GameHasControl)
        {
            // Load our song
            Songs.Add("2020", Content.Load<Song>("Breadcrumbs_2020"));

            // Play the song, repeating
            MediaPlayer.IsRepeating = true;
            MediaPlayer.Play(Songs["2020"]);
        }

Assuming that we can play our music, there is a number of other methods and properties that we can access from the MediaPlayer class to affect the way in which the music plays:

  • Pause and Stop can be used to halt playback. Just as with sound effects, Pause will remember the position at which the song was paused, allowing it to be later resumed; whereas Stop will discard the position. Either way, you can call the Resume method to start the song playing again.

  • IsMuted and Volume provide control over the playback volume. IsMuted is a boolean property that will completely silence the song without pausing it, while Volume allows the playback volume to be faded between silence (0.0) and the current device volume (1.0).

  • IsRepeating allows you to set the song to loop endlessly. This looping is often very useful for games because they tend to have background music that plays repeatedly the whole time the game is running. There is a slight issue with repeating music to be aware of, however, as we will discuss in a moment.

  • PlayPosition returns a TimeSpan object detailing the current playback time through the song. This can be used to create a playback time display, as will be demonstrated shortly.

Each loaded Song object also has a series of interesting-looking properties that might be interrogated. Unfortunately, it turns out that they aren't too useful after all. Properties are available to provide information on the song's Album, Artist, and Genre, among other things, but when songs are read from a game's Content project, none of them is populated even if the information is present inside the MP3 file. These properties are instead used to access data on songs contained within the device's media library.

One useful property that we can read from the Song is its Duration, which also returns a TimeSpan, this time containing the length of the song. We can use this alongside the MediaLibrary.PlayPosition for our playback time display. The BackgroundMusic example project displays such a timer and generates its text as shown in Listing 5-6. An example of the display it produces is shown in Figure 5-3.

Example 5.6. Displaying the current position and duration of a song

// Are we playing a song?
        if (MediaPlayer.GameHasControl)
        {
            // Yes, so read the position and duraction
            currentPosition = MediaPlayer.PlayPosition;
            duration = Songs["2020"].Duration;
            // Display the details in our text object
            TextObject positionText = (TextObject)GameObjects[0];
            positionText.Text = "Song position: "
                        + new DateTime(currentPosition.Ticks).ToString("mm:ss") + "/"
                        + new DateTime(duration.Ticks).ToString("mm:ss");
        }
The display from the BackgroundMusic example project

Figure 5.3. The display from the BackgroundMusic example project

This is nearly all you need to know about playing music, but there is one other thing that you should be aware of, and it is a rather annoying feature of XNA's media playback functionality. When you set a song to loop, there is a very slight pause between the song finishing and restarting. If your song fades to silence at the end, it will be unnoticeable, but if you try to loop the song so that it restarts seamlessly, this pause can be quite noticeable.

Although there is nothing you can do to eliminate the pause, you can make a minor adjustment to the song to slightly reduce its impact. The pause can be irritating on two levels: it enforces a brief moment of silence and it results in the music playback being thrown slightly off-beat. This second problem can be very distracting indeed.

To eliminate the timing problem, edit your music file and trim about one-tenth of a second from the end. Then save it and use this modified version in your game. The pause will then be offset by a corresponding gap in the music track, allowing the beat to continue uninterrupted.

Game in Focus: Cosmic Rocks (Part III)

We could certainly enhance Cosmic Rocks by adding some sound effects, so let's do so now.

After giving some thought to the aspects of the game that could use sound effects, the following list emerged:

  • A laser gun sound for when the player fires. It needs to avoid being overpowering because it will be played a lot of times.

  • A white noise sound for when the player is thrusting.

  • A sound for hyperspace.

  • A substantial explosion for when the player's ship is destroyed,

  • A smaller explosion for when a rock is damaged. Once again, this is a very frequent sound, so it needs to be much quieter than the player explosion.

I spent some time searching through the Creative Commons sound effect sites; after a little hunting, I managed to find a set of samples that I think work very well. All the sounds and the attribution information can be found within the Content project of the CosmicRocksPartIII project that accompanies this chapter. The attribution information is contained within the Attribution.txt file, also included in the Content project. In a finished game, this information would need to be included somewhere inside the game itself (perhaps in an "About" or "Credits" screen, but we've not developed one of them yet, so this will suffice for the time being).

For the most part, the integration of the sound is very straightforward: at the appropriate trigger points (the spaceship's FireBullet, Hyperspace, and Explode functions and the rocks' DamageRock function), the game simply needs to call the Play method of the appropriate sound effect.

The only sound that is a little more complex is that of the thruster. It is implemented using a looping sound effect, so a SoundEffectInstance object is used. This is declared as a class-level variable within the SpaceshipObject class and is named_thrusterSound.

Two simple functions are present within the spaceship code to support this: StartThrusterSound and StopThrusterSound. When the game detects that the screen has been touched long enough for thrusting to begin, it calls the first of these functions to start the sound; when contact is released, it calls the second function to stop it again.

The only minor complication is that, when the spaceship explodes or enters hyperspace, the thrust is cancelled immediately, without waiting for the player to release contact with the screen. To stop the thruster sound from continuing to play when these events occur, the Explode and Hyperspace functions both call into StopThrusterSound. Remember when you are writing your own games to keep track of looping sounds so that they can be carefully controlled.

One final feature worth noting is the sound of the player's ship exploding. The sound effect used for this is already quite a deep bassy sound, but when the ship explodes, the game actually starts two instances of the sound. The first is played at the default pitch, but the second has a very small random variation to its pitch. These two sounds interfere with one another in a pleasing way when they are played, giving the impression of even more depth to the produced sound. This combination provides a satisfying auditory output for an event as significant as the player losing a life.

Make Some Noise

Sound and music form an important part of a game experience. Carefully crafted sound effects and background music can really bring the game to life and help the player to connect with the action that is taking place on the screen. It is well worth investing some time and effort into choosing the sounds that you include with your game.

Don't overlook the possibility that your player will want to completely disable all of the game sound, however. There are many environments (such as in an office) where someone mightwant to have a quick play of your game, but doesn't want to have sound unexpectedly blasting from their device. Be considerate and provide players with an option to switch the sound off quickly and easily should they want to do so.

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

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