Alex Epton

INTERACTIVE AUDIO



Musical Callbacks usingFMOD and Command Instruments:



what if we could keep track of what key the music is in , then play an event from unity that corresponds with that key

Techniques


one way to accomplish this with FMOD and unity is to go into the low level code to get FMOD timeline callbacks. the typcal use case for this is for rhythmn games and it is covered in the FMOD documentation [here](https://www.fmod.com/docs/2.00/unity/examples-timeline-callbacks.html) using the timeline callback technique you would need to put a marker denoting the change on each bar where your chords change *and* you would need to figure out a way to parse your marker data from any other timeline markers you might be using for transitions in FMOD. for example if you have destination markers for denoting sections of your music ( Intro, exploration, combat, etc.... ) *and* you're getting your chord / key information from markers, then you would need to parse out those two streams of data back on the unity / c# side.

Another simpler method i came up with is as follows: it's a much simpler setup on the c# side and about the same amount of work in FMOD. within FMOD you can create a region on an audio track called a command instrument. you can use command instuments to change parameters within FMOD. if we make a global variable in FMOD we can increment it with command instruments, per chord change, and then read it back using getParameterByID...without setting up all the boilerplate for proper timeline callbacks. your global parameter can be an enum or an integer, whatever's easy to read back on the unity side.


Implementation


set up your level music event instance and play it:


void Start()
{
string levelMusic = LevelMusicHook.instance.levelMusic; // what to play
if (levelMusic != null)
{
musicPlayEvent = RuntimeManager.CreateInstance(levelMusic);
musicPlayEvent.start();
}
}




then when we get a request to play a stinger ( or whatever other event you want ) ...we can play the appropriate one by checking against our chordID global parameter and passing that back to FMOD. for the code below to work properly it's important that those stinger events are named according to whatever logic you set up in the second line of the function... and that the audio *files are in the same directory* as the event that they are meant to match up with. another potential gotcha here is you need to read back the "final value" parameter of your global parameter. this final value gives the value of the parameter *after* any processing internal to FMOD ie. being changed by another instrument. in this case a command instrument. more here

public void RequestPlayStinger()
{
RuntimeManager.StudioSystem.getParameterByID(chordID, out float value, out float finalvalue);
string stingerPath = LevelMusicHook.instance.levelMusic + "_Chord_" + finalvalue;
print("stinger path" + stingerPath);
RuntimeManager.PlayOneShot(stingerPath);

}


Setup


the FMOD setup looks like this. there's a command instrument every chord change that sets a global parameter called chord. this all happens inside fmod and is read back using getParameterByID the marker track is tidy and readable and our chord info has it's own lane! 


here’s a video showing this system in action. plus a couple of examples of interactive music implementation: