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!