FMOD Engine User Manual 2.03

5. White Papers | 3D Sounds

3D Sounds

This section will introduce you to using 3D sound with the Core API. With it, you can easily implement interactive 3D audio and have access to features such as 5.1 or 7.1 speaker output, and automatic attenuation, doppler and more advanced psychoacoustic 3D audio techniques.

For information specific to the Studio API and FMOD Studio events, see the Studio API 3D Events white paper.

Loading sounds as '3D'

When loading a sound or sound bank, the sound must be created with System::createSound or System::createStream using the FMOD_3D flag. ie.

result = system->createSound("../media/drumloop.wav", FMOD_3D, 0, &sound);
if (result != FMOD_OK)
{
    HandleError(result);
}

It is generally best not to try and switch between 3D and 2D at all, if you want though, you can change the Sound or Channel's mode to FMOD_3D_HEADRELATIVE at runtime which places the sound always relative to the listener, effectively sounding 2D as it will always follow the listener as the listener moves around.

Distance models and linear roll-off vs inverse

Inverse

This is the default FMOD 3D distance model. All sounds naturally attenuate (fade out) in the real world using an inverse distance attenuation. The flag to set to this mode is FMOD_3D_INVERSEROLLOFF but if you're loading a sound you don't need to set this because it is the default. It is more for the purpose or resetting the mode back to the original if you set it to FMOD_3D_LINEARROLLOFF at some later stage.

When FMOD uses this model, 'mindistance' of a Sound / Channel, is the distance that the sound starts to attenuate from. This can simulate the sound being smaller or larger. By default, for every doubling of this mindistance, the sound volume will halve. This roll-off rate can be changed with System::set3DSettings.

As an example of relative sound sizes, we can compare a bee and a jumbo jet. At only a meter or 2 away from a bee we will probably not hear it any more. In contrast, a jet will be heard from hundreds of meters away. In this case we might set the bee's mindistance to 0.1 meters. After a few meters it should fall silent. The jumbo jet's mindistance could be set to 50 meters. This could take many hundreds of meters of distance between listener and sound before it falls silent. In this case we now have a more realistic representation of the loudness of the sound, even though each wave file has a fully normalized 16bit waveform within. (ie if you played them in 2D they would both be the same volume).

The 'maxdistance' does not affect the rate of roll-off, it simply means the distance where the sound stops attenuating. Don't set the maxdistance to a low number unless you want it to artificially stop attenuating. This is usually not wanted. Leave it at its default of 10000.0.

Linear and Linear Squared

These are an alternative distance model that FMOD has introduced. It is supported by adding the FMOD_3D_LINEARROLLOFF or FMOD_3D_LINEARSQUAREROLLOFF flag to System::createSound or Sound::setMode / ChannelControl::setMode. This is a more fake, but usually more game programmer friendly method of attenuation. It allows the 'mindistance' and 'maxdistance' settings to change the attenuation behavior to fading linearly between the two distances. Effectively the mindistance is the same as the logarithmic method (ie the minimum distance before the sound starts to attenuate, otherwise it is full volume), but the maxdistance now becomes the point where the volume = 0 due to 3D distance. The attenuation in-between those 2 points is linear or linear squared.

Some global 3D settings

The 3 main configurable settings in the FMOD Engine that affect all 3D sounds are:

All 3 settings can be set with System::set3DSettings. Generally the user will not want to set these.

Velocity and keeping it frame rate independent

Velocity is only required if you want doppler effects. Otherwise you can pass 0 or NULL to both System::set3DListenerAttributes and ChannelControl::set3DAttributes for the velocity parameter, and no doppler effect will be heard.

It is important that the velocity passed to the FMOD Engine is in meters per second and not meters per frame. To get the correct velocity vector, use vectors from your game's physics code etc. Don't just subtract the last frame's position from the current position, as this is affected by framerate, meaning that the higher the framerate the smaller the position deltas and thus the smaller the doppler effect, which is incorrect.

If the only way you can get the velocity is to subtract this and last frame's position vectors, then remember to time adjust them from meters per frame back up to meters per second. This is done simply by scaling the difference vector obtained by subtracting the 2 position vectors, by one over the frame time delta.

Here is an example.

velx = (posx-lastposx) * 1000 / timedelta;
velz = (posy-lastposy) * 1000 / timedelta;
velz = (posz-lastposz) * 1000 / timedelta;

timedelta is the time since the last frame in milliseconds. This can be obtained with functions such as timeGetTime(). So at 60fps, the timedelta would be 16.67ms. if the source moved 0.1 meters in this time, the actual velocity in meters per second would be:

vel = 0.1 * 1000 / 16.67 = 6 meters per second.

Similarly, if we only have half the framerate of 30fps, then subtracting position deltas will gives us twice the distance that it would at 60fps (so it would have moved 0.2 meters this time).

vel = 0.2 * 1000 / 33.33 = 6 meters per second.

Orientation and left-handed vs right-handed coordinate systems

Getting the correct orientation set up is essential if you want the source to move around you in 3D space.

By default FMOD uses a left-handed coordinate system. If you are using a right-handed coordinate system then FMOD must be initialized by passing FMOD_INIT_3D_RIGHTHANDED to System::init. In either case FMOD requires that the positive Y axis is up and the positive X axis is right, if your coordinate system uses a different convention then you must rotate your vectors into FMOD's space before passing them to FMOD.

Note for plug-in writers: FMOD always uses a left-handed coordinate system when passing 3D data to plug-ins. This coordinate system is fixed to use +X = right, +Y = up, +Z = forward. When the system is initialised to use right-handed coordinates FMOD will flip the Z component of vectors before passing them to plug-ins.

A typical game loop

3D sound and the FMOD channel management system need to be updated once per frame. To do this use System::update.

This would be a typical example of a game audio loop.

do
{
    UpdateGame();       // here the game is updated and the sources would be moved with channel->set3DAttibutes.

    system->set3DListenerAttributes(0, &listener_pos, &listener_vel, &listener_forward, &listener_up);     // update 'ears'

    system->update();   // needed to update 3d engine, once per frame.

} while (gamerunning);

Most games usually take the position, velocity and orientation from the camera's vectors and matrix.

Stereo and multi-channel audio can be 3D!

A stereo sound when played as 3d, will be split into 2 mono voices internally which are separately 3d positionable. Multi-channel audio formats are also supported, so an 8 channel sound for example will allocate 8 mono voices internally in FMOD. To rotate the left and right part of the stereo 3d sound in 3D space, use the ChannelControl::set3DSpread function. By default the subchannels position themselves in the same place, therefore sounding 'mono'.

Split screen / multiple listeners

In some games, there may be a split screen mode. When it comes to audio, this means that the FMOD Engine has to know about having more than 1 listener on the screen at once. This is easily handled via System::set3DNumListeners and System::set3DListenerAttributes.

If you have 2 player split screen, then for each 'camera' or 'listener' simply call System::set3DListenerAttributes with 0 as the listener number of the first camera, and 1 for the listener number of the second camera. System::set3DNumListeners would be set to 2.

When using the Core, 3D Channels have the following behavior:

Speaker modes / output

To get 5.1 sound is easy. If the sound card supports it, then any sound using FMOD_3D will automatically position itself in a surround speaker system, and only the user has to be sure that the speaker settings in the operating system are correct so that the sound device can output the audio in 5.1 or 7.1. You do not need to set the speaker mode for FMOD.