Transitions latency when changing parameter

Further investigation has revealed a latency issue that was missed when we were making the latency fixes for FMOD Studio 2.00.00. This issue results in approximately 20 milliseconds of additional latency when making a parameter value change compared to starting a new event. We’re still investigating the cause of this bug, but will include a fix in an upcoming release of FMOD Studio.

Until this bug is fixed, stopping one event and starting another may be your best option for reducing latency.

1 Like

That sounds great Joseph - hope I will be able to bring that to GamesCom in August :slight_smile:

Can you say if this will be fixed both for 1.10.13 and 2.00.00?

Both 1.10.13 and 2.00.00 have already been released, and will not change; the fix will be included in future patch releases, not existing ones. Perhaps 1.10.14 and 2.00.02, or 1.10.15 and 2.00.03, or some other future releases.

In any case, we’re still investigating this bug, and have not yet identified its cause. As such, there’s no way for us to estimate how long it will take to fix at this time.

Alright thank you Joseph – I’ll keep my fingers crossed :slight_smile:

Can you tell if this has been fixed in the recent 1.10.15 or 2.00.03 update? Finger crossed that I don’t have to make workaround for this before showcasing our game at GamesCom :grimacing:

Those versions do not include a fix for the 20 ms latency issue. Given that GamesCom is imminent, I recommend pursuing that workaround.

Hi Joseph!
What is the cause of the 20 ms latency issue?


I’m experiencing a similar issue with my music system, where the transitions don’t trigger correctly if I don’t manually insert some latency by either waiting for about 5 frames or waiting for 30 ms.

Here’s how my event is set up:

I have several songs in nested events, inside the main “musicController”-event.
All the songs can be accessed through the “00 Selection Loop” by switching the “Song”-parameter to their appropriate indexes (setup as integers: 01, 02, 03, etc).
All songs can go back to the “00 Selection Loop” by switching the “Song”-parameter to 0.

This means that in order to go from Song 02 to Song 04, FMOD would have to do like this:

Song 02 → 00 Selection Loop → Song 04


I’ve implemented this solution in Unity by doing the following in a Coroutine:

Frame 0
CurrentParameterValue == 2f
SetParameter to 0f
yield/wait 1 frame (for Fmod to to switch to the Selection Loop)

Frame 1
CurrentParameterValue == 0f
SetParameter to 4f
CurrentParameterValue == 4f


When I print the parameter value during each stage of the process (Before switching, In-Between Switching, After Switching), the parameter values I get back from the API are correct, and the music/audio is most times also correct.
But the bug I’m encountering is that sometimes the actual audio of the event is stuck on the first song. Ie. the switch to the “00 Selection Loop” never happens.

My workaround so far for this is to yield/wait for 5(!) frames or wait for 30 ms (as described above) between Frame 0 and Frame 1. When I do that, the music switches correctly, at least so far as my testing has proven.

But, doing that is pretty hacky.


So my question is:

Since this game is going to be released on several platforms (PS4, XBONE, Switch, PC, etc), which approach should I use?

  • Waiting for an arbitrary amount of frames (which could differ on the different platforms)?
  • Or should I rather wait for a set amount of time (which may or may not correspond to the same amount of frames on different devices)?

Regards,

Pablo Sorribes Bernhard
contact@pablosorribes.com
pablosorribes.com

Hi Paalo

We’ve been able to reproduce this issue in a simple example and what I believe is happening when the audio gets stuck on a song is that the calls to set the controlling parameter’s value to zero and then the new song index are landing in the same (asynchronous) FMOD Studio update. API commands are processed at the start of our update, followed by scheduling logic. When two commands to set a parameter’s value are processed in the same update they will both be evaluated before we perform scheduling, so in this case the scheduler never sees the parameter value of zero and never triggers the transition from the playing song to the selection loop, therefore it won’t transition to the new song.

