XTab's Blog

Ged Mead's Blog at vbCity

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login

JanFebruary 2010Mar
SMTWTFS
31123456
78910111213
14151617181920
21222324252627
28123456
78910111213

Archives

Topics

Ramblings

VB.NET

Introduction 

 You'll know by now that I'm quite a fan of WPF, but I have to say that my first excursion into using sound in a WPF application was a bit of a disappointment.  Rather frustrating too. 

 Maybe I expected too much, but I had this idea that the audio features would have been ramped up by the same kind of scale as the visual features have.  Sadly that's not quite the case and, although things have moved on a tad beyond having to use the  sound APIs directly in code, I still had to fiddle around more than I would have liked.

  But as I say, maybe I'm just becoming spoiled by the wealth of other WPF features.  

  Anyway, as I had to create a  test project to work out how I could get the sounds to play as and when I needed them, I thought I'd blog some of the results. 

  To keep this to a reasonable length, it will be more of a "here's how" approach than a "why it works that way" one.  Also I will be creating everything in code, not markup.  There are several more approaches and advanced techniques available via XAML that I won't be covering here.

PART 1  :  The SoundPlayer

1. Hard Coded File Path

  Starting with possibly the least realistic scenario, you can use the SoundPlayer to play a .wav file by pointing directly to a file via a hard coded path. 

