VB:Tutorials:WINAPI:Playing WAV Sound Files

From GPWiki

Files:GUITutorial_warn.gif The Game Programming Wiki has moved! Files:GUITutorial_warn.gif

The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server.

However, the GPWiki forums are still active! Come say hello.

So there you are, looking at a program you've made, thinking to yourself "Man I wish I could add a poignant little 'ding' when the user pushes this button!" Well my friend, won't you play with my ding-a-ling?

Shut up Ryan.

Ok ok, here's the API call you need to use to play wave files:

Private Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal _
    lpszSoundName As String, ByVal uFlags As Long) As Long

Aye, and what a bonny function she is! All you have to do to play a wave file now is tell the function what file you'd like to play (or in computer speak: ByVal lpszSoundName As String) and how you'd like to play it (ByVal uFlags As Long).

First things first. I'd like to play a wave file in my windows\media directory called ding.wav, so for the lpszSoundName argument I pass "c:\windows\media\ding.wav". It's as simple as that! If the ding.wav were in the same directory as my program, however, I would pass App.path & "\ding.wav" since this will work no matter where my program is, so long as ding.wav is in the same place. (App.path returns a string containing the path to the directory in which the application is running.)

Second things second. I'd like to play my wave file in a loop, how do I communicate that to the function? Well, most API calls come equipped with a few constants, and this function is no exception:

Const SND_ASYNC = &H1
Const SND_LOOP = &H8
Const SND_NODEFAULT = &H2
Const SND_SYNC = &H0
Const SND_NOSTOP = &H10
Const SND_MEMORY = &H4

To play my wave file in a loop, all I have to do is declare the SND_LOOP constant in my declarations section and then pass SND_LOOP as my uFlags argument. So, the final function call would look something like this:

sndPlaySound App.path & "\ding.wav", SND_LOOP

A loop isn't the only method for playing a wave file, however. As you can see, there are more constants yet unexplained:

SND_ASYNC 
Allows us to play waves with the ability to interrupt currently playing waves. By that I mean that we can play our wave at any time and ensure that it will be heard.
SND_NODEFAULT 
Ensures that if the wave file specified cannot be found then no other sound will be played in it's place (like some default windows noise!).
SND_SYNC 
Plays a wave file, but does not return control to the program until the wave file has finished playing. This is very annoying if all we were interested in was playing a sound in the background of our program.
SND_NOSTOP 
Ensures that if a wave file is already playing, our wave file will not interrupt it. Use this if you want to ensure that your waves are never cut short.
SND_MEMORY 
Plays a wave file that is already stored in memory. The routine to store a wave file in memory will not be shown here, but it simply involves storing the wave in a string using a get command (be sure to size the string properly first) and passing that string as the argument.

If we wish to use more than one of these constants in conjunction, we link them with an OR statement so that both constants will have an effect. For example, it is best to use SND_ASYNC along with SND_LOOP to ensure that the program can continue functioning while the looped wave file is playing. If we used SND_SYNC with SND_LOOP, we would never get control back to our program! Example:

sndPlaySound App.path & "\ding.wav", SND_ASYNC or SND_LOOP

That's all there really is to know about playing wave files using the windows API. For advanced sound functions, we shall turn to the DirectSound component of DirectX.

To download sample source code using the principles discussed here click here.