[Tutorial] Playing sound effects through Windows Phone 8

MainMenuPage

The practical parts of my Windows Phone children’s app is complete, so now I’m working on cleaning up the code and adding details to refine it and make it appear like a professional product. In particular, I wanted to add sound effects.

I wanted to add a clicking sound when a user navigates to and from the various pages. Additionally, when a user taps the “What do you see?” input box on the Details Page and enters the correct text, I needed an audio cue to notify the congratulate the user on entering the correct text.

The first thing you’ll need to know about audio in Windows Phone, and SilverLight as well, is that it uses the XNA API to handle audio. There are a few key differences however.

DetailsPage

SoundEffect vs. SoundEffectInstance

When it comes to sounds, you may have noticed that there is a SoundEffect class and a similarly titled SoundEffectInstance class. Essentially SoundEffectInstance allows you to have more control over the particular effect and modify properties such as volume, pitch, and pan. I found no need for this in my project, so I chose to use SoundEffect.

Either way, we’ll need to add the following namespaces to our page:

using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;

Xna.Framework.Audio allows us to use the SoundEffect class, whereas Xna.Framework will allow us to call the FrameworkDispatcher.Update which will be required to update the audio effect each frame; we’ll cover this in more detail in the next section.

XNA updates every frame, Windows Phone does not

The game loop is called each frame in an XNA game, and in turn calls Update which is essential for making changes to the game’s audio, visual, and input classes. Windows Phone and Silverlight do not update on a constant basis, so therefore we need to call FameworkDispatcher.Update so that we can create that update loop on our own.

A static class

I chose to create my SoundEffects class and all of its properties as a static one for two simple reasons:

1) Only one instance of my sound effects need to exists at a time
2) Keeps my code neat and clean

There’s no need to have to create a new instance of my SoundEffects class during the initialization of each of my pages, and I want to write as little code as possible.

Creating the class

Let’s begin by creating our class and adding our variables:

public static class SoundEffects
{
     private static bool initialized = false;
     private static SoundEffect sfx_ButtonClick;
     private static SoundEffect sfx_yay;
}

I’ve created two SoundEffect variables; one for when the user enters a menu, and the other for when the user successfully matches a word with what he or she sees on screen. The bool initialized is there for error checking more than anything else.

/****************************************************************
 * Must be called before using static methods
 ****************************************************************/
 public static void Initialize()
 {
    if (SoundEffects.initialized)
       return;

    // Adds an Update delegate, to simulate the XNA update method.
    FrameworkDispatcher.Update();
    initialized = true;
 }

The initialization function will be called by each page which uses our SoundEffects class. This checks to see if our SoundEffects class has been created. The next step called the FrameworkDispatcher that I mentioned earlier, which is our artificial loop for updating the audio.

/****************************************************************
 * Plays the click sound when user enters/exits a menu
 ****************************************************************/
 public static SoundEffect SFX_ButtonClick
 {
    get
    {
       // If not initialized, returns null.
       if (!SoundEffects.initialized)
           return null;

     // Holds informations about a file stream.
     StreamResourceInfo info = App.GetResourceStream(new Uri(@"AssetsAudioButton_Enter.wav", UriKind.Relative));

    // Create the SoundEffect from the Stream
    sfx_ButtonClick = SoundEffect.FromStream(info.Stream);
    return sfx_ButtonClick;
    }
 }

Here, I create a SoundEffect called SFX_ButtonClick. The first thing it does is check if the SoundEffects class has been initialized, and if not it returns null and exits. The next step is to open the file stream by calling the StreamResourceInfo class, which is Windows Phone’s alternative to XNA’s content pipeline and tells your program where to grab the this particular file from. In this case, I have my Button_Enter.wav file stored in my Assets/Audio folder.

Finally, I create the sound effect using the information from my stream I’ve just defined above. So my sfx_ButtonClick takes my stream as a parameter, and my stream simply tells the sound effect to look at AssetsAudioButton_Enter.wav to find the audio file.

Implementing the SoundEffects class into your app

Let’s take a look at my MainPage class, which is the first thing a user sees when they load this program. Inside this constructor I call my SoundEffect.Initialize function.

/*********************************************************
 * Constructor
 ********************************************************/
 public MainPage()
 {
    ....
    // Initializes SoundEffects class
    SoundEffects.Initialize();
    ....
 }

Inside of my OnNavigatedTo function I have my SoundEffects.SFX_ButtonClick.Play function called, which triggers my sound effect each time my the main page is navigated to.

/*********************************************************
 * Loads data for ViewModel
 *********************************************************/
 protected override void OnNavigatedTo(NavigationEventArgs e)
 {
    if (!App.ViewModel.IsDataLoaded)
       App.ViewModel.LoadData();

     // Plays the click sound
     SoundEffects.SFX_ButtonClick.Play();
 }

Inside of my MainLongListSelector_SelectionChanged function I call SFX_ButtonClick.Play again so that the sound effect is triggered when I enter my details page as well.

/*********************************************************
 * Handle selection changed on LongListSelector
 *********************************************************/
 private void MainLongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
    ....
    // Plays the click sound
    SoundEffects.SFX_ButtonClick.Play();
    ....
 }

Compile your project and you’re good to go! You can find the SoundEffects class in its entirety right here.

Key Points:

1) SoundEffect cannot play .mp3
I found this out the hard way. I kept running into debugging issues when I finally discovered that it will only accept .wav files. I was initially hesitant to use .wav due to the file size, but you can easily adjust the compression settings from within visual studio.

2) I couldn’t find tutorials which illustrated how to use more than one sound  effect
So I wrote this one. Any questions, comments, or other things you’d like to see? Let me know!

Additional Resources

http://www.freesound.org/ – Free sound effects and audio clips

-----------------------


subscribe-to-youtube

6 thoughts on “[Tutorial] Playing sound effects through Windows Phone 8

  1. Hello Dave,

    thank you for this great tutorial. I tried your code, but I always get an “ArgumentException” at the line:
    “sfx_ButtonClick = SoundEffect.FromStream(info.Stream);”

    I guess there is something wrong with my .wav-File, do you have to change something at it’s properties-panel, maybe the build action, or so?

    Thank you,

    • I’m sorry for the delay! WordPress never notified me about this comment, otherwise I would have gotten to it sooner!

      I have the code for my phone project on my GitHub, here:

      https://github.com/DaveVoyles/DataBoundApp3

      Hopefully that can help you out a bit, so that you can see exactly how I integrated it.

      Other than that, I’m really not quite sure to tell you the truth. I wish I could have been more helpful.

    • I’m sorry Chris, I’m not quite sure.

      I would suggest doing something like a check to see if the sound effect instance is null. So:

      If (sfx_buttonClick == null){
      // Do something
      }

  2. Hello mr. Voyles. I found your site after searching for how to implement audio in my WP8-app. I might be using the wrong words when searching.. anyway your tutorial was the closest I came to understand my problem.
    I have an app which starts with a logo and title of the app. Here I have used a short tune (like a fanfare), then it loads a pivot-page when clicking on the logo. I have managed to play another tune in the background while “surfing” the pivot pages, however if I click on a button with a sound effect on one of the pivot-pages, the music in the background stops.. And I have found no way around this..
    Will you please help me in the right direction?

    • Hello Stolt — It sounds like the sound effect is being cleaned up with the garbage collector every time you change the page.

      I would suggest setting that sound effect as a “watch variable” or “local” in your Visual Studio debugger and see what happens when you switch pages. Have you set a break point for the function that is called when you switch pages, and stepped through that?

Leave a Reply