Code Copy
Imports System.Media

    Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
        Dim player As New SoundPlayer("C:\Temp\4WAY.WAV")
        player.Play()
    End Sub
 

    Note the Imports statement at the top. 

    This wave file will play asynchronously (I do wish someone would come up with an easier to type word than that!  -  it's nearly as bad as 'concatenation' )   But I digress....

    If it's a particularly large wav file, you can help things out by inserting a Load statement after the initialization and before the Play fires.  This will tee the player up to play without any kind of pause while it cranks up the file.   This is something well worth bearing in mind as we users have become more and more impatient of delays.

2.  Use a Content File

   One particularly useful approach which gets around all the potential problems of hard coding file paths is to add the file to your Solution Explorer items.  You can do this with the standard "Add Existing Item" selection from the IDE menu, adding the wav file directly to the list of files for the Project. 

  This now brings me to Frustration #1.  First, here's valid code to play the sound using a SoundPlayer object:

Code Copy
    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button6.Click

        Dim player As New SoundPlayer
        player = New SoundPlayer("SND0103.WAV")
        player.Play()

    End Sub

   Now, before we move on, let's check the Solution Explorer:

     

    As you can see the file name is correctly entered and that file is sitting in the Solution Explorer's list of files that (you would think) it knows about.

   The key to fixing this problem is the 'Copy to Output Directory' Property.  By default, this is set to 'Do Not Copy'. 

 

 You need to change this to 'Copy Always' and you'll be back on track.

3. Audio File as Resource (Frustration #2)

   I wasn't going to include this option because it has generally caused me more trouble than it's worth (especially bearing in mind that there are several relatively trouble-free alternatives).  However, you can add a wav file as a Project Resource as normal and then play that Resource via a Stream.

   The syntax is:

Code Copy
  Private Sub btnResource_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnResource.Click
        Dim player As New SoundPlayer(My.Resources.canon)
        player.Play()

  End Sub

 

   Even with small, well tested files I often found that using this approach I would get a lot of unacceptable sound distortion (actually additional unrelated sounds to that expected).   I have tried it on several PCs,  each with different sound card configurations and the problems occur on them all.

5.  Other SoundPlayer Features

   In addition to the standard Play method, the SoundPlayer has a PlaySync method - in case you should rather unusually want the system to be locked until the sound has finished playing. 

  And finally if you want a sound to be repeatedly played, you can use the PlayLooping method to drive people mad; sanity can be restored by inserting the Stop method!

PART 2:  MediaPlayer and Media Element

    As you've already seen, the  SoundPlayer has some limitations.  It only understands wav format files and you can generally only play one wav file at a time (unless you start to get quite fancy with multithreading).  In many cases, the MediaPlayer or MediaElement will be a better option, but there is a good reason why I included the discussion of the SoundPlayer above.  In some situations on particular systems you will have  problems getting the  two Media components to work properly.  So it's always useful to know how to use the lighter weight SoundPlayer if you run into these problems in the future.

6.  But I Want to Play MP3 Files!

  -  or WMA or MID, etc. for that matter.  And this is a job for either the MediaPlayer or MediaElement.  Keeping to my approach of doing all the work in code, I'm therefore going to home in on the MediaPlayer.  (If you have a need to create a media object in XAML and have it play, pause, stop, trigger, etc, only in XAML then the MediaElement will be your tool of choice.)  

   Before abandoning the MediaElement approach altogether, I should point out that  you can create the MediaElement in XAML and then access it's properties and methods in code.   However, there is no advantage that I know of and in fact, the syntax is slightly more verbose and it also caused Frustration #4 - the fact that the audio file will only play once and then needs to be 'reset' by calling its Stop method; the Stop method apparently has the effect of returning the playhead to the beginning of the file.

  So let's look at the MediaPlayer in WPF.  It has an Open method which loads the file in the form of a URI.  This was Frustration #5 for me, as it took me a while to get past the problem of the "Value of Type 'String' cannot be converted to 'System.URI.'" error.  It took a lot more  than a quick search to finally discover that I needed simply to add the URIKind argument to the Open method; so the considerable amount of time I spent trying to do casts was wasted.   But maybe that's something I should have known. 

  It also has Play, Pause and Stop methods, plus the more sophisticated Balance and Volume properties.

  There is another small Gotcha involved in using this control.  Take a look at the following code snippet:

Code Copy


Dim mplayer As New MediaPlayer
mplayer.Open(New Uri("Godfather.mp3", UriKind.Relative))
mplayer.Play()

  

  It's hard to see anything wrong with that code snippet, but if you do try it you'll find that the audio will play for a short period of time and then - for no apparent reason - stop.   This is Frustration #6.

   As I understand it, what happens here is that the new MediaPlayer object is created, passed a URI for its source and then instructed to play.  Play begins but at that point seemingly the MediaPlayer closes itself, saying  "I've set the audio away, so my work here is done".  The end result is that at some unpredictable point in time the closed MediaPlayer is released from memory and will be disposed.  And of course as soon as it no longer exists there is no means for the sound to continue to be played.  So it stops in mid note!

   Anyway, having dragged you  laboriously through that explanation, you'll probably already have realised that the fix is simple.  All you need do is instantiate the MediaPlayer outside the scope of the click event so that the MediaPlayer will continue to exist throughout the lifetime of that Window or Page.  In other words, like this:

Code Copy
Class Window1
    Dim mplayer As MediaPlayer

  Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click

        mplayer = New MediaPlayer
        mplayer.Open(New Uri("Godfather.mp3", UriKind.Relative))
        mplayer.Play()

    End Sub

End
Class

 

  As with the SoundPlayer sample, the mp3 file has been added to the project files in Solution Explorer,  its Build property set to Content and its Copy To Output Director set to Copy Always.

  If the file is extra large and you get a pause before it actually begins to play then you can of course move the mediaplayer instantiation and Open code to, for instance, the Window Loaded event or some other place where the delay won't be so obvious.  It will then be teed up ready to go as soon as the Play method is invoked.

7.  Summary

   There isn't much else to add.  I think you now have the tools you need to  play sound and music files in WPF.  By the way, that does also mean both sounds and music at the same time, because you can have multiple instances of MediaPlayers running concurrently (or MediaPlayer(s) and a SoundPlayer running together).   Therefore  you can have almost any combination of sound files running, subject to the limitations of your system, that is.    

   I hope you will find this information useful in your future projects if you need to include sound and want to avoid the frustration of the learning curve.

  

   

posted on Tuesday, June 10, 2008 8:46 AM

Feedback

# Creating a Gadget style window with WPF and Visual Basic.NET 2008 6/29/2008 5:03 AM CanOz Blog


# Ged Mead on Windows Presentation Foundation 7/17/2008 6:18 AM Goto 100 - Development with Visual Basic
UK Visual Basic MVP Ged has been taking a look at WPF this year. I spotted his post on WPF Basics: How

# re: WPF Basics: How To Play Sounds and Music in Windows Presentation Foundation 10/15/2008 6:52 PM chaiguy1337
Another method that helped me out, if your sound file is compiled into the assembly as a WPF resource:

Uri uri = new Uri( @"pack://application:,,,/<assembly name>;Component/<path in assembly>/mySound.wav" );
mySound= new SoundPlayer( Application.GetResourceStream( uri ).Stream );
mySound.LoadAsync();
mySound.Stop();

Calling Stop() helps to precache the sound so that it starts immediately upon the call to Play(). LoadAsync doesn't seem to do this, and is probably not necessary but I threw it in anyway and it works fine.

#  C# ta ses dosyas? ?alma - Ceviz Forum 12/3/2008 2:21 PM Pingback/TrackBack
C# ta ses dosyas? ?alma - Ceviz Forum

# re: WPF Basics: How To Play Sounds and Music in Windows Presentation Foundation 1/31/2010 3:40 PM Mapquest driving directions
What is the best player?

Post Feedback

Title:
Name:
Url:
Comments: 
Protected by Clearscreen.SharpHIPEnter the code you see: