Audio Feedback the Easy Way

Adding audio feedback to a .NET 1.1 application was a bit of a nuisance — you had to use interop to call the Windows Multimedia or DirectSound APIs. You can find plenty of code for this if you search around; however, .NET 2.0 has an easier solution: the System.Media namespace. This new namespace provides you with several ways to play sound in your .NET applications with very little code, and without the need for any interop.

Playing System Sounds

The easiest entry point into System.Media is the SystemSounds class, which provides you with direct access to five of the sounds from the current Windows sound scheme:

  • Asterisk
  • Beep
  • Exclamation
  • Hand
  • Question

To play one of these sounds, you use a static method of the SystemSounds class to retrieve the appropriate SystemSound object, and then call its Play method. For example, to play the current default beep sound from your C# application you can use this line of code:

SystemSounds.Beep.Play();

System sounds are specified by the end user through the Sounds tab of the Sounds and Audio Device Properties control panel applet, as shown in Figure 1.

Playing Any .wav File

The main potential drawback to using the system sounds is that you can never be quite sure what sound you’re going to get (or indeed, if you’re going to get any sound at all). Because it’s up to the user to select, say, the default Question sound, you have no guarantee what that sound will be or whether it will be appropriate when your application wants to ask a question. That’s why the System.Media namespace also contains the SoundPlayer class, which provides a way to play any .wav file.

By default, the SoundPlayer class works asynchronously, using a background thread to do its work. The easiest way to use this class is to tell it where to find the sound that you want to play, and then to call its Play method, which plays the sound asynchronously. For example, you could use this code to play a sound:

SoundPlayer sp = new SoundPlayer();
sp.SoundLocation = "c:\windows\media\ding.wav";
sp.Play();

In addition to the Play method, the SoundPlayer class offers two other methods to play a sound after its location has been specified. You can call the PlaySync method to play the sound on the user interface thread (beware, though, that this will suspend updates to your application’s user interface while the sound is playing), or the PlayLooping method to play the sound continuously in a loop until the Stop method is called.

Pre-loading Sounds

The SoundLocation property isn’t limited to specifying disk files to play. You can also load sounds from a URL by specifying the URL as the SoundLocation. Alternatively, you can leave the SoundLocation empty and specify a Stream containing a .wav file in the SoundPlayer’s Stream property.

If you experiment with these alternative locations, particularly if you’re working with large .wav files, you’ll discover a small drawback to the Play method: it has to load the full sound file before playback begins. To work around this problem, you can use the LoadAsync method and an event callback to load the sound file before you try to play it.

To use this method, you need to first create your SoundPlayer method and hook up an appropriate event delegate. You might, for example, do this when you load a form:

private SoundPlayer spAsync = new SoundPlayer();
private void Form1_Load(object sender, EventArgs e)
{
   // set up event handler for async loading
   spAsync.LoadCompleted +=
      new AsyncCompletedEventHandler(spAsync_LoadCompleted);
}

Before you actually need to play the sound, call the SoundPlayer’s LoadAsync to load the file that you want to play:

spAsync.SoundLocation = "c:\windows\media\ding.wav";
spAsync.LoadAsync();

When the SoundPlayer finishes loading the sound, it will call the LoadCompleted delegate. Depending on your application flow, you might use this handler to play the sound, or to enable some piece of your user interface. You can use the IsLoadCompleted property to check whether any errors happened during the load:

// enable the play button when loading is finished
void spAsync_LoadCompleted(object sender, AsyncCompletedEventArgs e)
{
   if (spAsync.IsLoadCompleted)
      btnPlay.Enabled = true;
}

Using this method, you can be sure that a sound is ready to play when you want it, without an annoying delay.

A Note of Caution

Just because .NET 2.0 makes it easy to play sounds in your applications doesn’t mean you should go overboard. Remember, there are potential accessibility issues to depending solely on audio feedback in an application. Some users do not hear well; others may be working in a noisy environment, or running your application on a computer with no sound card or speakers. Still others find audio feedback just plain annoying. Take these factors into account when planning your sound use. At a minimum, you should use sound as one means of feedback, but not the exclusive means, especially for critical issues. If you do use sounds, it’s a good idea to provide an option to turn them off. Finally, it adds a bit of polish to your application to let the user choose their own sounds, rather than depending on the files that you choose to ship. .NET 2.0 makes the audio plumbing easy, but it’s up to you to design a system that makes good use of this new capability.

About the Author

Mike Gunderloy is the author of over 20 books and numerous articles on development topics, and the Senior Technology Partner for Adaptive Strategy, a Washington State consulting firm. When he’s not writing code, Mike putters in the garden on his farm in eastern Washington state.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read