I’ll log a bug for this, in the meantime the best way for you to workaround the issue is to call Studio::System::flushCommands after you’ve set the song parameter to 0 and before you set it to the new song index. This will force the set parameter command to be evaluated, setting the parameter value to 0, and the scheduling logic to be performed, triggering the transition to the selection loop.

Cheers
Derek

1 Like

Hi Derek,

Would the workaround calling Studio::System::flushCommands after haveing changed a parameter generally be a good workaround for avoiding the latency the transitioning using parameters bug?

Cheers,
Nikolaj

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;
	}

Hi deHaan

It might be worth trying out but I wouldn’t expect too much. There is potential to reduce some latency between your code calling the FMOD API to set a parameter value and FMOD processing the command, but I think most of the latency you are experiencing is probably scheduling delay which can’t be worked around.

Any chance this got fixed in 1.10.16? :pray: We’re gettting closer to release date, and I would love those transitions to be snappier :slight_smile:

Or in 1.10.17? I don’t see any revision history for those updates :slight_smile:

1 Like

So, we’re soon about to release our game, and still have the latency issue, which kind of sucks :frowning: Are there any workarounds? (It is a soccer game, and I want the music to go to a marker right when the players touch the ball during the 2nd half of the game…)

Just to make things clear, the observed transition latency is not something we are addressing as a bug, so there is no easy fix to wait for. Allow me a moment to explain the latency you’re seeing.

When something is put on the timeline, we evaluate ahead of time to ensure playback is sample accurate and smooth. If streams are used anywhere, this will add latency because we need to ensure they are buffered up ready for playback. So my first tip is don’t use streams anywhere in an event to reduce its latency. This latency is called scheduling delay.

Secondly, FMOD internally updates every 20ms unless you change this setting via FMOD_STUDIO_ADVANCEDSETTINGS. To ensure no gaps in timeline playback we schedule double that time in advance, so 40ms. When you have a condition on the timeline it is evaluated ahead of time, this is probably the latency you are seeing. To reduce this latency you can change the Studio update rate to 10ms, halving the latency. This latency is called scheduling lookahead.

If there is a particular EventInstance where you want to override these settings take a look at EventInstance::setProperty with FMOD_STUDIO_EVENT_PROPERTY_SCHEDULE_DELAY and FMOD_STUDIO_EVENT_PROPERTY_SCHEDULE_LOOKAHEAD. Use these with care though, as I mentioned above setting too small could cause sample inaccuracy.

If the above doesn’t help you may need to consider engineering the Event differently.

Hmm. I seem to be having a similar issue, but it seems to depend on where my playhead is. It’s almost like sometimes it waits for the instrument to finish as if it has some kind of async setting on it. Screen capture provided that shows my transition happening correctly first, and incorrectly the second time. Thank you for your time.

~Cameron

EDIT 01: I should note before it is asked, that 2nd track is set to async, but the problem persists when async is toggled off.

EDIT 02: Seems to work now. I had an unused LFO modulator on the parameter, and once I removed it my problem went away.

Has there been a fix for this issue? I’m currently experiencing this problem and these workarounds don’t have the same effect.

Which issue do you mean? There are several discussed in this thread.

To send a parameter and that the parameter instatantly activates whatever it needs to. For instance a parameter that smoothly (and instantly) transitions between combat music and cutscene music. You need to have the transition to begin immediately since the cutscene also begins immediately.

As Mathew mentioned above, transition latency is not something we consider to be a bug, so there is no issue for us to fix.

To rephrase his explanation: It is physically impossible for a transition to occur immediately when a parameter’s value is changed. The processing required to play a sound takes a non-zero amount of time, and so any change in what sound is to be played needs to be scheduled a short time in advance of the change occurring. We have reduced this “scheduling delay” as much as we feasibly can without risking artifacting, playback gaps, stuttering, and other undesirable behavior.

If you want to reduce scheduling delay, the techniques listed by Mathew in his answer may help, depending on the content involved. That being said, none of them can reduce scheduling delay to zero, as doing so is physically impossible.