Audio formats supported in Silverlight 3
Silverlight 3 supports the audio encodings shown in the following table:

If we want to use an audio file with an encoding that does not appear in the previously
shown table, we will have to convert it to one of the supported formats.
Using free applications to convert audio formats
Expression Encoder is not the only application capable of converting audio files to the
encoding profiles supported by Silverlight 3. We can also use many free or open source
applications and several online services to convert audio files to any of the previously
shown formats.
The same applications mentioned for converting video formats are capable of
converting audio files to the encoding profiles supported by Silverlight 3.
Time for action – creating a class to handle audio concurrency
Now, your project manager wants you to add different sound effects associated with
different game events. Sometimes, these sounds have to be played concurrently. For
example, a thunder can happen at the same time as the player applies an impulse to an UFO.
It is time to create a simple yet useful sound manager class. It must be able to handle many
concurrent sound banks:
- Stay in the 3DInvadersSilverlight project.
- Create a new class—SoundManager.
- Add the following lines of code at the beginning of the class definition
(as we are going to use the System.Collections.Generic.List class):using System.Collections.Generic;
- Add the following private and static variables:
// The target for the new MediaElement instances (it must be a Panel subclass) private static Panel _target; // The last sound bank used private int _lastSoundBank = -1; // The number of sound banks available private static int SoundBanks = 5; // The default media folder public static String MediaFolder = "Media/";
- Add the following private list of media elements that will hold many
MediaElement instances:// The list of media elements private List<MediaElement> _soundBanks;
- Add the following property to control the Volume (it must be improved later with
additional code):public double Volume { get; set; }
- Add the following constructor with a parameter:
public SoundManager(Panel target) { _target = target; _soundBanks = new List<MediaElement>(SoundBanks); for (int i= 0; i< SoundBanks; i++) { _soundBanks.Add(new MediaElement()); _target.Children.Add(_soundBanks[i]); } }
- Add the following public method to play a sound taking advantage of the banks
using a round robin algorithm:public void Play(Uriuri) { _lastSoundBank++; if (_lastSoundBank >= SoundBanks) { // A simple round robin algorithm _lastSoundBank = 0; } _soundBanks[_lastSoundBank].Stop(); _soundBanks[_lastSoundBank].Source = uri; _soundBanks[_lastSoundBank].Volume = Volume; _soundBanks[_lastSoundBank].Play(); }
- Add the previously encoded audio files (235__Erratic__ufo_atmosphere.wma
and 2525__RHumphries__rbh_thunder_03.wma) to the Media folder in the
web project. - Add the following two public methods to reproduce the previously added
audio files without the need to call the generic Play method specifying a Uri:public void PlayAtmosphere() { Play(new Uri(MediaFolder + "235__Erratic__ufo_atmosphere.wma", UriKind.Relative)); } public void PlayThunder() { Play(new Uri(MediaFolder + "2525__RHumphries__rbh_thunder_03.wma", UriKind.Relative)); }
What just happened?
The code to manage multiple concurrent audio playback is now held in the new
SoundManager class. It uses some static private variables because there will be just
one sound manager for the game. Thus, we will need just one instance of this class.
The class is quite easy to understand. The constructor receives a Panel as a parameter. It
will use it as a container for the multiple MediaElement instances that it is going to create.
The _soundBanks list holds the number of MediaElement instances defined in the static
variable SoundBanks (5).
Using a round robin algorithm to work with concurrent sounds
The Play method is responsible of playing the audio file, which Urireceives as a parameter.
It uses a simple round robin algorithm to assign the available MediaElement instances
(sound banks) for each new audio file that has to be played.
Initially, there are 5 sound banks available.
If we call the Play method 7 times, the following sequence will take place:
- Play audio file #1 with MediaElement instance #0 (_soundBanks[0]).
- Play audio file #2 with MediaElement instance #1 (_soundBanks[1]).
- Play audio file #3 with MediaElement instance #2 (_soundBanks[2]).
- Play audio file #4 with MediaElement instance #3 (_soundBanks[3]).
- Play audio file #5 with MediaElement instance #4 (_soundBanks[4]).
- Play audio file #6 with MediaElement instance #0 (_soundBanks[0]). The round
starts again here. - Play audio file #7 with MediaElement instance #1 (_soundBanks[1]).
Each time the Play method is called, the value in the _lastSoundBank increases by 1:
_lastSoundBank++;
If the value is equal or greater than the maximum number of sound banks, it is time to start
using the first sound bank available again (a new round):
if (_lastSoundBank >= SoundBanks)
{
_lastSoundBank = 0;
}
Then, it is time to play the new audio file using the assigned MediaElement instance
(sound bank).
This way, we can play many audio files concurrently. We do not have to
worry about MediaElement instances in the game because we can use
the SoundManager instance features.
Time for action – generating sounds associated to game events
Now, it is time to add concurrent sound effects associated to game events.
- Stay in the 3DInvadersSilverlight project.
- Open InvadersGame.cs.
- Add the following private variable to hold the SoundManager instance:
private SoundManager _soundManager;
- Add the following lines of code after the line base.Initialize(); in the
Initialize method:InitializeSoundManager();
- Now, add the following lines of code before the end of the
UpdateWithTime method (a random thunder):if (_random.Next(20) == 2) _soundManager.PlayThunder();
- Replace the code that checks the Key./ key in the CheckKeyboard method
with these lines:if (KeyboardManager.IsKeyDown(Key.I)) { _ufo1.Body.ApplyImpulse(_levelImpulse); // Play a sound when the user applies an impulse to the UFO _soundManager.PlayAtmosphere(); }
- Build and run the solution. Click on the button and turn on your speakers again.
You will hear the background music. Then, the game will start. If you wait for a
few seconds, you will hear the sound of many thunder claps. Sometimes, before
a thunder clap finishes, you will hear many others. The music will go on playing
in the background. - Now, press the / key and you will hear a strange sound like the atmosphere of a
UFO. Another thunder clap will scare you. Press the / key again and you will enjoy
concurrent sound effects.
Add the following private method to create and initialize the sound manger
related to the game:
private void InitializeSoundManager()
{
_soundManager = new SoundManager(_mainPage.LayoutRoot);
_soundManager.Volume = 1;
}
What just happened?
You are promoted from the position of a game developer to that of a senior game developer!
The game has background music and amazing concurrent sound effects thanks to the simple
use of a SoundManager class.
We created and initialized a SoundManager instance (_soundManager). Then, we used its
methods to play a random thunder sound and a UFO atmosphere effect when the player
presses the / key.
Using a sound manager it is very easy to fire sounds when
certain game events occur.
Have a go hero – animating the game over scene
Now that you have shown your project manager videos with animated projections, he wants
you to change the Game Over screen.
You have to use a VideoBrush to paint the GAME OVER text with an animated video.
You do not know how to do it. However, you know about brushes, videos, animations, and
timeline management. You can do it with some additional research!
Have a go hero – configuring sounds and music
Most games allow the players to configure the desired volume levels for the different sound
effects and the background music.
Your project manager wants you to add a new gauge with a button to the game. When the
player clicks on this button, the game has to pause and a Canvas with a control panel using
different sliders must allow the user to control the volumes for sounds and music.
You will have to make some changes to the SoundManager class to allow the user to change
some properties that define the volume for sounds organized by categories. Also, you have
to change the way you play the background music in the game.
Pop quiz – working with audio and video in Silverlight 3
- In order to reproduce an AVI (Audio Video Interleave) video in Silverlight 3 using
MediaElement: - You just have to assign the Urito the MediaElement's Source
property and Silverlight will recognize the video format. - You must convert it to one of the video formats supported by
Silverlight 3. - You must typecast Urito AviUriand assign the result to the
MediaElement's Source property and Silverlight will recognize the
video format. - If you want a video or audio file to be available in a website instead of being
embedded in the application's .xap file: - You can add it to the ClientBin folder in the application's web
project. - You can add it to the Assets folder in the application's main project.
- You can add it to the ClientBin folder in the application's
main project. - In order to start reproducing a video or audio file using a MediaElement instance,
you can: - Call its Reproduce method.
- Call its Render method.
- Call its Start method.
- When you reproduce multiple concurrent video or audio files using many different
MediaElement instances: - Silverlight reproduces only the last started MediaElement's audio.
- Silverlight mixes the concurrent sounds.
- Silverlight reproduces only the first started MediaElement's audio.
- In order to reproduce a WAV audio in Silverlight 3 using MediaElement:
- You just have to assign the Urito the MediaElement's Source
property and Silverlight will recognize the audio format. - You must typecast Urito WavUriand assign the result to the
MediaElement's Source property and Silverlight will recognize the
audio format. - You must convert it to one of the audio formats supported by
Silverlight 3. - The Projection class allows describing:
- How to project a 2D object in the 3D space using perspective transforms.
- How to project a 2D object in the 2D space using perspective transforms.
- How to project a 3D model in the 3D space using perspective transforms.
- You can apply a perspective transform to a UIElement:
- Setting its 3DEffects property to a PlaneProjection instance.
- Setting its Projection property to a PlaneProjection instance.
- Setting its Projection property to a Projection instance.
- Silverlight 3 can use GPU acceleration to:
- Reproduce videos on any size.
- Reproduce audio files.
- Scale or stretch videos.
- When a MediaElement's Stretch property has the UniformToFill value:
- It does not preserve the video's native aspect ratio.
- It preserves the video's native aspect ratio.
- It reproduces the video using a fixed 16:9 aspect ratio.
Summary
We learnt a lot in this chapter about adding and controlling sound, music, and videos.
Specifically, we were able to use Expression Encoder to convert many different audio and
video formats to the encoding profiles supported by Silverlight. We added animated plane
projections to videos. We created a simple sound manager class capable of reproducing
concurrent sound effects. Also, we learnt how to take advantage of hardware acceleration
when scaling or stretching videos.
We learnt a lot in this book about developing 3D games using Silverlight and many other
exciting applications, engines, libraries, and tools.
Now that we have learned to develop 3D games using Silverlight, we are ready to give life
to 3D models in Rich Internet Applications. We can create amazing 3D scenes and games.
Besides, when Silverlight is not enough, we have the option to switch to the more powerful
XBAP WPF applications.