libgdx and FMOD
(Warning: Technical gamedev post!)
I’ve been prototyping an integration of FMOD (through lwjgl) and libgdx over the last day, and it looks like these are the steps you need to do to get FMOD working in Java:
- Make sure you include
lwjgl-fmod
3.3.2+ as a dependency, e.g. in yourbuild.gradle
’s dependencies fordesktop
, and rebuild with gradle.
project(":desktop") {
apply plugin: "java-library"
dependencies {
implementation project(":core")
// ...
api "org.lwjgl:lwjgl-fmod:3.3.2"
}
-
Get a copy of
fmod.dll
andfmodstudio.dll
– these cannot be redistributed. It seems the best source for these are from the FMOD downloads under FMOD for Unreal >FMODStudio/Binaries/Win64/*.dll
for Windows. -
Put these
.dll
s in the root of yourdesktop
project. (There’s probably a better place to put these.) -
You can then use FMOD in your desktop application!
public class MyApplication {
static {
// all of this enables super memory debugging mode, that fails early if you're
// messing up memory allocation/deallocation
Configuration.DEBUG.set(true);
Configuration.DEBUG_FUNCTIONS.set(true);
Configuration.DEBUG_LOADER.set(true);
Configuration.DEBUG_STACK.set(true);
Configuration.DEBUG_MEMORY_ALLOCATOR.set(true);
Configuration.DISABLE_CHECKS.set(false);
Configuration.DISABLE_FUNCTION_CHECKS.set(false);
}
private static void check(int result) {
if (result != FMOD.FMOD_OK) {
throw new RuntimeException("unexpected error: " + result);
}
}
public void run() {
try ( MemoryStack stack = MemoryStack.stackPush() ) {
int result;
// create a new FMOD Studio System
long system;
{
PointerBuffer buf = stack.mallocPointer(1);
result = FMODStudio.FMOD_Studio_System_Create(buf /* out */, FMOD.FMOD_VERSION);
check(result);
system = buf.get(0); /* get the location of system */
}
System.out.println("system = " + system);
int maxchannels = 32;
int studioflags = FMODStudio.FMOD_STUDIO_INIT_NORMAL | FMODStudio.FMOD_STUDIO_INIT_LIVEUPDATE;
int flags = FMOD.FMOD_INIT_NORMAL;
result = FMODStudio.FMOD_Studio_System_Initialize(system, maxchannels, studioflags, flags, 0 /* null */);
check(result);
// load Banks from files
System.out.println("loading banks...");
for (String path : new String[] { "Master.bank", "Master.strings.bank", "Vehicles.bank", "SFX.bank" }) {
PointerBuffer buf = stack.mallocPointer(1);
result = FMODStudio.FMOD_Studio_System_LoadBankFile(system, path, FMODStudio.FMOD_STUDIO_LOAD_BANK_NORMAL, buf);
check(result);
System.out.println("loaded " + path);
}
// select an Event
long event;
{
PointerBuffer buf = stack.mallocPointer(1);
result = FMODStudio.FMOD_Studio_System_GetEvent(system, "event:/Vehicles/Car Engine", buf);
check(result);
event = buf.get(0);
}
// create a new Event instance
long eventInstance;
{
PointerBuffer buf = stack.mallocPointer(1);
result = FMODStudio.FMOD_Studio_EventDescription_CreateInstance(event, buf);
check(result);
eventInstance = buf.get(0);
}
// start playing the instance of the event
result = FMODStudio.FMOD_Studio_EventInstance_Start(eventInstance);
check(result);
// set a parameter on the instance
int ignoreseekspeed = 0;
result = FMODStudio.FMOD_Studio_EventInstance_SetParameterByName(eventInstance, "RPM", 2400, ignoreseekspeed);
check(result);
FMOD_3D_ATTRIBUTES attr3d = FMOD_3D_ATTRIBUTES.malloc(stack);
FMOD_VECTOR v = FMOD_VECTOR.malloc().set(0, 0, 0);
FMOD_VECTOR vListener = FMOD_VECTOR.malloc().set(0, 0, 0);
FMOD_VECTOR vVelocity = FMOD_VECTOR.malloc().set(0, 0, 0);
// Forwards orientation, must be of unit length (1.0) and perpendicular to up.
FMOD_VECTOR vForward = FMOD_VECTOR.malloc().set(0, 0, -1);
// Upwards orientation, must be of unit length (1.0) and perpendicular to forward.
FMOD_VECTOR vUp = FMOD_VECTOR.malloc().set(0, 1, 0);
float f = 0;
FMOD_3D_ATTRIBUTES attr3dListener = FMOD_3D_ATTRIBUTES.malloc(stack);
boolean running = true;
while (running) {
// update location of event instance to (x, 0, 0)
f = (f + 0.1f) % 5;
v.set(f, 0, 0);
attr3d.set(v, vVelocity, vForward, vUp);
result = FMODStudio.FMOD_Studio_EventInstance_Set3DAttributes(eventInstance, attr3d);
check(result);
// update location of listener to (0, 0, 0)
attr3dListener.set(vListener, vVelocity, vForward, vUp);
int listener = 0;
FMOD_VECTOR attenuation = null; // no idea what attenuation is
result = FMODStudio.FMOD_Studio_System_SetListenerAttributes(system, listener, attr3dListener, attenuation);
check(result);
// key call, should be called once per render frame
result = FMODStudio.FMOD_Studio_System_Update(system);
check(result);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// "The Studio System is shut down and released by calling Studio::System::release,
// make sure to call this before your game is exited."
result = FMODStudio.FMOD_Studio_System_Release(system);
check(result);
}
}
public static void main(String[] args) {
new MyApplication().run();
}
}
I haven’t yet tested how to correctly build and integrate this into the application, and how best to distribute an actual playable build to players – so this is still a work in progress.