robburke.NET
© 2009 Robert Burke
All Rights Reserved.

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

  1. Silverlight 2 Greasepole Game Engine
  2. WPF Commanding – When do Commands re-evaluate their CanExecute method?
  3. Legend of the Greasepole, Silverlight 2 Beta Edition

5 Responses to “More of Silverlight sound implementation for multimedia app”

  1. RogerGuess 4th Sep 2008 @ 4:43 pm

    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!

  2. B*gger 13th Sep 2008 @ 9:35 pm

    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!

  3. Rob Burke 14th Sep 2008 @ 9:32 am

    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.

  4. Rob Burke 14th Sep 2008 @ 9:38 am

    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.

  5. Mike 13th Nov 2008 @ 4:47 pm

    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.

Trackback URI | Comments RSS

Leave a Comment