Transitions latency when changing parameter

EDIT:
I summarized my bug, the solution and my results in a separate thread:


Hi Derek!
Sorry for the late response, I wanted to make sure that the workaround was effective.

We have now tested the game with the workaround you suggested and it worked for us. So far we haven’t been able to reproduce the issue, neither on PC nor Nintendo Switch. So thanks a lot, I was on the edge of considering to remake the entire music/ambience system.


Some notes for other devs with similar issues:
The biggest challenge was to find/make a valid FMOD::Studio::System -object which was properly initialised. The solution for that was to use the one provided on the FMODUnity.RuntimeManager .

So the final code snipped that did the trick looks like this:
FMODUnity.RuntimeManager.StudioSystem.flushCommands();


If anyone’s interested, here’s the code for the entire Coroutine which handles the switch of music/ambience:

	/// <summary>
	/// Simplifies the Fmod-event by allowing the timeline to jump back to zero for a frame, 
	/// then jump to the desired song/ambience.
	/// <para></para>
	/// Also checks if the desired music/ambience is the same as the current one. In that case, it will do nothing.
	/// </summary>
	private IEnumerator SwitchAudioCoroutine(int desiredMusicSong, int desiredAmbienceType)
	{
		//The "_Fmod"-class just contains a bunch of variables with public readonly strings 
		//to avoid someone doing a typo somewhere, and propagate name-changes from one centralized place.
		//So the values are:
		//_Fmod.Params.song == "song"
		//_Fmod.Params.variation == "variation"

        //Just making sure that the value doesn't get truncated (ie. float 0.9 → int 0, which is not the desired result).
		int currentMusicParamValue = Mathf.RoundToInt(AudioManager.Instance.GetParameterValue(musicController, _Fmod.Params.song));
		int currentAmbienceParamValue = Mathf.RoundToInt(AudioManager.Instance.GetParameterValue(ambController, _Fmod.Params.variation));

        //Only go to selection loop if we actually are changing the desired music/ambience
		if (currentMusicParamValue != desiredMusicSong)
		{
			musicController.SetParameter(_Fmod.Params.song, 0);
		}
		if (currentAmbienceParamValue != desiredAmbienceType)
		{
			ambController.SetParameter(_Fmod.Params.variation, 0);
		}

        //Wait a frame for the parameter change to take effect.
		yield return null;

        // HACK: Fmod has latency when switching with parameters and transition regions (https://qa.fmod.com/t/transitions-latency-when-changing-parameter/14383/28)
        // Therefore we flush the fmod thread, so that all the polled commands will be executed first, before continuing Fmod's internal (asynchronous) update.
        // This makes it *actually* register the last frame's parameter change (ie. setting it to 0, triggering a transition to the "selection loop"), 
        // before changing the parameter to the desired music/ambience.
        FMODUnity.RuntimeManager.StudioSystem.flushCommands();

        //Set the music/ambience to the desired values.
        musicController.SetParameter(_Fmod.Params.song, desiredMusicSong);
		ambController.SetParameter(_Fmod.Params.variation, desiredAmbienceType);
	}

Also, to get the parameter value, here’s the code for that:

public float GetParameterValue(FMODUnity.StudioEventEmitter eventEmitter, string parameterName)
	{
		FMOD.Studio.ParameterInstance parameterInstance;
		float paramValue;

		eventEmitter.EventInstance.getParameter(parameterName, out parameterInstance);
		parameterInstance.getValue(out paramValue);

		return paramValue;
	}