|
Direct Sound Tutorial
| Version Compatibility: |
Visual Basic 5 Visual Basic 6
|
This code has been viewed 153397 times. DirectSound,
as the name suggests, plays sounds. It is mostly used for Sound Effects in games,
as it can handle more than one sound at a time ("Mixing"). You can
also gain more control of the users audio system through DirectSound, such as
panning and volume. There is now a sub section called DirectSound3D, this allows
you to specify an x,y,z coordinate for the sound to originate from, this only
really comes into use on a 4 speaker surround sound computer. 3D sound is best
used in First Person Shooters, where you can have explosions coming from above/below
left/right or all directions.
DirectSound
is incredibly important for games, many reviewers rate a game on it's 3D engine,
yet forget the sound. Listen to a game with the speakers off and you'll see
what a difference it makes.
As
with many of the other components of DirectX, they have limited use in Visual
Basic. There is very little support for true 3D positional Sound. This is mainly
to do with the language itself, Visual Basic was primarily a database tool (thats
why there are so many data orientated controls), because of this it was never
designed to be good at making games. Professional companies use C++ for games,
therefore DirectX has more support in C++ than Visual Basic.
This
tutorial will show you how to make a simple application that plays multiple
sounds at the same time. It will have options for panning (Left <-> Right)
and volume (You know this!).
The Code from this can then be added to any game where sound effects are needed.
First,
a few words:
BUFFER-These
hold the Sound Data
WAV FILE-This is the file type that DSound uses: *.Wav
Click
on The List to see the relevent section:
STARTING YOUR PROJECT
[top]
By now you should know how to start your project.
You
will also need some sounds to play, find some .Wav files (If you dont know of
any, use "find file" from the start menu). Copy TWO DIFFERENT files
into the folder where your project is, naming them Tester1.Wav and Tester2.Wav
Save
your project, and carry on with the tutorial.
˙
CREATING THE VARIABLES
[top]
There are very few variables in this project, but i need
to go over them. Add these lines into the (Declarations) section of Form1:
|
Option
Explicit˙˙˙˙
'This means that you have to define every variable, which is good
practise, and DirectX likes it more
Dim m_dx As New DirectX7˙
'This is the root DirectX object, DirectSound is created from this
object
Dim m_ds As DirectSound˙˙˙
'This is the directSound Object. Later on we will "Create"
it from the main DirectX Object
Dim m_dsBuffer(1) As DirectSoundBuffer 'Note:
This is an array, it isn't needed, but it makes programming this alot
easier. 'With it as it is, m_dsBuffer(0) will hold tester1.Wav and
m_dsBuffer(1) will hold Tester2.wav
|
As
you will see later on, each buffer will be called to play/stop it's contents.
˙
CREATING THE INTERFACE [top]
The interface, as you can see, is quite complicated. I
suggest going to the DOWNLOAD PAGE to get my pre-made copy, it'll make your
life a lot easier. The interface is designed will a set of controls for each
Buffer, and a final master set. The controls should be fairly obvious, but you'll
need to know all the names:
|
(1)
First off, create 2 frames, with any name. The first ones caption
should be "Volume" & the second "Panning"
(2) Then, within the first frame, add in two
scroll bars.
scrlTester1_Vol
˙˙˙˙ .Max=0
˙˙˙˙ .Min=-5000
˙˙˙˙ .LargeChange=20
˙˙˙˙ .SmallChange=255
scrlTester2_Vol
˙˙˙˙ .Max=0
˙˙˙˙ .Min=-5000
˙˙˙˙ .LargeChange=20
˙˙˙˙ .SmallChange=255
You can add the labels in if you want, but their
not really necessary.
(3) Next, in the second frame, create 2 more
scroll bars, like so:
scrlTester1_Pan
˙˙˙˙ .Max=10000
˙˙˙˙ .Min=-10000
˙˙˙˙ .LargeChange=1000
˙˙˙˙ .SmallChange=500
scrlTester2_Pan
˙˙˙˙ .Max=10000
˙˙˙˙ .Min=-10000
˙˙˙˙ .LargeChange=1000
˙˙˙˙ .SmallChange=500
(4) As a guide, use the picture to create the
main "Control Panel", give each button these names/captions
cmdTester1_Play
˙˙˙˙ .Caption="Play
Tester1.Wav"
cmdTester2_Play
˙˙˙ .Caption="Play Tester2.Wav"
cmdBoth_Play
˙˙˙ .Caption="Play Both"
cmdTester1_Stop
˙˙ .Caption="Stop Tester1.Wav"
cmdTester2_Stop
˙˙ .Caption="Stop Tester2.Wav"
cmdBoth_Stop
˙˙ .Caption="Stop Both"
cmdTester1_Pause
˙˙ .Caption="Pause Tester1.Wav"
cmdTester2_Pause
˙˙ .Caption="Pause Tester2.Wav"
cmdBoth_Pause
˙˙ .Caption="Pause Both"
(5) Then, the last part (phew!) is the Check
Boxes:
chTester1_Loop
˙˙˙ .Caption="Tester1.Wav
Loop"
chTester2_Loop
˙˙˙ .Caption="Tester2.Wav
Loop"
chBoth_Loop
˙˙˙ .Caption="Loop Both
Sounds"
|
You
should now have an interface.
Next,
We need to create the linking code. These are short portions of code that go
in each control to make it all happen. Remember, dont run the project whilst
adding these lines in, you'll get error messages about lots of things (Cos'
we 'aint finished the code yet!). The Code for the Scroll Bars will be covered
later on, as that needs a bit more detail.
Becase
you have added all the controls and names, Paste these parts into the relevent
places:
|
Private
Sub Form_Load()
˙˙˙ Me.Show
˙˙˙ On Local Error Resume Next
˙˙˙ 'First we have to create
a DSound object, this must be done before any features can be used.
˙˙˙ 'It must also be done before
we set the cooperativelevel or create any buffers.
˙˙˙ Set m_ds = m_dx.DirectSoundCreate("")
˙˙˙ 'This checks for any errors,
if there are no errors the user has got DX7 and a functional sound
card
˙˙˙ If Err.Number <> 0
Then
˙˙˙˙˙˙˙ MsgBox
"Unable to start DirectSound. Check to see that your sound card
is properly installed"
˙˙˙˙˙˙˙ End
˙˙˙ End If
˙˙˙ 'THIS MUST BE SET BEFORE
WE CREATE ANY BUFFERS
˙˙˙ 'associating our DS object
with our window is important. This tells windows to stop
˙˙˙ 'other sounds from interfering
with ours, and ours not to interfere with other apps.
˙˙˙ 'The sounds will only be
played when the from has got focus....
˙˙˙ 'DSSCL_PRIORITY=no cooperation,
exclusive access to the sound card
˙˙˙˙˙˙˙ 'Needed
for games
˙˙˙ 'DSSCL_NORMAL=cooperates
with other apps, shares resources
˙˙˙˙˙˙˙ 'Good
for general windows multimedia apps.
˙˙˙ m_ds.SetCooperativeLevel
Me.hwnd, DSSCL_PRIORITY
˙˙˙ LoadWave˙
'This sub is created later on, wait and see what it does.....................
End Sub
')))))))))))))))))))))(LOOPING
CODE)(((((((((((((((((((((((((((((((((((((((((((((
'I have grouped all these parts together, as
they are almost identical.
'In all 3 cases it checks if the checkBox has
been de-selected
'then, checks to see if there is anything in
the buffers (Has it been loaded yet?)
'Lastly, it stops the sound playing, and "Rewinds"
it back to the beginning.
'The
Buffer Check is an error handler, you cant modify the buffer if there
is nothing there
'It would cause an error if you attempt to stop
a buffer playing when
'it's empty......
Private Sub chBoth_Loop_Click()
If chBoth_Loop.Value = 0 Then
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1)
Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End If
End Sub
Private
Sub chTester1_Loop_Click()
If chTester1_Loop.Value = 0 Then
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
End If
End Sub
Private
Sub chTester2_Loop_Click()
If chTester2_Loop.Value = 0 Then
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End If
End Sub
'))))))))))))))))))))))))))(END
LOOPING CODE)((((((((((((((((((((((((((((
')))))))))))))))))))))))))))))))(PAUSING
CODE)(((((((((((((((((((((((((
'Again, i have grouped them together because
they are almost
'identical. The buffer.STOP function
pauses it. to stop it and put
'it back to the beggining you have to tell it
to (See later on). If you tell it to stop
'next time the user clicks play, it'll resume
from where it was........
Private
Sub cmdBoth_Pause_Click()
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1)
Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(1).Stop
End Sub
Private
Sub cmdTester1_Pause_Click()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
End Sub
Private
Sub cmdTester2_Pause_Click()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
End Sub
')))))))))))))))))))))))))(END PAUSING CODE)((((((((((((((((((((((((((((((((
')))))))))))))))))))))))))))))))(STOPPING)((((((((((((((((((((((
'Yet again, i've grouped them together.
'All
these subs do is stop the sound, then set it's position back to 0
(the beggining)
Private
Sub cmdBoth_Stop_Click()
If m_dsBuffer(0) Is Nothing And m_dsBuffer(1)
Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0˙
'This line could be changed to make it start in˙
'the middle of a sound file
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End Sub
Private
Sub cmdTester1_Stop_Click()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).Stop
m_dsBuffer(0).SetCurrentPosition 0
End Sub
Private
Sub cmdTester2_Stop_Click()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).Stop
m_dsBuffer(1).SetCurrentPosition 0
End Sub
'))))))))))))))))))))))))))))))))))))))))))))))))))(END
STOPPING CODE)((((((((((((((((((((((((((((((
|
This is all of the linking code for now, there is more later on, but this will
do for now. Remember, dont run the project, you'll get an error message if you
click on anything.
˙
CREATING THE LOADING PROCEDURE
[top]
The Next Step is getting it to load some data into the
Buffer. This is going to be in the sub "LoadWave", which was mentioned
in the Form_Load sub. Paste this code in to the sub:
|
Sub
LoadWave()
˙˙˙
Dim bufferDesc As DSBUFFERDESC 'a
new object that when filled in is passed to the DS object to describe
˙˙˙
'what sort of buffer to create, very similiar to DirectDraw's surface
descriptions
˙˙˙ Dim waveFormat As WAVEFORMATEX
˙˙˙
'These settings should do for almost any app....
˙˙˙ bufferDesc.lFlags = DSBCAPS_CTRLFREQUENCY
Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME Or DSBCAPS_STATIC
˙˙˙
waveFormat.nFormatTag = WAVE_FORMAT_PCM
˙˙˙ waveFormat.nChannels = 2˙˙˙
'2 channels
˙˙˙ waveFormat.lSamplesPerSec
= 22050 '22
hz (i think), only change this if you understand hertz etc.......
˙˙˙ waveFormat.nBitsPerSample
= 16˙
'16 bit rather than 8 bit (Better Quality)
˙˙˙ waveFormat.nBlockAlign =
waveFormat.nBitsPerSample / 8 * waveFormat.nChannels
˙˙˙ waveFormat.lAvgBytesPerSec
= waveFormat.lSamplesPerSec * waveFormat.nBlockAlign
˙˙˙
'this next line creates a buffer with the specified file in it, 'BufferDesc'
and 'waveformat'
˙˙˙ 'describe the properties
of the new buffer. they can only be modified when creating a new buffer...
˙˙˙
Dim sFile As String
˙˙˙ sFile = App.Path & "\tester1.wav"
'This
file should be in your projects folder......
˙˙˙ Set m_dsBuffer(0) = m_ds.CreateSoundBufferFromFile(sFile,
bufferDesc, waveFormat)
˙˙˙ sFile = App.Path & "\tester2.wav"
˙˙˙ Set m_dsBuffer(1) = m_ds.CreateSoundBufferFromFile(sFile,
bufferDesc, waveFormat)
˙˙˙ 'checks for any errors
˙˙˙ If Err.Number <> 0
Then
'basically, generate an error message if the number is anything but
0(0=no error)
˙˙˙˙˙˙˙ MsgBox
"unable to find " + sFile
˙˙˙˙˙˙˙ End
˙˙˙ End If
˙˙˙
'check the panning and volume "properties"
˙˙˙ scrlTester1_Pan_Change 'instead
of writing all the code out again, just call the
˙˙˙ scrlTester1_Vol_Change
'sub that it's in.........
˙˙˙ scrlTester2_Pan_Change
˙˙˙ scrlTester2_Vol_Change
End Sub
|
Note:
If you get an error message, but you know that the files are there, it could
be that they are in the wrong format. You cant tell the difference until you
try to load them, but some .Wav files are PCM format (Which is what DirectSound
wants) and others aren't. If this happens, select another sound file.
˙
MAKING IT PLAY SOMETHING
[top]
Now we're going to get a response from our program. I
am going to go over the code that goes into:
cmdBoth_Play
cmdTester1_Play
cmdTester2_Play
Open up the relevent windows, and paste in this code:
|
Private
Sub cmdBoth_Play_Click()
Dim flag As Long
flag = 0 'Set
the value to normal, then only change it if the checkBox is checked...
If chBoth_Loop.Value <> 0 Then flag =
1 'decide
whether or not too loop the sound
m_dsBuffer(0).Play flag
m_dsBuffer(1).Play flag
'When you type out "m_dsbuffer(*).play"
a menu will drop down with "DSBPLAY_NORMAL"˙
'and "DSBPLAY_LOOPING", The "flag
variable is the same, 0 = normal, 1=looping.
End Sub
'These
next 2 portions are almost identical....
Private Sub cmdTester1_Play_Click()
Dim flag As Long
flag = 0
If chTester1_Loop.Value <> 0 Then flag
= 1
m_dsBuffer(0).Play flag
End Sub
Private
Sub cmdTester2_Play_Click()
Dim flag As Long
flag = 0
If chTester2_Loop.Value <> 0 Then flag
= 1˙
m_dsBuffer(1).Play flag
End Sub
|
Ok,
so it's not really that complicated, but i thought i'd cover it in a seperate
section.
The Next section is a bit more interesting.
˙
ADDING IN VOLUME AND PANNING
[top]
The Volume is pretty simple, the panning is very useful.
If you are making a platformer game, you can use this to make a sound come from
the left or right of the player; adding a whole new dimension to the environment.
It is also very very simple.
You should already have set up the individual ScrollBars and their properties,
so open up the code window and enter this code:
|
Private
Sub scrlTester1_Pan_Change()
If m_dsBuffer(0) Is Nothing Then Exit Sub
'This line stops it changing anything on
'a buffer if it's empty.
m_dsBuffer(0).SetPan scrlTester1_Pan.Value
End Sub
Private
Sub scrlTester1_Vol_Change()
If m_dsBuffer(0) Is Nothing Then Exit Sub
m_dsBuffer(0).SetVolume scrlTester1_Vol.Value
End Sub
Private
Sub scrlTester2_Pan_Change()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).SetPan scrlTester2_Pan.Value
End Sub
Private
Sub scrlTester2_Vol_Change()
If m_dsBuffer(1) Is Nothing Then Exit Sub
m_dsBuffer(1).SetVolume scrlTester2_Vol.Value
End Sub
|
All
in all, extremely simple. BUT, you might have noticed the odd Maximum/minimum
settings for the controls. This is the only thing that you have to watch out
for,
Volume is -5000 (Mute) to 0 (Loudest). It is only a "percentage" of
the volume set in control panel. If the Volume is set low there, no matter what
you set the internal volume to be, it wont get any louder than this. Panning
is -10,000(Full Left) to 0(Center) to 10,000(Full Right). Ok, that's it! Have
fun.
OVERVIEW
Ok, so what have you just done?
You have made a program that stores a .Wav file in memory and the plays it back
at a set volume and audio balance(Panning).
Things to remember:
Storing files in memory takes up RAM, which is ok if you only have 5-6 small
sounds. If you are holding 10 or More Large sounds in memory, performance will
be very sluggish. At some point i will post a tutorial on streaming, which loads
a file as it plays it, instead of storing it in memory.
¸2000 Jack Hoxley -˙All rights
reserved.
The material on this page may be
reproduced as long as credit is˙given to myself
"Jack˙Hoxley"
The author can be e-mailed at jollyjeffers@greenonions.netscapeonline.co.uk.
His web site is http://members.dencity.com/dx4vb/
|