This extension provides an interface to integrate a game with the adaptive audio engine FMOD Studio.
To use FMOD in your Defold project, add a version of the Defold FMOD extension to your game.project dependencies from the list of available Releases. Find the version you want, copy the URL to ZIP archive of the release and add it to the project dependencies.

Select Project->Fetch Libraries once you have added the version to game.project to download the version and make it available in your project.

The game will bundle fine, but in order for FMOD to be available when running
from the editor, an extra step is required.
The lib_path is parameter that takes a reference to the fmod/res directory of your library.
After fetching the library, unzip the extension inside .internal/lib/*/extension-fmod-0.1.0-alpha, and you’ll be able to reference it.
[fmod]
lib_path = .internal/lib/*/extension-fmod-0.1.0-alpha/fmod/res
Check if FMOD is available on your platform:
if not fmod then
-- Platform not supported, handle gracefully
return
end
Banks contain your audio events and metadata. Load the Master Bank and Master Bank.strings before loading other banks. The strings bank is required for event lookup by name.
fmod.studio.system:load_bank_memory(resource.load("/banks/Master Bank.bank"), fmod.STUDIO_LOAD_BANK_NORMAL)
fmod.studio.system:load_bank_memory(resource.load("/banks/Master Bank.strings.bank"), fmod.STUDIO_LOAD_BANK_NORMAL)
fmod.studio.system:load_bank_memory(resource.load("/banks/Vehicles.bank"), fmod.STUDIO_LOAD_BANK_NORMAL)
Load banks during initialization, ideally before creating any event instances. This ensures all required audio data is in memory when needed.
An event description represents a type of sound event, like an explosion or engine sound. An event instance is a specific playback of that event. You can create multiple instances from the same description.
Get the event description by its path as defined in FMOD Studio, then create and start an instance:
local event_description = fmod.studio.system:get_event("event:/Vehicles/Basic Engine")
local event = event_description:create_instance()
event:start()
You can store event instances (perhaps in your script’s self table) to keep them alive and control them throughout the game object’s lifecycle.
Events can be stopped immediately or allowed to finish naturally:
event:stop(fmod.STUDIO_STOP_IMMEDIATE) -- Stops instantly
event:stop(fmod.STUDIO_STOP_ALLOWFADEOUT) -- Stops with fade-out
When an event instance is no longer needed, call event:release() to free resources.
Events automatically release themselves when they finish playing, but explicit release is useful for long-lived instances you stop manually.
FMOD operations can fail. Use pcall to catch errors and check error codes:
local ok, err = pcall(function ()
local desc = fmod.studio.system:get_event("event:/Inexistent event")
end)
if not ok then
local code = fmod.error_code[err]
if code == fmod.ERR_EVENT_NOTFOUND then
-- Handle missing event gracefully
end
end
Common error codes include ERR_EVENT_NOTFOUND, ERR_INVALID_HANDLE, and ERR_NOTREADY. Validate operations that might fail, especially when loading banks or retrieving events.
FMOD supports 3D spatial audio with listener and emitter positioning. Set up both the listener, typically the camera or player, and source positions.
The listener represents where the audio is heard from. Create 3D attributes and update them in your update loop:
local listener_attr = fmod._3D_ATTRIBUTES()
listener_attr.position = go.get_world_position("listener") * world_scale
listener_attr.velocity = vmath.vector3(0.0)
listener_attr.forward = vmath.vector3(0.0, 1.0, 0.0)
listener_attr.up = vmath.vector3(0.0, 0.0, -1.0)
fmod.studio.system:set_listener_attributes(0, listener_attr)
Use a world scale factor like 0.01 to match FMOD’s coordinate system with Defold’s. FMOD expects distances in meters.
For 3D audio events, set their position attributes the same way:
local source_attr = fmod._3D_ATTRIBUTES()
source_attr.position = go.get_world_position("source") * world_scale
source_attr.velocity = vmath.vector3(0.0)
source_attr.forward = vmath.vector3(0.0, 1.0, 0.0)
source_attr.up = vmath.vector3(0.0, 0.0, -1.0)
event:set_3d_attributes(source_attr)
Update 3D attributes every frame in your update function. Calculate velocity from position delta for Doppler effects:
local function update_attributes(attr, dt, new_position)
local delta_pos = new_position - attr.position
attr.position = new_position
attr.velocity = delta_pos * (1.0 / dt)
end
function update(self, dt)
if not fmod then return end
local listener_pos = go.get_world_position("listener") * world_scale
update_attributes(self.listener_attr, dt, listener_pos)
fmod.studio.system:set_listener_attributes(0, self.listener_attr)
local source_pos = go.get_world_position("source") * world_scale
update_attributes(self.source_attr, dt, source_pos)
self.event:set_3d_attributes(self.source_attr)
end
The extension calls the underlying FMOD Studio update from native code each frame, so you do not need to call fmod.studio.system:update() manually.
Events can have parameters that control playback behavior, like RPM for engine sounds or intensity for ambience. Set parameters before or during playback:
event:set_parameter_by_name("RPM", 650.0, false)
The third parameter controls whether the change is immediate (false) or seeks to the new value (true). Use seeking for musical transitions. Immediate changes work better for gameplay-driven parameters.
Parameters can be marked as global in FMOD Studio. When global, setting that parameter affects all instances of events using it, not just one.
Event instances remain valid until they finish playing or are explicitly released. You can query their state:
local playing = event:is_valid() -- Check if instance is still valid
When an event finishes and reaches the end of its timeline, it releases itself automatically. For one-shot sounds, you typically don’t need to manually release. For looping or long-running events you control manually, call event:release() when done.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB