Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous

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.

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster