- Home /
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?
Thanks!
Answer by Jonatan Crafoord · Feb 18, 2015 at 03:36 PM
Can you post your code?
I'm out of the office today, but suffice to say the code is a very vanilla corroutine - not unlike the dozens of 'how to fade' audio out there.
I have verified that the number being passed into source.volume is a correctly interpolating float. The same fade makes a nice smooth canvas fade to black. The peoblem happens with both a linear and curve based interpolation.
The issue is that where my fade produces a correct number per frame over the duration, the sound playback itself seems to pop to the correct volume 2 to 3 times. Like audio is updated in quarter second slices.
Is this a limitation of Unity's audio playback? 3d sounds? Changing multiple sounds during the same update?
Are there alternative ways to fade blocks of audio, such as with multiple listeners?
Thanks!
I haven't experienced any such problems with fading audio sources, but if you've tried everything you mention and the code is otherwise solid, it does sound like some update bug in the audio thread. I'm having some trouble believing this to be the case however - Unity should without trouble be able to fade a multitude of sources simultaneously. Have you tried your code on some other machine (in case it is a hardware issue)?
Answer by ACZ · Feb 19, 2015 at 05:02 PM
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;
UpdateAudioVolume(alpha);
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[i].volume = _cacheVolumeList[i] * target * _masterVolumeScale;
}
}
Where do you set the old target volume, and why do you multiply the volume with a cached volume value at the end? Can you share the whole class?
I'd prefer not to post the whole class - the company gets a bit iffy about stuff like that.
The old setting is cached when a fade starts. For purpose of this discussion, we are lerping between a fade of 0.0 and 1.0 or from 1.0 to 0.0. (I can replace those variables with constants and the anomaly still happens).
The _cached volume is basically so that we respect the level designer chosen setting. This way the group of audio sources we want to fade can include a major sound with a default volume of 1.0 and a set of background sounds at 0.25. If we remove this (interpolate all sources from a volume of 0.0 to 1.0) the anomaly still happens.
I can verify that each _source.volume value is correct at each frame during the fade, and that even though we set this property 120 times during a 2 second fade, the audio pops - changing volume only 2 or 3 times. It very much looks like the source's actual low level playback does not respond to changes in .volume in complete real time. I can't find any information on whether this is a known issue / if there are any workarounds.
Your answer
Follow this Question
Related Questions
How to fade in-out groups of audio sources? 0 Answers
Footsteps not playing on Flash Export 1 Answer
Play Audio on destroy 3 Answers
How to read in Audio Input 1 Answer
audio.clip.GetData() returns no data. 0 Answers