DirectSound:
3D Sound
By: Jack Hoxley
Written: June 2000
Download:
DS_3D.Zip
(14kb)
DirectSound3D is a fairly new
addition to DirectX, and is possibly one of the fastest developing areas of
technology (behind 3D). New 3D soundcards are coming out all the time, with
incredible sound quality. Sound has moved on from just squeaks and beeps. I
happen to own one of each of the main competitors (Aureal Vortex 2 and Creative
EAX) - playing games that support 3D and using 4 speakers is amazing; it adds
something to the game.
Anyway; Using DirectSound3D is
fairly easy; as most of it is automated - you set up the sound parameters, and
set where it's coming from in 3D space and it'll do the rest. Bare in mind that
it is hardware dependent - Although you dont need to enumerate for it's presence,
it wont really be in full effect unless the computer either has 2 speaker 3D
emulation or a full 4 (or more) speaker surround sound system. Also bare in
mind that setting a buffer to be 3D has performance costs; because of this you
should limit the number of 3D sounds, and give users the option of turning it
off - It could well make a difference, especially if the 3D calculations are
done by the processor (rather than hardware).
DirectSound3D can be combined
with Direct3D; which is often the case. Because they both use the same unit/coordinate
scheme it is easy to set a sound to come from a given place in your 3D world;
which adds to the atmosphere greatly. You will need to bare the following things
in mind when setting up your application
Coordinates
The coordinate system is the same for DirectSound as it is for Direct3D - X,
Y, Z. It is easily shown with this diagram:
In Directsound
3D, unless set otherwise, you (the listener) is positioned at 0,0,0 This means
that to get a sound in front of you it must have a +Z value; for it to be behind
you it must have -Z value. For it to be to the left it must be -X, to the right
it must be +X. To be above it must be +Y and below -Y. Of course, this all changes
when you start moving around...
Distances
The distance from the sound to the listener needs to be very small to be heard
properly. To be heard at a reasonable volume (when the normal volume is at Max)
it must be within 0.5 units of the listener. Anything more than 5 will be almost
silent. If the sound you are playing doesn't appear to be playing, it is quite
likely to be that it is too far away. If this system does not fit into your
3D world, you can quite easily add a multiplier or divider to increase/decrease
the value that you use.
And you will need to know what
these are:
DirectSound3DListener
This class represents you - the listener; and how the sounds are played.
In a typical 3D game, the position of the DirectSound3DListener would need to
be the same position as the player. This object also controls the amount of
Roll Off and Doppler effects of sound heard by the user, and other effects and
settings related to the environment. More on this in another Tutorial.
DirectSound3DBuffer
This object does all the 3D calculations for a sound. It attaches itself
to a normal sound buffer (with a normal wave file) and then modifies it. You
can use this object to set the sounds properties; including orientation, direction,
Velocity and position. The changes made here affect only this sound; whereas
changes in Directsound3DListener affect everything on a global scale.
Step1: Initialising Everything
This is very similiar to intialising a normal DirectSound program; except for
a few different variables and flags.
'We must always have the
root DirectX object
Dim Dx As New DirectX7
'DirectSound will be created by DirectX
Dim Ds As DirectSound
'This is where the sound is; and what we play
'to hear it
Dim DsBuffer As DirectSoundBuffer
'This does all the 3D calculations
Dim DsBuffer3D As DirectSound3DBuffer
'The primary sound buffer
Dim DsPrimary As DirectSoundBuffer
'This represents you.
Dim DsListener As DirectSound3DListener
'Although this says D3D at the beginning
'it is only used because it has all the right
'properties for us: X, Y, Z
Dim SoundPos As D3DVECTOR |
|
|
|
On Local Error Resume Next
Set Ds = Dx.DirectSoundCreate("")
'Tell the user we've got a problem
If Err.Number <> 0 Then
MsgBox "Unable to initialise; Either bad soundcard or bad drivers. Quiting"
End
End If
'Priority gives us greater control.
Ds.SetCooperativeLevel Me.hWnd, DSSCL_PRIORITY
'These two describe what our sound buffer will be
like
Dim primDesc As DSBUFFERDESC, format As WAVEFORMATEX
'Using the CTRL3D flag has speed penalties; dont use
it unless
'you have to - but you have to use it for 3D sounds...
primDesc.lFlags = DSBCAPS_CTRL3D Or DSBCAPS_PRIMARYBUFFER
'You can set the Stereo/Mono and Frequency settings
here
'and they will be applied to the primary buffer.
Set DsPrimary = Ds.CreateSoundBuffer(primDesc, format)
'Get a 3D listener device
Set DsListener = DsPrimary.GetDirectSound3DListener()
'The listener is at the 3D coordinate 0,0,0
'We set the sound to be front-left
'of the listener
SoundPos.X = -0.5: SoundPos.Z = 0.5
'0 is the loudest volume
DsBuffer.SetVolume 0 |
|
|
|
Step2: Loading and Setting
up
Now that we have everything initialised we can load some data into our buffer;
and set the options of our buffer.
Dim bufferDesc1 As DSBUFFERDESC
Dim waveFormat1 As WAVEFORMATEX
file = App.Path & "\tester.wav"
bufferDesc1.lFlags = (DSBCAPS_CTRL3D Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN
Or DSBCAPS_CTRLVOLUME) Or DSBCAPS_STATIC
Set DsBuffer = Ds.CreateSoundBufferFromFile(file, bufferDesc1, waveFormat1)
'The original buffer (above) must be created before this
'line; and the original buffer must have the CTRL3D flag present
Set DsBuffer3D = DsBuffer.GetDirectSound3DBuffer
'The angles define how sensitive the sound buffer
will be. A
'narrower cone will result in more sensitive.
'You can have 0 degrees for no cone
'You can have 360 degrees for a full sphere
'Or you can use any of these constants
'DS3D_MINCONEANGLE
'DS3D_MAXCONEANGLE
'DS3D_DEFAULTCONEANGLE - the default is 360 degrees
DsBuffer3D.SetConeAngles DS3D_MINCONEANGLE, 100, DS3D_IMMEDIATE
'the DS3D_IMMEDIATE makes Directsound stop and recalculate
ALL
'Directsound3D Buffers, coordinates and positions. If you use
'DS3D_DEFFERED flag, you can make several parameter changes before
'allowing DirectSound to recalculate everything. You have to call;
'DirectSound3DListener.CommitDefferedSettings before they take effect.
DsBuffer3D.SetConeOutsideVolume -400, DS3D_IMMEDIATE
DsBuffer3D.SetPosition SoundPos.X / 50, 0, SoundPos.Z / 50, DS3D_IMMEDIATE |
|
|
|
Now; If we play our DsBuffer
object we will be getting a 3D sound. Cones are quite important, and are discussed
in a later tutorial.
Step3: Positioning the sound.
Before this code is executed; you should set the sound to play looping. The
code is very simple; and is included in the example project. This next piece
of code will rotate the sound in a square about your position. If you listen
closely you will hear the sound go past you, behind you and to either side of
you.
Select Case CurrStage
Case 0 'Left
SoundPos.Z = SoundPos.Z - 0.1
If SoundPos.Z <= -0.5 Then
CurrStage = 1
End If
Case 1 'behind
SoundPos.X = SoundPos.X + 0.1
If SoundPos.X >= 0.5 Then
CurrStage = 2
End If
Case 2 'right
SoundPos.Z = SoundPos.Z + 0.1
If SoundPos.Z >= 0.5 Then
CurrStage = 3
End If
Case 3 'in front
SoundPos.X = SoundPos.X - 0.1
If SoundPos.X <= -0.5 Then
CurrStage = 0
End If
End Select
'The next line is a safety
net; to stop us changing stuff at the wrong times.
If DsBuffer3D Is Nothing Then Exit Sub
DsBuffer3D.SetPosition SoundPos.X, SoundPos.Y, SoundPos.Z, DS3D_IMMEDIATE
|
|
|
|
Although this tutorial has shown
you all the code needed, it is advisable to look at the demonstration program
- which will give you a better idea of how this works. You can get it from the
top of the page; or from my downloads page.
|