Getting Started

FMOD Studio API

Firelight Technologies FMOD Studio API

Getting Started

Introduction

The FMOD Studio and Low Level API has been designed to be intuitive and flexible. In this section an introduction to using the engine as well as the key issues involved in using it effectively will be explained.

FMOD provides a C++ API and also a C API. They are functional identical, and in fact the C++ and C functions can be mixed interchangeably, with the C++ and C classes being able to be casted back and forth. The following examples only show the C++ version.

Initialization

FMOD Studio API Initialization

When using the Studio API, you can create a FMOD Studio System and then call Studio::System::initialize. That function will also initialize the in-built low level FMOD system as well. Here is a simple example:

FMOD_RESULT result;
FMOD::Studio::System* system = NULL;

result = FMOD::Studio::System::create(&system); // Create the Studio System object.
if (result != FMOD_OK)
{
    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
    exit(-1);
}

// Initialize FMOD Studio, which will also initialize FMOD Low Level
result = system->initialize(512, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, 0);
if (result != FMOD_OK)
{
    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
    exit(-1);
}

FMOD Low Level API Initialization (Do not use this if using FMOD Studio API Initialization)

The FMOD Low Level API can be used without needing to use the FMOD Studio API at all. Using the Low Level API gives access to the fundamental abilities of loading and playing sounds, creating DSP effects, setting up FMOD channel groups, and setting sample-accurate fade points and start/stop times. However, when just using the Low Level API, it will not be possible to load Studio banks or load and play Studio events that sound artists have set up in the Studio tool. To initialize FMOD Low Level directly:

FMOD_RESULT result;
FMOD::System *system = NULL;

result = FMOD::System_Create(&system);      // Create the main system object.
if (result != FMOD_OK)
{
    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
    exit(-1);
}

result = system->init(512, FMOD_INIT_NORMAL, 0);    // Initialize FMOD.
if (result != FMOD_OK)
{
    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
    exit(-1);
}

Advanced Initialization Settings

FMOD can be customised with advanced settings by calling System::setAdvancedSettings or Studio::System::setAdvancedSettings before initialization. For a description of the typical settings for effective virtual voices, see the Virtual Voice System.

Playing a sound (Low Level API only)

The simplest way to get started, and basic functionality of FMOD Low Level API - is to initialize the FMOD system, load a sound, and play it. All functions execute immediately, so the developer will either fire and forget during their main loop execution, or poll for the sound to finish. Playing a sound does not ‘block’ the application.

To execute a simple playSound

  1. Load a sound with System::createSound, using the system object handle as described above. This will return a ‘Sound’ handle. This is your handle to your loaded sound.
  2. Play the sound with System::playSound, using the Sound handle returned from Step 1. This will return a ‘Channel’ handle.
  3. Let it play in the background, or monitor its status with Channel::isPlaying, using the Channel handle returned from Step 2. A channel handle will also go immediately ‘invalid’ when a sound ends, when calling any relevant Channel based function, so that is another way to know a sound has ended. The error code returned will be FMOD_ERR_INVALID_HANDLE.

Using decompressed samples vs compressed samples vs streams

Decompressed Samples

The default mode for createSound is FMOD_CREATESAMPLE, which decompresses the sound into memory. This may be useful for distributing sounds compressed, then decompressing them at runtime to avoid the overhead of decompressing the sounds while playing. This can be expensive on mobile devices depending on the format. Decompressing to PCM uses litte CPU during playback, but also uses many times more memory at runtime.

Streams

Loading a sound as a streaming, gives the ability to take a large file, and read/play it in realtime in small chunks at a time, avoiding the need to load the entire file into memory. This is typically reserved for Music / Voice over / dialogue or Long ambience tracks. The user can simply play a sound as a ‘stream’ by adding the FMOD_CREATESTREAM flag to the System::createSound function, or using the System::createStream function. The 2 options equate to the same end behaviour.

Compressed Samples

To play a sound as ‘compressed’, simply add the FMOD_CREATECOMPRESSEDSAMPLE flag to the System::createSound function

Because compressed samples are more complicated, they have larger contexts to deal with (for example vorbis decode information), so there is a constant per voice overhead (up to a fixed limit) for a playing sound.
This allocation is typically incurred at System::init time if the user calls System::setAdvancedSettings and sets a maxCodecs value, or it could happen the first time a sound is loaded with the FMOD_CREATECOMPRESSEDSAMPLE flag. This will not be configured by the user so uses the default of 32 codecs for the allocation.

As an example: the vorbis codec has an overhead of 16kb per voice, so the default of 32 vorbis codecs will consume 512kb of memory. This is adjustable by the user to reduce or increase the default of 32, using the System::setAdvancedSettings function as mentioned. The user would adjust the FMOD_ADVANCEDSETTINGS maxVorbisCodecs value for the vorbis case. Other supported codecs are adjustable as well.

The best cross platform codec to used as a compressed sample is Vorbis (from an FSB file) but if it uses too much CPU for your platform (ie mobile), the FADPCM codec is a good second option. It is less compressed, and uses far less CPU cycles to decode, while giving good quality and 4:1 compression. For PS4 or Xbox One, it is better to use the AT9 and XMA codec format respectively, as the decoding of these formats are handled by separate media chips, taking the load off the CPU.

Update

FMOD should be ticked once per game update. When using FMOD Studio, call Studio::System::update, which internally will also update the Low Level system. If using Low Level directly, instead call System::update.

If FMOD Studio is running in asynchronous mode (the default, unless FMOD_STUDIO_INIT_SYNCHRONOUS_UPDATE has been specified), then the Studio::System::update will be extremely quick as it is merely swapping a buffer for the asynchronous execution of that frame's commands.

Shut Down

To shut down FMOD Studio call Studio::System::release. If using the Low Level directly, instead call System::release.

Error Checking

In the FMOD examples, the error codes are checked with a macro that calls into an handling function if an unexpected error occurs. That is the recommended way of calling FMOD Studio API functions. There is also a callback that can be received whenever a public FMOD function has an error. See FMOD_SYSTEM_CALLBACK for more information.

Configuration

The output hardware, FMOD's resource usage, and other types of configuration options can be set if you desire behaviour differing from the default. These are generally called before System::init. For examples of these, see Studio::System::getLowLevelSystem, System::setAdvancedSettings, Studio::System::setAdvancedSettings.

Avoiding stalls while loading a or releasing a sound

One of the slowest operations is loading a sound. To place a sound load into the background so that it doesn’t affect processing in the main application thread, the user can use the FMOD_NONBLOCKING flag in System::createSound or System::createStream.

Immediately a sound handle is returned to the user. The status of the sound being loaded can then be checked with Sound::getOpenState. If a function is called on a sound that is still loading (besides getOpenState), it will typically return FMOD_ERR_NOTREADY. Wait until the sound is ready to play it. The state would be FMOD_OPENSTATE_READY.

To avoid a stall on a streaming sound when trying to free/release it, check that the state is FMOD_OPENSTATE_READY before calling Sound::release.