Introduction

The most exciting feature in DirectSound 9 is the possibility to move in the 3D space, the sounds and the points of listening. Audio is so important in applications such as videogames, that 3D audio is a godsend, especially because implementing 3D audio system with DirectSound 9 is very simple.

Requirements

To understand this tutorial, it is important to have familiarity with simple audio playback with Managed DirectSound 9 and with all the general concepts about Managed DirectX, so please read the previous tutorial about sound playback. In DirectSound 9 a sound source can be used in 3D only if it is mono. This is important because even a stereo file has ‘3D sound information’. If you try to use a non-mono file, DirectSound will raise an exception.

Using 3D audio sources and listeners

The technique is so simple that I will use only a paragraph to explain it. The first step is to create a Device and a sound, adding some new objects for this particular purpose:

The Buffer3D is the new buffer object that manages the 3D virtualization of the sound. This object can be moved in the space and its properties will be considered later. Listener3D is a point of listening and represents, obviously, a ‘human’ listener. This object can be moved in the space and has some cool options. Now you can proceed and create the objects:

It is better to select, when possible, the most powerful audio card, so use the overloaded constructor of Device, as shown in the previous tutorial. A note about d.Guid3DAlgorithm: this property specifies the algorithm the system will use to manage the 3D audio. There are various possibilities:

Guid3DAlgorithmDefault (audio card’s default, very easy)

Guid3DAlgorithmHrtfFull (max quality, even if a software emulation is needed)

Guid3DAlgorithmHrtfLight (less quality but less used resources)

Guid3DAlgorithmNoVirtualization (only left/right effects, perfect in bad systems or even with stereo-only outputs or if you don’t move the sounds vertically)

The next step is to create the 3D buffer:

sound3D = new Buffer3D(sound);
sound3D.Mode = Mode3D.HeadRelative;

The property sound3D.Mode specifies how the system will manage the 3D sound. There are three options:

Vector3 is a struct that represents one point in a 3D space. It is located inside the Microsoft.DirectX namespace. Now you have to play the sound and move it, or move the listener. Let's see some tricks.

Listener3D has these important members:

Position: the position (Vector3) of the listener.

Velocity: (vx, vy, vz) the instantaneous speed (Vector3) of the listener. You should use this when the listener is moving and you want to apply a Doppler effect.

Orientation: it is the ‘forward’ orientation of the listener. You have to set the Front and the Top directions using Vector3 objects. In this tutorial I set the Front to the positive Z axis, and the Top to the positive Y axis.

DistanceFactor: it is the measurement unit for the distances. 1 equals to a meter, so 0.001 equals to a millimeter.

RolloffFactor: the sound attenuation in the space (0 to 10, 1 is the default for real world).

DopplerFactor: the factor for the automatic Doppler effect (0 to 10, 1 is the default for real world). If you don’t know what the Doppler effect is, I'll explain it with an example: think of a car that is approaching you. The noise that the car produces when it approaches you is different from the noise that is produces when it goes away. This effect occurs in each type of wave phenomena, such as sound and light spreading.

Buffer3D has these members:

Play, Stop and so on are inherited from the Buffer and are equal to the SecondaryBuffer’s ones.

Position: the sound source position (Vector3), same as Buffer3D.Position.

MinDistance, MaxDistance: the first one is the distance from where the sound starts to attenuate, the second one is the distance from where the sound stops to attenuate. In other words, until MinDistance the sound is at its max volume, between MinDistance and MaxDistance the sound gradually attenuates, over MaxDistance the sound remains at a low volume and attenuates no more. For these options Listener3D.DistanceFactor and Listener3D.RolloffFactor matter! Unfortunately, the best way to understand the real behaviour of these parameters is to try and test them.

Velocity: the speed of the sound source, if it is moving, the same as Listener3D.Velocity.

ConeOrientation: (Vector3) this option allows you to specify the cone inside which the sound will spread. The Vector3 is the end-point of an imaginary line starting from the sound position, defining the orientation of the cone.

ConeAngles: (Angles) the angle for the inside cone and outside cone: inside the first one the volume will have maximum value, inside the second one the volume will attenuate progressively (see MSDN).

ConeOutsideVolume: specifies the volume outside the external cone described above.

There are no more interesting features to describe. See the attached demo app, that shows a moving sound source and a fixed listener. You can move the source with your mouse or make it rotate around the listener. As usual, I suggest going through the MSDN documentation: after you understand the main techniques, extending them is very simple.

Performances notes

We can say DirectSound is very fast. This statement is valid in most cases, but we need to describe some situations. For example if the audio card doesn’t support 3D sounds, DirectSound will emulate them via software. If the system (or the same app) does not have to perform other tasks, the user won’t notice the difference. But if you are developing a videogame, 3D sounds will load the CPU, slowing down the system. So make your choices right. In the demo app you may notice a little roughness of the source’s movements, even though the CPU load remains under 10%.

Conclusions

Now you should be able to manage sounds inside a 3D space. Personally, I believe it is very simple. In the next tutorial I will explain how to record sounds with DirectSound’s CaptureDevice.

I'm working on a tool that needs to exactly control the output from every single speaker in a 7.1 environment individually. DirectSound is the simplest possibility for 3d Sounds I've yet found but I can't figure out how to send the Sound to a single speaker...

Is there a way to make the change across the Y-axis less noticeable? On my system, moving X from 1 to 0 is very noticeable (immediate hard pan, try it in headphones), whereas moving from 1 to 2 is not noticeable at all. Is there a way to smooth out this behavior so it sounds more realistic?
Thanks.

Well, i'm trying to develop a little 3DSound app very similar to your Demo. My problem is the following.

I have to move Listener, not Sound sources. I try to code it myself.. but all I get is the same sound with no differents changing Listener object position. Then, I modified you demo to check what was happening.. and i've discover that there's the same problem. If you change listener.position instead of sound3d.position in demo.... the sound isn't affected.

Maybe it's necessary to configure any other Listener propierty?. I'd be very gratefull I you could help me. : )

I've been having the same problem in my own code. If I rotate the listener (orientation), it works. However, when I move him (translate) it doesn't affect volume or anything. I noticed that if I put in some code that moves each sound by a tiny bit (0.001) when I move the listener, then DirectSound seems to update everything, but if only the listener moves, nothing. This is very annoying. Any ideas?

Hello:
I've been able to immplement most of the 3d stuff in this article, but I'm having a hard time figuring out how to mute some of my 3d sounds. I know of the bufferdesc.Mute3DAtMaximumDistance, but this only works for software buffers. If using a hardware buffer, how does one mute 3d sounds, as the listener is walking away from an object.

I've never tried to do that... so, without any test, I suggest to you to use the SecondaryBuffer's Volume property: sound.Volume = -10000. -10000 mutes the sound.
So you have to check when the listener's distance from the source is what you need, and mute the sound.

If this doesn't work or it is too raw, I will need some time to investigate...