FMOD native extension

Hi there!

After weighing in our options, we decided to use FMOD for our game, so I tried to make a proof of concept that it can be integrated with Defold.

Defold FMOD is the result of that work. It’s still quite experimental, mainly because Defold doesn’t officially support dynamic libraries (DEF-2732).

Github link
Asset portal link

Platform support is as such:

  • macOS & Linux: It works :tada:
  • Windows: It works, with a small workaround for running in the editor.
  • iOS: It works :tada:
  • Android: It (finally) works :tada:
  • HTML5: It works :tada:

On Windows MSVC crashes when compiling LuaBridge (lol).

Because of the above issues I think I’ll try compiling the bindings into a separate dynamic lib, which I will dlopen() from the native extension. (Because fetching all the FMOD symbols this way would be a pain in the ass and it’s easier to make a lib, link it with FMOD and expose a few entrypoint symbols to the NE).

I’m not sure what to do about the MSVC crash, though. Maybe the above approach might work by virtue of compiling the module with another version of MSVC.

20 Likes

I managed to make it work on Windows, Linux and macOS. To work around needing to bundle licensed FMOD headers, the extension is compiled separately as a static library (also, when compiling the Windows code on Defold’s build servers, MSVC crashed).

On Windows, this links directly to the FMOD DLLs and on macOS and Linux, the FMOD libraries are loaded at runtime with dlopen(). The macOS and Linux builds also intelligently figure out that they’re running in the editor (where the libs aren’t bundled) and look for the libs in the user’s project directory, in the dir specified in bundle_resources in game.project.

Next up, making the call to FMOD::System::setSoftwareFormat customisable and then expanding the exposed API surface.

10 Likes

Nice job!

2 Likes

Very interesting.

I give a try , as i know FMOD is able to read music modules (xm, s3m…).

It would be nice for my little game, as it would avoid converting 64kb modules to 4mb OGG files. (I could divide the size of my game by two, this way.)

5 Likes

So, now you can set the speaker mode (necessary for loading banks). Also, I managed to expose all the APIs in FMOD::Studio, minus the callbacks. I think this should be roughly enough for this extension to be useful. :microphone:

Before I’ll dig into the low level APIs, I should try to automate writing bindings, as the API surface is huge (especially for the low level API).

If you try it, please open issues if something seems wrong. There is a lot of glue code in this extension that I can’t possibly test on my own (since FMOD is so big). Also, if you have suggestions towards which parts of the low level API I should start with, fire away!

4 Likes

Awesome job.
We are soon starting to work on sounds for our game and I will definitely look into your FMOD extension and hope to at least give you feedback and suggestions.

5 Likes

Added iOS support and a config option to enable FMOD Studio’s live reload feature. Also, started using it in my own game and ironing out the bugs.

Update: Added HTML5 as well.

8 Likes

Good news! I got permission to distribute the FMOD libs alongside defold-fmod, which means installing the extension is a whole lot easier now. Also updated it for FMOD 1.10.03.

Don’t forget to remove the old fmod_stub approach from your project.

UPDATE: I also made it link at runtime on Windows, so no more weird system32 hacks.

12 Likes

I finally managed to make the time to make this work on Android :tada:. Also it how handles interruptions correctly on iOS.

7 Likes

When I find the time I’ll start toying with this for my game - awesome work!

1 Like

Only Studio API supported? The low level system is not supported?

Yeah. Only Studio API is supported for now. FMOD’s API has a huge surface area and adding bindings for it is a lot of manual work. A solution for the future would be to parse the headers somehow and generate the bindings, but If you feel like exposing the part of the API that you need yourself, feel free to submit a PR.

3 Likes

There’s actually several tools for this and I’ve been meaning to explore them, but never gotten around to it. I attended the 2016 LuaWorkshop in SF and there was a guy there who presented his findings on Lua binders (https://www.lua.org/wshop16.html#ThePhD and https://github.com/ThePhD/lua-bench). Sol2 was his solution: https://github.com/ThePhD/sol2

5 Likes

Why Studio::EventInstance::release not exposed? AFAIK this very important. One-shot event instances (for example, player jumps or gunshots, all created with slightly different pitch) should be released after usage.
And where is Studio::System::update method? According FMOD documentation, it is should be called every frame: “Updates the Studio System. This should be called once per ‘game’ tick, or once per frame in your application.”

Studio::System::update()is called automatically for you by the extension and release() functions are not exposed because references are counted and release() is called automatically when Lua garbage collects the last reference to your EventInstance.

6 Likes

I made an initial v1.0 release with a few maintenance changes:

  • Updated the FMOD libraries to 1.10.09
  • Recompiled the HTML5 libs with emscripten 1.38.12 (so that it works with Defold 1.2.139)
  • Made sure the HTML5 build is compatible with Chrome’s autoplay policy, by starting audio on the first click inside the canvas.
10 Likes

You are releasing a game on Steam in the future using this for audio?

I want to test using this for a big project in the near future.

Yes. We’re using it heavily for Interrogation, which we plan on releasing on Steam next year.

3 Likes

Could you give tips on best practices? How are your banks organized?

All the best practices for using FMOD Studio apply here. Check out their video tutorials. They’re pretty good. Their API docs (for the C++ Studio API) are also pretty helpful.

Banks are your “unit of loading”. We have one bank with common SFX that is always loaded, then a bunch of other banks that are loaded and unloaded on a per-scene basis, which contain the music and sfx for those scenes.

For Interrogation, for the case where multiple scripts might need the same bank, we have a “get_bank” and a “release_bank” that we use to reference count the banks.

2 Likes