Prefader modulation stops working when sound is muted in Unity

Hello!
We’re getting a parameters finalValue to scale an object along with the sound but when muting the audio in the game window tab OR setting the master volume to 0 via our FMOD vca’s, the parameters finalValue return to it’s default value even though we can see the parameter still being modulated inside FMOD.

It doesn’t default the value in Unity when muted for ALL our events, only some and we can’t figure out why that is.

There is one that IS working: The Music Player event (that works) are sending its tracks to return tracks within the event which then have the sidechain effect applied Pre-Fader. The parameters are then being sidechained from the return tracks. The animations that are driven by these parameters still works when muting the game.

All other instances where we use the same setup the animations stop working when muting the game.
What we’ve tried/checked in FMOD:

  • Making the parameter global and sidechaining the entire bus in the mixer view (pre fader).
  • Having the sidechain effect on the track directly instead of using return tracks, still applying the sidechain pre fader.
  • Making new events and parameters from scratch, same broken behavior.
  • Different instrument types, programmer and single instrument.

What we’ve tried/checked in Unity:

  • Getting the parameter by both name and ID.
  • Using ‘value’ instead of ‘finalValue’.
  • Isolating the behavior in a clean script/object (only the needed calls).

We’ve tried all the small tweaks and changes we could think of so any suggestions are very welcome!

Here’s the test script we’ve been using and tweaking:

using System.Runtime.InteropServices;
using FMOD;
using FMOD.Studio;

public class MusicTest : UnityEngine.MonoBehaviour {
    public FMODUnity.EventReference eventRef;
    public UnityEngine.Transform scaleObject;
    public string paramName;
    public string musicKey;
    EVENT_CALLBACK musicCallback;
    EventInstance sound;
    
    void OnEnable() {
        Play();
    }

    void OnDisable() {
        Stop();
    }
    
    public void Play() {
        musicCallback = new FMOD.Studio.EVENT_CALLBACK(MusicEventCallback);
        sound = FMODUnity.RuntimeManager.CreateInstance(eventRef);

        GCHandle stringHandle = GCHandle.Alloc(musicKey);
        System.IntPtr intPtr = GCHandle.ToIntPtr(stringHandle);
        sound.setUserData(intPtr);
        sound.setCallback(musicCallback);
        sound.start();
    }
    
    public void Stop() {
        sound.stop(STOP_MODE.ALLOWFADEOUT);
        sound.release();
    }
    
    void Update() {
        sound.getParameterByName(paramName, out float value, out float finalValue);
        scaleObject.localScale = UnityEngine.Vector3.one * finalValue;
    }
    
    
    [AOT.MonoPInvokeCallback(typeof(EVENT_CALLBACK))]
    static RESULT MusicEventCallback(EVENT_CALLBACK_TYPE type, System.IntPtr instancePtr, System.IntPtr parameterPtr)
    {
        EventInstance eventInstance = new EventInstance(instancePtr);

        // Retrieve the user data
        System.IntPtr stringPtr;
        eventInstance.getUserData(out stringPtr);

        // Get the string object
        GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
        string key = stringHandle.Target as string;

        switch (type)
        {
            case EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
            {
                var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));

                SOUND_INFO eventSoundInfo;
                var keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out eventSoundInfo);
                Ensure.IsTrue(keyResult == RESULT.OK, $"Could not get programmer instrument from using key: {key}! Result: {keyResult.ToString()}");
                if (keyResult != RESULT.OK)
                {
                    break;
                }

                Sound eventSound;
                var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(eventSoundInfo.name_or_data, MODE._2D | MODE.LOOP_OFF | MODE.CREATESTREAM | MODE.NONBLOCKING | eventSoundInfo.mode, ref eventSoundInfo.exinfo, out eventSound);
                Ensure.IsTrue(soundResult == RESULT.OK, $"Would not create programmer instrument sound! Result: {keyResult.ToString()}");
                if (soundResult == RESULT.OK)
                {
                    parameter.sound = eventSound.handle;
                    parameter.subsoundIndex = eventSoundInfo.subsoundindex;
                    Marshal.StructureToPtr(parameter, parameterPtr, false);
                }

                break;
            }

            case EVENT_CALLBACK_TYPE.SOUND_PLAYED:
            {
                break;
            }

            case EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
            {
                var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));
                var sound = new Sound(parameter.sound);
                sound.release();
                
                break;
            }
            
            case EVENT_CALLBACK_TYPE.DESTROYED:
            {
                // Now the event has been destroyed, unpin the string memory so it can be garbage collected
                stringHandle.Free();
                break;
            }
        }

        return RESULT.OK;
    }
}

Thanks for sharing the information and the script.

Could I please grab the version number of the FMOD you are currently using?

From what you described, one possibility is that the different events may be using slightly different signal paths for their sidechain or parameter modulation. Muting the Game window or pulling a VCA to 0 does not stop the entire FMOD DSP graph, but it can affect some parts of the graph differently depending on where the fader, send, return track, and sidechain source are placed.

That might explain why your “Music Player” event keeps updating its parameter even when muted, while the other events fall back to the default value. Its sidechain source may be in a part of the signal flow that keeps running even when muted, whereas the others might not.

To understand your setup better, could you please share:

  1. A screenshot of the routing / signal flow of the “Music Player” event (the one that works)
  2. A screenshot of any non-working event’s signal flow, especially where the send/return track and sidechain compressor are located?

Thank you for responding!

I hope that these screenshots shows everything you might need! Let me know if you want anything else! :slight_smile:

Sorry forgot to post the FMOD version → 2.03.09

Sorry for the late response, and thank you for sharing the screenshots and version number!

I’ve tried rebuilding a few different test setups on my side (sidechain, VCAs, Game view mute, etc.), but I still haven’t been able to reproduce the issue where finalValue resets to its default value.

Since this only happens for some of your events and not others, there’s probably something specific about the routing or modulation chain in your project.

Would it be possible for you to provide a small minimal repro project, even just a very simple FMOD + Unity scene that shows the issue? That would help a lot. Once I have something that reproduces the behaviour on my end, I can investigate it in much more detail.