Roger from SilverlightAddict.com asked me for more information about how I manage the sound effects in the Silverlight version of Legend of the Greasepole.
I have a Canvas element in my scene called MusicCanvasRoot. It contains a number of MediaElement children equal to the maximum number of simultaneous sounds that the game will play. This helper method allows my sound routines to find an unused MediaElement, and returns null if the maximum number of sounds is currently playing:
private static List<MediaElement> MediaElements = null;
private static int MaxSimultaneousSounds = 14;
private static MediaElement GetFreeMediaElement()
{
if (MediaElements == null)
{
MediaElements = new List<MediaElement>();
for (int i = 0; i < MaxSimultaneousSounds; i++)
{
MediaElement me = new MediaElement();
MediaElements.Add(me);
Page.Instance.MusicCanvasRoot.Children.Add(me);
}
}
foreach (MediaElement me in MediaElements)
{
if (me.Tag == null) return me;
}
return null;
}
When a sound is playing in a MediaElement, I set the Tag on the MediaElement to indicate whether or not the sound is looping. Here’s the internal method that handles requests that come in to play a sound:
private void DoPlay(int volume, int pan, bool looping)
{
MediaElement mediaElement = GetFreeMediaElement();
if (mediaElement == null) return;
mediaElement.MediaEnded += me_MediaEnded;
mediaElement.Volume = Page.Instance.IsMuted ? 0d : 1d;
if (looping) mediaElement.Tag = “PLAYLOOP”; else mediaElement.Tag = “PLAYONCE”;
// …
// Assign a Uri to mediaElement.Source
//
// My sounds are stored as MP3 files stored as Resources in an
// Assembly that is downloaded after the app starts.
// …
// TODO: Set Volume and Pan in Silverlight.
// This allows me to implement IsPlaying for a particular sound effect
MyMediaElements.Add(mediaElement);
mediaElement.Position = TimeSpan.Zero;
mediaElement.Play();
}
And here’s the Event Handler for the MediaEnded event, which managing stopping sounds, or looping them when they complete:
void me_MediaEnded(object sender, RoutedEventArgs e)
{
MediaElement me = sender as MediaElement;
if (((string)me.Tag) == “PLAYLOOP”)
{
me.Position = TimeSpan.Zero;
me.Play();
return;
}
else
{
ReleaseMediaElement(me);
}
}
private void ReleaseMediaElement(MediaElement me)
{
me.MediaEnded -= me_MediaEnded;
me.Stop();
me.Tag = null; // free it up for use by another sound effect.
MyMediaElements.Remove(me);
}
The string-based Tags are a throwback to Silverlight 2 Beta 1, where the Tag exhibited some strange behavior that seems to be resolved in Beta 2.
Hope that helps. Let me know if you have any questions or want a full drop of the sound code.
Possibly Related Articles
- Silverlight 2 Greasepole Game Engine
- WPF Commanding – When do Commands re-evaluate their CanExecute method?
- Legend of the Greasepole, Silverlight 2 Beta Edition
Posted Aug 5th, 2008
into Developer, Microsoft, Silverlight
with tags Legend of the Greasepole, SilverlightAddict, sound
5 Comments »

I like this approach, but wonder if it will still give me the errors I have been encountering. My first technique was to have a collection of MediaElements, and simply set their source to a stream that was already open to a embedded resource. However, this creates a crazy memory leak (search Silverlight.net forums for MediaElement leak). On my second attempt I tried creating a finite list of MediaElements with their sources already set to my sounds. I would then just stop and play them over and over. The problem there is that after the first play of each MediaElement, you can’t truly rewind (by calling stop()), so it would never again play the first fractions of a second of the sounds. With this method, I had to pad the front of my sounds with nearly half a second of silence before it sounded good. In your code above, can you tell if your sounds are really starting from the very beginning? Am wondering if this is the same issue people are having with getting perfect seamless loops. I hate the idea of destroying and recreating the MediaElements and streams constantly. I just assumed that would be more expensive, but honestly have not tried it yet.
Thanks!
Hey Roger,
I just want to confirm that I’m having the same experience with MediaElements; of course you can recreate each MediaElement each time (it works) which gives some overhead and really leaks in memory.
Hopefully Microsoft will fix this problem very soon.
Cheers!
Guys, just to be clear, I am *not* re-creating the MediaElements each time I play a sound. Not at all. The only time I ever instantiate a MediaElement is at load time, when I create a set of MediaElements (in the above example, 14) which I reuse throughout the application. Note that this restricts me to a maximum of 14 sounds being played simultaneously.
Look how the MediaEnded event is being handled. The MediaElement is being ‘released’ back into the pool of available MediaElements, so that it might be used again to play a different sound.
Roger – just a few more notes in response to your questions above:
I would be able to tell if the sounds weren’t playing from the beginning, and I am pretty certain that they are.
I am having trouble creating perfect seamless loops myself (as you can tell from the artifacts in the menu music, and the code for creating them is above — this works very well in WPF). I experimented with this and didn’t come up with a satisfactory solution.
And for the record, the idea of destroying and re-creating MediaElements for every sound definitely makes me shudder
WPF would have an absolute conniption fit if you did that.
I’m getting similar results to what Roger is getting. If either of you are still monitoring this post could you tell me if you are using .wma or .mp3 files? I’m using .wma and have sounds that are under 1second and they don’t make a sound when playing.