How to animate properties of an AudioEffect?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Diet Estus

I currently have an AudioBus that has a LowPassFilter AudioEffect on it. I currently use a function to toggle this effect on and start a Timer. When the Timer ends, I toggle the effect off. The code looks like this:

func start_effect():
    AudioServer.set_bus_effect_enabled(1, 0, true)
    get_node("EffectTimer").start()

func _on_EffectTimer_timeout():
    AudioServer.set_bus_effect_enabled(1, 0, false)

Unfortunately, it sounds strange just toggling the effect on and off like this. It’s too binary.

Ideally, I’d like to have an animation which continuously changes the values of my audio effect.

How can I animate the properties of an AudioEffect?

If animation isn’t possible, what else could I do?

:bust_in_silhouette: Reply From: s9menine

I was having the same problem, and iFire (also iFire#6518 in the Godot Discord) was kind enough to come up with a solution: using a combination of the setget keyword and to export a variable.

First create a Node and attach a script:

export(float, EXP, 20.0, 20000.0, 2) var filter_cutoff setget setter_function, getter_function

func setter_function(value):
    filter_cutoff = value

func getter_function():
    return filter_cutoff

When a variable uses the setget keyword to declare a setter function, every time an external source tries to modify that variable, it will call the setter function with the value as an argument, instead of directly assigning the value to the variable. E.g.

func in_the_parent_node():
    $Node.filter_cutoff = value

# works like

func in_the_parent_node():
    $Node.setter_function(value)

So we can use this setter function to do other interesting stuff, such as checks to validate the input, or changing a filter effect’s cutoff property via AudioServer.

export(float, EXP, 20.0, 20000.0, 2) var filter_cutoff setget setter_func, getter_func

func setter_function(value):
    filter_cutoff = value
    # assuming the filter effect is the first (or only) effect on the bus
    AudioServer.get_bus_effect(AudioServer.get_bus("BusName"), 0).cutoff_hz = value

func getter_function():
    return filter_cutoff

So next we need to modify filter_cutoff from an external source - such as playing animations of an AnimationPlayer Node.

Exporting filter_cutoff exposes it to the editor inspector, where you can handily click on the key icon to set keyframes for animations.

Playing animations to change filter_cutoff will then call the setter function every time AnimationPlayer changes it, which is framely (I think?) during an animation, then top it all off with easings and beziers, and voila, you are smoothly animating a bus effect. It works on bus volumes too!

Note that this is not really suitable for making fast and extreme effects, such as a looping LFO to modulate filter cutoffs similar to dubstep wubs.

And here’s the little demo iFire put together and posted on the Discord. Cheers.

Sacha Holsnyder | 2020-03-28 17:07