DirectXAudio:
DirectSound3D
Author:
Jack Hoxley
Written: 27th January 2002
Contact: [EMail]
Download: AUD_03.Zip
(32kb)
Contents
of this lesson
1. Introduction
2. Setting up DirectSound3D
3. Optional Parameters
1.
Introduction
So
far in this series I've covered simple playback
of sound effects, and background music. This is
all fine for a simple game, but for those that
want a rich, lifelike and immersive environment
in their games this is just not going to cut it.
Stereo sound effects are okay upto a certain point,
but what we really need is full-on 3D sounds,
we may have hi-poly graphics engines, but without
the sound effects to match this really isn't that
impressive.
With
3D sound effects, we can simulate sounds all around
the user, even as key features (drawing attention
to a particular area) - and in the heat of the
action (say, Unreal Tournament) it can give the
player critical information (location of friends/foes,
explosions, rockets, gunfire etc...). However,
this all comes with two downsides (doesn't everything!).
Firstly, 3D sound playback is more complicated
than traditional playback and only the newer hardware
cards can really perform adequately. Secondly,
it only comes into it's own with 4 or more speaker
configurations - 2 speaker emulation isn't bad,
but when you've experience full 4-speaker surround
sound it pales in comparison.
2.
Setting up DirectSound3D
I'm
going to assume that you've already read the first
DirectSound tutorial,
because once you've got that under your belt,
implementing 3D sound effects isn't that hard
really. However, because it is easy to set up,
dont get carried away with 3D sound effects. Every
sound buffer that you make a 3D sound will add
an overhead for everytime it is played - basically,
only make a sound 3D if the user is going to benefit
from it. Another aspect of this is that some drivers
will only permit a limited number of 3D buffers
to be created at any one time, and almost all
drivers will restrict the number of 3D buffers
that can be played at the same time (usually 8-16
playing, 32-64 created).
The
first stage is to add some new variables and objects:
Dim
DSBuffer As DirectSoundSecondaryBuffer8
Dim DSBuffer3D As DirectSound3DBuffer8
Dim DSBListener As DirectSound3DListener8 |
|
|
|
Only
the last two should actually be new to you. The
second one is a 3D representation of the original
buffer. We still store our audio data in a normal
DirectSoundSecondaryBuffer8 object, we just use
the DirectSound3DBuffer8 object to hold the various
3D parameters and settings (as well as doing some
of the internal processing I'm guessing), therefore
we need a pair of these objects for every sound
that we want to make 3D. The third object is a
"listener" - representing the player,
using this interface we can set what speed and
direction the player is going, and various other
unique parameters (more later). There can only
be one active listener object at any one time.
The
second stage is to create the sound buffer. This
comes in two sections - first we create the normal
sound buffer (as we did before), and then we aquire
a 3D sound buffer interface from it.
If
Not (DSBuffer Is Nothing)
Then DSBuffer.Stop
Set DSBuffer = Nothing
DSBDesc.lFlags
= DSBCAPS_CTRL3D Or
DSBCAPS_CTRLVOLUME
Set
DSBuffer = DS.CreateSoundBufferFromFile(App.Path
& "\blip.wav",
DSBDesc)
If
DSBDesc.fxFormat.nChannels
> 1 Then
MsgBox "You can
only use mono (1 channel)
sounds with DirectSound3D,
please change the
input file",
vbCritical, "error"
End If
'CREATE
THE 3D INSTANCE:
If optLow.Value Then
DSBDesc.guid3DAlgorithm
= GUID_DS3DALG_NO_VIRTUALIZATION
If optMedium.Value
Then DSBDesc.guid3DAlgorithm
= GUID_DS3DALG_HRTF_LIGHT
If optHigh.Value Then
DSBDesc.guid3DAlgorithm
= GUID_DS3DALG_HRTF_FULL
Set
DSBuffer = DS.CreateSoundBufferFromFile(App.Path
& "\blip.wav",
DSBDesc)
Set
DSBuffer3D = DSBuffer.GetDirectSound3DBuffer()
|
|
|
|
Not
too complicated really, the three main areas you
need to pay attention to:
Adding the DSBCAPS_CTRL3D is very important, you
wont be able to aquire the 3D instance later on
if you dont specify this parameter. Secondly,
dont add a DSBCAPS_CTRLPAN option - if you think
about it, panning has no meaning in a 3D representation,
so it's not allowed.
We must only use mono (single channel)
sound effects - as tested for by the logic just
after creating the buffer. As with panning, a
stereo (dual channel) sound effect has no meaning
in a 3D representation. The sound is coming from
a point in 3D space, so where (in the general
case) are the two channels going to come from?
The level of 3D Algorithm - as shown in
the DSBDesc.guid3DAlgorithm parameter. The first
(_NO_VIRTUALIZATION) uses the CPU only, and should
work on all systems, but the effect is minimal
and lots of corners are cut to improve speed.
The second (_HRTF_LIGHT) uses a mix of CPU and
sound card hardware, ie, where possible it'll
make use of available hardware, but it'll still
use the CPU to fill the gaps. This is slightly
higher quality. The third (_HRTF_FULL) is the
best, but will only work properly if you have
3D hardware (or a sound card driver that'll emulate
it). With the higher-spec sound cards the amount
of factors that are considered when playing sounds
is quite silly really - but the end result is
a very realistic audio reproduction.
At
this point we have our 3D sound ready, and we
can begin some basic playback (we haven't set
up enough parameters to get proper yet). There
is one last part to initialise - the listener
object. It is not really required that you have
a listener object, as DirectSound will set up
a default set of parameters for you. This tends
to be okay for sample programs, but in a proper
game this is a waste of time - your player position,
direction and velocity will very rarely match
that of the default configuration.
'CREATE
THE LISTENER OBJECT:
DSBDesc_2.lFlags = DSBCAPS_CTRL3D
Or DSBCAPS_PRIMARYBUFFER
Set DSBPrimary = DS.CreatePrimarySoundBuffer(DSBDesc_2)
Set
DSBListener = DSBPrimary.GetDirectSound3DListener
'CONFIGURE
THE LISTENER:
DSBListener.SetOrientation
0#, 0#, 1#, 0#, 1#,
0#, DS3D_IMMEDIATE
|
|
|
|
Not
to complicated really. We need to create a primary
buffer first - but once we have the listener object
we can discard the primary buffer (unless you
want to keep it). A quick note on the "apply
flags" (DS3D_IMMEDIATE in this case); every
parameter in DS3D tends to have this parameter
- there are two choices: immediate or deffered.
In the sample code I've left it at DS3D_IMMEDIATE
(makes the changes straight away), but the deferred
option may suit your situation better. Deferred
parameter changes will not be applied until you
call CommitDeferredSettings( ), this allows you
to apply several different changes all at the
same time - which in some cases will reduce the
number of calculations and changes required internally
(using immediate lots of time very quickly can
slow down due to it repeating the same/similiar
changes).
The
last line sets up the orientation of the listener
- the first 3 parameters indicate the direction
the player is facing, the second 3 parameters
indicate the "up" direction. These two
vectors must be at right angles to each other,
or DS3D will change it. This sample code has left
the listener at the origin, but you can (and probably
will want to) change the position of the player,
as well as it's velocity.
We
now have a fully set-up DirectSound3D application,
I've ommitted some bits of code that were in the
original tutorial, but you can find them in the
downloadable source code.
3.
Optional Parameters
There
are quite a few parameters that can be changed
in individual 3D sounds, and in the general listener
object - here is a quick round up of the important
ones:
Volume:
Volume is a fairly simple feature - and is done
in the same way that we used in the first tutorial.
Here is the code from the sample program:
If
DSBuffer Is Nothing
Then Exit Sub
DSBuffer.SetVolume scrlVolume.Value |
|
|
|
Just
remember how the volume is configured - as attenuation
in decibels (thus 0=load, -3000=quiet).
Position:
Position is an important feature - why else
use 3D sound? You can set the position of the
listener and the sound effect using these two
functions. The sample code uses a form of 2D polar
coordinates to move the sound around on the xz
plane.
DSBuffer3D.SetPosition
Src_X, 0, Src_Y, DS3D_IMMEDIATE
DSBListener.SetPosition
Src_X, 0, Src_Y, DS3D_IMMEDIATE
|
|
|
|
The
coordinate system used by DirectSound can be changed,
but by default it uses the same system as Direct3D
- which makes things pretty easy to match up.
Velocity:
velocity indicates the speed and direction that
the sound source is travelling - BUT it does not
actually change the position of the sound. In
the real-world, you will have noticed that a car
zooming past makes a different sound to a stationary
car - the sound is slightly blurred/stretched.
In conjunction with the doppler effect, DirectSound3D
uses the velocity to apply a blurring/stretching
effect to the sound when it is played. It is often
a subtle effect and not always noticable.
DSBuffer3D.SetVelocity
X, Y, Z, DS3D_IMMEDIATE
DSBListener.SetVelocity
X, Y, Z, DS3D_IMMEDIATE |
|
|
|
Doppler
Effect:
As already mentioned, the doppler effect distorts
sound based on the direction they are travelling
in, and the speed they are travelling at. The
doppler parameter is for the listener only, as
it is a global parameter. You can only specify
values on scale of 0.0 to 10.0, with 1.0 being
a real-world doppler effect, 2.0 being double
the doppler effect of the real-world, and 0.5
being half the doppler effect. 0.0 indicates no
doppler effect.
DSBListener.SetDopplerFactor
CSng(scrlDoppler.Value),
DS3D_IMMEDIATE |
|
|
|
Rolloff
Effect:
rolloff is how the sound attenuates with distance
(louder when close, quieter when further away).
As with the doppler factor, it is a multiple of
the real-world attenuation conditions, and is
a global parameter. You can use this parameter
to simulate different atmospheres (alien worlds
etc...), setting it to a high (5.0-6.0) value
will make sound drop away very quickly, giving
the impression of a very flat, stuffy and dull
atmosphere.
DSBListener.SetRolloffFactor
CSng(scrlRolloff.Value),
DS3D_IMMEDIATE |
|
|
|
Distance:
The maximum distance that a sound can be heard
at is a very useful parameter. By default, DirectSound
sets this to 1 billion units; and while you can
never really hear a sound more than 200 units
away, it does mean that DS3D will still be processing
a playing a sound - which can be an unnecessary
overhead. if you set this value to be much closer
then you can cut out processing of sounds that
are too far away.
DSBuffer3D.SetMaxDistance
250, DS3D_IMMEDIATE
DSBuffer3D.SetMinDistance
0.01, DS3D_IMMEDIATE |
|
|
|
Rolloff
factor is dependent on these parameters; sounds
closer than the minimum distance wont get any louder,
and likewise tend towards 0 at the maximum distance.
There,
that should be all you need to set up some simple
3D audio effects. The ultimate in 3D sound effects
will also implement echoes, reverb and other environmental
effects - something that I intend to cover later
in the series.
I
missed out quite a bit of code (that wasn't directly
relevent to the discussion), so I strongly suggest
you download the source code from the top of the
page, or from the downloads
page.
|