Multiple Sounds in WPF Application

So I’m making a small WPF game, which you can find here by the way 😛, and I come across a confusing and infuriating issue. WPF has two built-in audio players: SoundPlayer and MediaPlayer.

SoundPlayer: Can play audio files that are embedded resources in the application, however, this can only play one sound at once.

MediaPlayer: Cannot play audio files that are embedded resources in the application, however, this can play multiple sounds at once.

I think you can see the issue I was having. I wanted to play some background music in my game as well as some sound effects for certain actions in the game. This meant the easiest way to get this functionality was to use both of these options and save the background music to the local disk as a temporary file. Not as clean as I wanted, but it will do I guess 🤷‍♂️

First, I set up my SoundPlayer as this was the simplest one of the two. I created a new SoundPlayer object using the embedded resource:

private static readonly SoundPlayer _soundOne = new SoundPlayer(WPF.Properties.Resources.soundOne);

Then when I wanted this sound to play, I would simply use:

_soundOne.Play();

Simple enough for the SoundPlayer… Now we move onto the MediaPlayer.

First, I make sure that my audio file is set as an Embedded Resource under the Build Actions in the file’s properties in Visual Studio:

You can see from this, that I have a WAV file called “backgroundmusic.wav” which I need to save to disk, play continuously and then delete once the form is closed.

Now that we have done this, we can create the method for saving the embedded WAV file to the %temp% location on disk. This is how I did that:

public static void SaveMusicToDisk(){
    //This sets up a new temporary file in the %temp% location called "backgroundmusic.wav"
    using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundmusic.wav")){
        
        //This them looks into the assembly and finds the embedded resource
        //inside the WPF project, under the assets folder
        //under the sounds folder called backgroundmusic.wav
        //PLEASE NOTE: this will be different to you
        Assembly.GetExecutingAssembly().GetManifestResourceStream("WPF.Assets.Sounds.backgroundmusic.wav").CopyTo(fileStream);
    }
}

Great we have now saved the embedded resource to disk, how can we play this now? 🤷‍♂️

We play this by creating a new MediaPlayer object and using the temp file location to play the audio:

//Create a new MediaPlayer object
private static readonly MediaPlayer _backgroundMusic = new MediaPlayer();

public static void StartBackgroundMusic(){
    //Open the temp WAV file saved in the temp location and called "backgroundmusic.wav"
    _backgroundMusic.Open(new Uri(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav")));
    //Add an event handler for when the media has ended, this way
    //the music can be played on a loop
    _backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
    //Start the music playing
    _backgroundMusic.Play();
}

My BackgroundMusic_Ended method looks like this and just makes sure that the music is always restarted once it has finished:

private static void BackgroundMusic_Ended(object sender, EventArgs e){
    //Set the music back to the beginning
    _backgroundMusic.Position = TimeSpan.Zro;
    //Play the music
    _backgroundMusic.Play();
}

Now that the music is playing continuously on a loop, how do we stop the music, dispose of the object and delete the temp WAV file from disk?

To stop and dispose of the MediaPlayer object is pretty easy, you can use:

public static void StopBackgroundMusic(){
    //Stops the music 
    _backgroundMusic.Stop();
    //Disposes of the MediaPlayer object
    _backgroundMusic.Close();
}

Now we go about removing the WAV file from the disk as we don’t want this to remain on the user’s computer once they have exited the application:

public static void DeleteMusicFromDisk(){
    File.Delete(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav"));
}

DONE! ✔️

With all the above code and a little tinkering to fit your specific setup, you should be able to use multiple sounds at once without an issue. Enjoy!


Leave a Reply