How to smoothly fade audio without any pops? Source.volume is correct, but the sound itself seems to update inconsistently.

I am smoothly fading a number (~ 15) of audio sources at the same time, by modifying the audio source’s volume parameter.

Source.volume is the correct value, and smoothly interpolates between 1.0f and 0.0f. The fades are generally 0.5 to 5.0 seconds.

Unfortunately, when you listen to the game the audio seems to pop. Specifically, the actual sound doesn’t seem to update in realtime, instead only updating at specific points.

Volume: 0.1, 0.15, 0.2, 0.25, 0.3, 0.35…
Playback: 0…0.3 …

The result is an ugly pop in the audio, and reduces my smooth fade to 2, possibly 3 increments. Time seems to affect it, but even if I fade over 5 to 10 seconds, it still pops noticeably. Frame Rate is quite solid (60+) so its not that we are dropping frames.

I’ve tried anything I can think of (making sure the listener position changes, changing the sound priority, changing the update velocity type, etc). I’ve also tried a few hack solutions, such as stopping and starting the audio each frame.

If I call source.Stop() and source.Play(), I can get the volume to fade / update correctly, but the framerate drops down to single digits. I can also have the fade correct (with an abysmal framerate drop) if I modify source’s time parameter, forcing an updating by changing its position by 0.000001 seconds or so.

Is this an issue with the low level audio playback, or is there any workaround? Is there any way to use multiple listeners or setup some sort of channel system where I can fade a channel instead of fading a set of sources? Is this related to the fact that they are 3d sounds?


Can you post your code?

We get the same behavior for both in editor, built standalone, built webplayer - on a variety of computers through the office.

This is the first time we’ve really used 3d sounds in Unity, or needed to blend more than a music track - previously most of our content was 2d sounds.

It really looks like the audio is updated in 1/4 - 1/2 second increments, instead of per frame. If we insert a Stop()/Play()[from time] to force it to update per frame, we do get the behavior we want… at 5 fps on a very high end computer. This further implies the fade logic is correct though.

Note that we get the same behavior if we just decrement a float timer in Update() and don’t use the coroutine. We also get the same behavior if we use WaitForEndOfFrame, do the timer method during fixed update.

		IEnumerator FadeVolume()
			float timer = _interpTime;

			while(timer > 0.0f)
				timer -= Time.deltaTime;

				if(timer < 0.0f)
					timer = 0.0f;

				float alpha = timer / _interpTime;

				yield return 0;

		private void UpdateAudioVolume(float alpha)
			// In the current scene, there are approximately 30 audio sources, 
			// 5 in range of the listener in our general test case
			for(int i = 0; i < _audioSourceList.Length; i++)
				float target = Mathf.Lerp(_targetVolume, _oldTargetVolume, alpha);
				_audioSourceList<em>.volume = _cacheVolumeList <em>* target * _masterVolumeScale;</em></em>

* }*
* }*