FMOD Engine User Manual 2.03
The Studio API and Core API are designed to be intuitive and flexible. This white paper contains an introduction to using both, and explains the key factors involved in using it effectively.
FMOD provides a C++ API and also a C API. They are functionally identical, and in fact the C++ and C functions can be mixed interchangeably, with the C++ and C classes being able to be cast back and forth. The following examples only show the C++ version.
Before anything else can be done with the FMOD Engine, it is necessary to initialize the studio system (if your game uses FMOD Studio) or core system (if it does not).
The Studio API can load FMOD Studio banks and can play events created by sound designers in FMOD Studio. When using the Studio API, you can create a studio system and then call Studio::System::initialize. That function will also initialize the in-built core 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 the Studio system, which also initializes the Core system
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);
}
The Core API can be used without needing to use the Studio API at all. Using the Core API gives access to the fundamental abilities of loading and playing sounds, creating DSP effects, setting up FMOD ChannelGroups, and setting sample-accurate fade points and start/stop times. However, when just using the Core API, it is not possible to load FMOD Studio banks or load and play events that sound artists have designed in FMOD Studio. To initialize the Core API 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);
}
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.
The simplest way to get started, and a basic function of the Core API, is initializing the Core API system, loading a sound, and playing it. All functions execute immediately, so you can either fire and forget a sound during main loop execution or poll for a sound to finish. Playing a sound does not block the application.
To execute a simple playSound
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.
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 behavior.
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.
FMOD should be ticked once per game update. When using the Studio API, call Studio::System::update, which internally will also update the Core system. If using Core API only, instead call System::update.
If the Studio API is running in asynchronous mode (the default, unless FMOD_STUDIO_INIT_SYNCHRONOUS_UPDATE has been specified), then Studio::System::update will be extremely quick, as it is merely swapping a buffer for the asynchronous execution of that frame's commands.
To shut down the Studio API, call Studio::System::release. If using the Core API only, instead call System::release.
In the FMOD examples, the error codes are checked with a macro that calls into a handling function if an unexpected error occurs. That is the recommended way of calling 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.
The output hardware, FMOD's resource usage, and other types of configuration options can be set if you desire behavior differing from the default. These are generally called before System::init. For examples of these, see Studio::System::getCoreSystem, System::setAdvancedSettings, Studio::System::setAdvancedSettings.
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.