Playing Wave Sounds


The Win32 API provides high-level support for playing wave sounds, which is extremely good news for you and me. One drawback with the high-level wave support in the Win32 API is that it doesn't allow for wave mixing , which is the process of mixing wave sounds so that multiple sounds can be played at once. Unfortunately, this means that only one wave sound can be played at any given moment. You'll have to decide how you want this to impact your games because there are certainly going to be situations in which two or more sounds need to be played at once. You have the following options when it comes to resolving the problem of being able to play only one sound among several:

  • Interrupt the currently playing sound to play the next sound.

  • Allow every sound to play to completion, and reject sounds that attempt to interrupt the currently playing sound.

graphics/book.gif

Wave mixing is made possible by the DirectX game programming API, which I've mentioned a few times throughout the book. DirectX is incredibly powerful, especially when it comes to its digital sound capabilities, but it has a very steep learning curve. If you should decide to tackle DirectX after reading this book, by all means go for it. However, for the purposes of creating your own games without spending a great deal of time and energy learning the inner workings of DirectX, the high-level Win32 API approach to playing wave sounds is sufficient.


Until you actually experiment with these two wave playing approaches, you might think that the first approach sounds appealing because it gives every sound a chance to play. However, in some situations you'll find that sounds interrupting each other can be as annoying as a bunch of people interrupting each other in a heated debate. If you've ever seen the political television show Crossfire , you know what I'm talking about. On the other hand, when you let sounds play to completion, you will inevitably be disallowing other sounds their chance at playing ”some of which might be important to the game play. So, it ultimately depends on the kind of game as to whether it makes sense to interrupt sounds or allow them to play out.

Regardless of how you address the limitation of only being able to play one sound, the Win32 API function that makes wave playing possible is called PlaySound() , and it looks like this:

 BOOL PlaySound(LPCSTR szSound, HMODULE hModule, DWORD dwSound); 

The three arguments to the PlaySound() function determine a variety of different things such as whether the sound is being played from a wave file or from memory as a wave resource. Additionally, the function allows you to control whether a sound may be interrupted while playing, as well as whether it should be looped repeatedly. The next few sections examine the PlaySound() function in more detail, and show you how to control the playback of wave sounds.

Playing a Wave from a File

The simplest way to use the PlaySound() function is to play a wave file directly from the local hard drive. When playing a wave from a file, the first argument to the PlaySound() function, szSound , identifies the name of the wave file. The second argument, hModule , applies only to playing wave resources, so you can pass NULL as the second argument when playing wave files. The third argument, dwSound , is used to determine the specific manner in which the wave is played.

The dwSound argument can contain one or more of several different flags that control various facets of the wave playback. For example, the SND_FILENAME flag indicates that you're playing the wave from a file. There are two other flags, SND_SYNC and SND_ASYNC , that determine whether a wave is played synchronously or asynchronously. A synchronous wave is a wave that doesn't allow a program to resume operation until it finishes playing, whereas an asynchronous wave allows a program to continue its business while the wave plays in the background. As you might be guessing, synchronous waves are pretty much out of the question in games because you don't want the whole game to pause while a wave is playing. So, you'll need to use the SND_ASYNC flag when playing waves using the PlaySound() function.

Following is an example of playing a wave file using the PlaySound() function:

 PlaySound("Boo.wav", NULL, SND_ASYNC  SND_FILENAME); 

As you can see, this is a pretty simple line of code when you think about everything it is accomplishing. A wave file is being loaded from disk and played through the speakers on your computer while your program is allowed to continue operating.

Another PlaySound() flag worth mentioning is the SND_NOSTOP flag, which causes a sound to be more respectful of a sound that is already playing. More specifically , if you specify the SND_NOSTOP flag when playing a wave sound, the sound will not interrupt another wave if it is already playing. The downside to this flag is that the sound will end up never getting played. If you want to make sure that a sound is played no matter what, be sure not to specify the SND_NOSTOP flag. When you don't specify the SND_NOSTOP flag, the sound you're playing will interrupt the currently playing sound no matter what.

Playing a Wave from a Resource

Earlier in the hour , I mentioned that playing a wave sound as a resource has advantages over playing a wave file because you can combine the wave resource into the main program file. The PlaySound() function includes a flag that allows you to specify that you're playing a wave resource, as opposed to a wave file. The SND_RESOURCE flag indicates that the wave is a resource and that the hInstance argument to PlaySound() is a resource identifier. Because a wave resource must be loaded from an executable program file, you must provide the module handle for the program in the second argument to PlaySound() . The games and program examples you've seen throughout the book store away this handle in the _hInstance global variable.

Following is an example of playing a wave sound as a resource using the PlaySound() function:

 PlaySound((LPCSTR)IDW_BOO, _hInstance, SND_ASYNC  SND_RESOURCE); 
graphics/book.gif

Wave resource IDs are typically named so that they begin with IDW_ , which indicates that the ID is associated with a wave.


In this example, the resource ID of the wave sound is IDW_BOO , whereas the module handle of the program is the global variable _hInstance . Also, the SND_RESOURCE flag is used to indicate that this is indeed a wave resource, as opposed to a wave file. One important thing to note about this code is that it assumes you've already declared the IDW_BOO resource ID and placed a reference to the wave resource in the resource script for the program. Just as when you add new bitmaps to a game, you'll need to create a resource ID and an entry in the resource script for each wave sound you use in a game.

Looping a Wave Sound

In some situations, you might want to play a sound repeatedly. For example, if you opt to use sampled music in a game, it probably will make sense to use a wave sound that can be looped over and over and sound like one continuous piece of music. The PlaySound() function supports a flag for playing a wave sound looped, which means that the sound is played repeatedly until you interrupt it with another sound or until you explicitly stop it using the PlaySound() function (more on stopping waves in a moment). The flag to which I'm referring is SND_LOOP , and specifying it results in a wave being repeated over and over.

Following is an example of playing a looped wave resource:

 PlaySound((LPCSTR)IDW_BACKBEAT, _hInstance, SND_ASYNC  SND_RESOURCE    SND_LOOP); 

The SND_LOOP flag requires you to also use the SND_ASYNC flag because it wouldn't make sense to loop a sound synchronously. Keep in mind that a looped sound will continue to loop indefinitely unless you stop it by playing another wave or by stopping the looped wave with another call to PlaySound() .

Stopping a Wave Sound

If you ever use a looped wave, you will undoubtedly want to know how to stop it from playing at some point. Additionally, you might have a fairly lengthy wave sound that you'd like to be able to stop in case your game is deactivated or otherwise needs to slip into silent mode. You stop a wave from playing by using the SND_PURGE flag in the PlaySound() function. The SND_PURGE flag requires the first two arguments to PlaySound() to be used just as when you first played the sound. For example, if you provided a module handle as part of playing a wave resource, you'll still need to provide the handle when purging the wave.

Following is an example of stopping the looped sound played in the previous section:

 PlaySound((LPCSTR)IDW_BACKBEAT, _hInstance, SND_PURGE  SND_RESOURCE); 

This example reveals how to stop a single wave from playing. It's also possible to stop any waves from playing so that you don't have to be so specific about what you're doing. This is accomplished by passing NULL as the first argument to PlaySound() , like this:

 PlaySound(NULL, NULL, SND_PURGE); 

This line of code results in the currently playing sound being stopped , regardless of what it is and how it was played.



Sams Teach Yourself Game Programming in 24 Hours
Sams Teach Yourself Game Programming in 24 Hours
ISBN: 067232461X
EAN: 2147483647
Year: 2002
Pages: 271

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net