godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.09k stars 21.18k forks source link

Pop when enabling audio filter, such as LowPassFilter #95308

Open jitspoe opened 3 months ago

jitspoe commented 3 months ago

Tested versions

4.0 - 4.3 rc2

System information

Windows 10, Vulkan forward +, Nvidia 3070

Issue description

When enabling filters on a bus, there can be a pop or crack, depending on the wave form when the filter is enabled. For example, I enable a low pass filter when the player enters the water, and sometimes there's a very audible click or pop.

Steps to reproduce

  1. Add a LowPassFilter to the Master bus.
  2. Toggle it on and and off with AudioServer.set_bus_effect_enabled()
  3. Note that sometimes there's a pretty glaring pop.

Minimal reproduction project (MRP)

test_filter_pop.zip

jitspoe commented 3 months ago

I guess this behavior is kind of expected, but it would be nice if it just had a very small crossfade, like when starting/stopping sounds or changing samples, to avoid pops.

I was considering enabling the low pass filter with the cutoff set very high then pan it down quickly in code, but it looks like there's no interpolation from the start/end values for all the frames in the buffer, so even that would probably have micro pops, especially at lower framerates.

My use case is that I'm enabling a low pass filter on everything when the player goes underwater, and clicking/popping can be pretty audible every time you jump in water.

Calinou commented 3 months ago
jitspoe commented 2 months ago

So I tried a couple ways to work around this and failed.

Method 1: Start at a high cutoff rate, like 48000 and adjust it every frame to reduce pops. Failure: High cutoff values cause the sound to cut out completely, and anything that doesn't cut out still results in pops (strangely, even 24000 seems to have worse pops than setting it to like 1000).

Method 2: Pass to 2 busses. One with the filter and one without and cross-fade. Failure: Doesn't appear to be any way to send to more than one bus.

I think we'll need an engine fix to be able to enable low-pass filters on the fly without popping.

jitspoe commented 2 months ago

Probably the most relevant related issue: https://github.com/godotengine/godot/issues/77669

michaelhartung commented 1 month ago

This is just a hunch:

audio_effect_filter.cpp does not interpolate the coefficients when updating them, and it doesn't use the provided process_one_interp method that uses the interpolated coefficients.

From what I know about DSP, changing filter coefficients without any smoothing can generate discontinuities (pops).

Maybe sth. to look into.