Audio Snapshot TransitionTo unaffected by timeScale?

Hi all,

Ran into a problem.

Audio: gameplay snapshot / menu snapshot (each plays different music).

UI pause/unpause uses a coroutine to transition timeScale between 1 and 0 over a second.

Problem: User clicks pause button, snapshot transition to menu music starts, coroutine lowers timeScale to zero. When timeScale reaches zero, audio snapshot transition has not completed. All I hear is faint gameplay music (instead of full volume menu music).

Is there a way to transition snapshots unaffected by timeScale? Audio snapshot transitions and pause transition are all 1 second long.

Thanks :slight_smile:

I wrote my own audio crossfade script which is not affected by Time.timeScale:

public AudioSource music;                   // assign via inspector
public AudioSource menuMusic;              // assign via inspector

private float musicVolumeOrigin;
private float menuMusicVolumeOrigin;

void Awake ()
{
    musicVolumeOrigin = music.volume;                // makes sure transitions respect the volume from inspector
    menuMusicVolumeOrigin = menuMusic.volume;       // makes sure transitions respect the volume from inspector
}

void Start ()
{
    music.Pause();
}

IEnumerator MusicCrossfade (bool toGameplay, float duration)
{
    AudioSource from = toGameplay ? menuMusic : music;
    AudioSource to = toGameplay ? music : menuMusic;
    float fromOrigin = toGameplay ? menuMusicVolumeOrigin : musicVolumeOrigin;
    float toOrigin = toGameplay ? musicVolumeOrigin : menuMusicVolumeOrigin;

    float startTime = Time.unscaledTime;
    float elapsed;

    to.UnPause();

    while ((Time.unscaledTime - startTime) < duration)
    {
        elapsed = (Time.unscaledTime - startTime) / duration;
        from.volume = Mathf.Lerp(fromOrigin, 0f, elapsed); 
        to.volume = Mathf.Lerp(0f, toOrigin, elapsed);
        yield return null;
    }
    from.Pause();

    yield return null;
}

And these functions can be called to execute the changes (i.e. from UI buttons):

public void GamePlayMusic(bool restart)
{
    if (restart)
    {
        music.Play();
    }
    StopCoroutine(MusicCrossfade(true, 0.5f));
    StartCoroutine(MusicCrossfade(true, 0.5f));
}

public void MenuMusic()
{
    StopCoroutine(MusicCrossfade(false, 0.5f));
    StartCoroutine(MusicCrossfade(false, 0.5f));
}

@jamesk5 Thanks for posting this. I can see why Unity would want a transition tied to timescale, but it would be nice to have a bool/check on a snapshot or mixer that says it should not be affected by timescale since one of the most probable use cases for transitions is a graceful mute :wink: (which usually happens when the game is paused).

[UPDATE]

Something I saw on another post actually works for this scenario: set the timeScale to a value like 0.0001f, then use that timeScale value multiplied against whatever fade time you send to the TransitionTo call:

AudioMixerSnapshot transition = masterGroup.audioMixer.FindSnapshot("MasterOn");
transition.TransitionTo(1f*Time.timeScale);

It’s a quick way to solve this issue, though your way is more complete/controlled - just thought I’d archive it here - thanks for posting

Just wanted to throw another solution in here. I wrote this code for my AudioManager class (though this is easily thrown into your own class), and it will transition over time between two snapshots - unaffected by Time.timescale. You can modify the “steps” variable to make it smoother (more iterations), and adjust it accordingly until it is smooth for your needs. Hope it helps!

http://www.sombr.com/2015/10/22/audiomixersnapshot-transitions-independent-of-timescale/