|
Sound & Games
The Next Level
A Note On DirectX
The upcoming and long
anticipated release of DirectX7 by Microsoft will give VB
programmers the ability to easily access DirectX features including
DirectSound. When that happens you will have more options for
sound play without having to resort to third-party controls.
The techniques we will present here are still
functional and there may be times that you won't want to include
the huge DirectX Library if all you need is some basic sound play.
The EasySound control created by Soren Christensen will be introduced in this
tutorial. It uses DirectX and should still work unless changes are
made to the underlying COM
interfaces, which according to Microsoft's standards should not
happen. This means you can get DirectSound functionality in your
programs right now. Of course the new version of DirectX will probably
have features than were not available at the time that the
EasySound control was created. Once the final release of DirectX is
out I expect we will see a flood of samples and
tutorials as VB programmers begin to explore the exciting new possibilities.
Introduction
A game without sound is like a
hamburger without the meat -it may fill your stomach but leave
you feeling slightly dissatisfied. Picture yourself vaporizing
enemy ships and seeing a tremendous animated explosion with no
sound. Now picture the same game with the satisfying 'whump!' as
your missile hits the enemy vessel, and then hear the deafening
roar of its explosion vibrating in your bones -big difference
right?
So how do we add sound to our VB
games? There is no easy way to add advanced sound features to our
VB games. Not that adding simple sounds is impossible, but
typically today's games will mix several sounds -like a
background theme, as well as shots being fired and sprites
yelling all at once- that can't be performed easily. We will
present you with three ways that sound can be added to our VB
games; the Win32 API, a DLL and a custom control. We will discuss
all three of them in this chapter and try to point out some of
the strengths and weaknesses of each one.
Win32 sounds with sndPlaySound
The easiest way to play sounds
in VB is to use the Win32 API. The API has several functions,
which can play a sound for you. The simplest of these functions
is sndPlaySound. Let's take a closer look at it:
Declare
Function sndPlaySound Lib "winmm.dll" Alias
"sndPlaySoundA" _
(ByVal
lpszSoundName As String, ByVal uFlags As Long) As Long |
The first parameter, lpszSoundName,
is a string to the file, which should be played. The second
parameter, uFlags, is the flags parameter, which defines
how the sound should be played. The flags are combined using the
OR operator. The available flags are:
| SND_ALIAS = &H10000 |
lpszSoundNameis an event sound in the registry
|
| SND_ASYNC = &H1 |
Play the sound asynchronously |
| SND_FILENAME = &H20000 |
The lpszSoundName is a file, which will be
played |
| SND_LOOP = &H8 |
The sound is played continuously |
| SND_MEMORY = &H4 |
The lpszSoundName is a pointer to a memory
sound, which should be played |
| SND_NODEFAULT = &H2 |
If the sound is not found, the function does not
play the default sound |
| SND_NOSTOP = &H10 |
The sound will not be played is a sound is currently
being played |
| SND_SYNC = &H0 |
The sound is played synchronously and the function
does not return until playback has stopped |
As you can see from the SND_MEMORY
flag, we are able to use the function to play a sound that is
already loaded in memory. This is a very useful option as it can
yield slightly better performance than if you were to read the
file from disc.
The question then is how do we
load the sound into memory. This is actually quite simple. Since
the function expects a string parameter to represent the sound,
all we have to do is to load the sound from file and into the
string, which resides in memory. Then by specifying the
SND_MEMORY flag, the function will read the string in memory as a
sound.
The sample project, SNDSOUND in
the SNDSOUND directory of Chap2, demonstrates the playback of a
simple short wav file, both from file and from memory. To load
the file from disc and into memory we use the following function:
'Loads a sound from file into memory
Private Function LoadSound(FileName As String) As String
On Error GoTo Error_Handler
Dim FreeFileNumber As Integer
Dim SoundBuffer As String
FreeFileNumber = FreeFile
SoundBuffer = Space$(FileLen(FileName)) 'Make room for sound file
Open FileName For Binary As #FreeFileNumber
Get #FreeFileNumber, , SoundBuffer
Close FreeFileNumber
'remove wasted spaces
LoadSound = Trim$(SoundBuffer)
Error_Handler:
Select Case Err
Case 0 'No error
Case Else
MsgBox Err.Description & vbCrLf & "Error Number: " & Err.Number
Err.Clear
LoadSound = ""
End Select
End Function
|
The string variable, SoundBuffer,
will serve as a temporary buffer for the sound file. Using the
Space function supplied with the length of the file dimensions
the string variable.
We open the file in binary mode
and read the entire file into the SoundBuffer variable in one Get
operation. This variable is returned from the function after it
has been trimmed with the Trim function. We have included an
error handler scheme in this function, since we are working with
files. This handler will catch any errors that might occur, and
display an appropriate error message.
The code to play the sound is in
the Click event of the command buttons. For the Play from File
command button, the code looks like this:
Private Sub cmdFile_Click()
sndPlaySound SoundFile, SND_ASYNC Or SND_FILENAME
End Sub
|
The sound is played
asynchronously, which means that the function returns immediately
instead of waiting until the sound has finished playing. The flag
SND_FILENAME is also specified and thereby telling the
function that the SoundFile variable is a file on disc,
and it should be loaded into memory.
For playing the sound in memory:
Private Sub cmdMemory_Click()
sndPlaySound SoundInMemory, SND_ASYNC Or SND_MEMORY
End Sub
|
The SND_ASYNC is still
set, but instead of the SND_FILENAME we specify the SND_MEMORY
flag, which tells the function that the SoundInMemory
variable is a residing in memory.
To stop a sound from playing you
call the sndPlaySound again and pass 0 in both of the
arguments:
Private Sub cmdStopFile_Click()
sndPlaySound 0, 0
End Sub
|
As you can see from the sample
project then it is very simple to play a sound from Visual Basic
using this method, but it has its drawbacks too. The first and
most severe drawback is that you can only play one wave file at a
time using the sndPlaySound function. The second drawback
is that you have to think about the size of the sound file you
play with this function. Microsoft recommends that you do not use
the sndPlaySound function with wave files larger than 100
KB, which also limits the possibilities of this function.
The Media Control Interface
The MCI is an alternative to the
sndPlaySound function, which gives you a few more options
when playing a sound. It replaces the use of the sndPlaySound
function for wave files above 100 KB in size, but you still
cannot play two wave files simultaneously. This is also the
reason why we will not dwell around this interface, but instead
just quickly show you how to play a wave file and then move on to
something we can really use.
The MCI function is declared as
such (in Windows 95/98):
Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _
(ByVal lpstrCommand As String, _
ByVal lpstrReturnString As String, _
ByVal uReturnLength As Long, _
ByVal hwndCallback As Long) As Long
| Parameters: |
| lpstrCommand: |
The command message to send |
| lpstrReturnString: |
The variable to store the return string in |
| uReturnLength: |
The length of the lpstrReturnString variable |
| hwndCallBack: |
The address of the callback function. |
|
The most important parameter
here is the lpstrCommand parameter. This parameter
specifies the action, which the function will carry out. There
are many different kinds of commands and command attributes to
the function. Here we will just use the commands that will enable
us to play a simple wave file.
To open a wave file with the mciSendString
function you use the "OPEN file name TYPE WAVEAUDIO
ALIAS alias" command. The file name is the
filename of the wave file to open. The "TYPE WAVEAUDIO"
specifies that it is a wave file we are attempting to open. The
"ALIAS" is used to specify an alias for the wave file.
This alias is used when we want to play it.
To play a wave file we use the
"PLAY alias FROM start TO end"
command. The alias is the same as the alias we specified
in the open command. The "FROM" parameter specifies
where the function should begin playing in the wave file.
The sample project MCI, in the
MCI directory of Chap2 directory, demonstrates how to playback a
wave file and how to stop it from playing with the mciSendString
function.
NOTE: In order to use the
sample project copy the sound file "sound.wav"
from the MCI directory to the root of your hard drive. This is
necessary since the mciSendString function apparently does
not accept space in the string which specifies the file name.
There is much more to the mciSendString
function, but nothing really relevant for us as game programmers,
since it still does not allow us to play multiple wave files
simultaneously. So we will quickly end this section and jump to
something we can use.
[Sound & Games #1] [Sound & Games #2] [Sound & Games #3] [Download All Samples]
These tutorials were originally developed by
Soren Christensen and Burt Abreu as part of a book which we were working on.
The book idea didn't come to fruition and so we decided to post the completed
chapters here in the hopes that you would find them useful. We retain copyright
to this material and you may not reproduce it, post it, or otherwise disseminate
it in any fashion without our express written consent with the exception of making
copies for your personal use.
|