DSP Effects#
This chapter explains how to add effects to sounds.
A DSP is an audio effect processing unit. Reverb, filtering, delay, compression, and spectrum analysis can all be treated as DSPs. When getting started, prefer the FmodAudioEffect* resource classes and add effects to a Bus. Use FmodDSP directly only when you need very low-level control.
Choose Where to Apply the Effect First#
Need |
Recommended approach |
|---|---|
Apply filtering to all music |
Add the effect to the |
Add reverb to all ambience |
Add the effect to the |
Affect only one playback instance |
Get the Channel for that playback and add the DSP there. |
Only adjust left/right position |
Prefer FmodChannelControl.set_pan(); no separate effect is needed. |
Build a spectrum UI |
Use |
For most projects, adding effects to a bus is the easiest to maintain. For example, when the pause menu opens, adding a low-pass filter or lowering volume on the Music bus affects all music together.
Choosing Common Effects#
Effect |
Class |
Common uses |
|---|---|---|
Gain |
Amplify or attenuate sound. |
|
Filter |
Underwater sound, sounds behind walls, or muffled pause-menu audio. |
|
Equalizer |
Adjust low, mid, and high frequencies. |
|
Reverb |
Room, cave, and corridor space. |
|
Delay |
Echo and rhythmic delay. |
|
Compressor |
Control dynamic range and make sound more stable. |
|
Spectrum analyzer |
Music visualization and frequency-band detection. |
|
Recording |
Record audio passing through a bus. |
Add an Effect to a Bus#
The following example adds a low-pass filter to the Music bus. It makes the music sound muffled, which is useful for pause menus, underwater scenes, or hearing sound through walls.
func add_pause_filter():
var layout := FmodServer.get_audio_bus_layout()
var filter := FmodAudioEffectFilter.new()
filter.cutoff_hz = 1200.0
filter.resonance = 0.2
layout.add_bus_effect("Music", filter)
After an effect is added to a bus, all sounds passing through that Bus are affected.
Bypass Effects#
If you only need to temporarily disable an effect, prefer bypassing it instead of repeatedly creating and deleting it.
func set_music_effects_enabled(enabled: bool):
var layout := FmodServer.get_audio_bus_layout()
layout.set_bus_bypass("Music", not enabled)
Bypass means the signal still passes through, but the effects on that bus are skipped.
Common Effect Examples#
Pause menu: muffle the music#
var pause_filter := FmodAudioEffectFilter.new()
func _ready():
pause_filter.cutoff_hz = 1000.0
pause_filter.resonance = 0.1
FmodServer.get_audio_bus_layout().add_bus_effect("Music", pause_filter)
FmodServer.get_audio_bus_layout().set_bus_bypass("Music", true)
func set_paused_audio(paused: bool):
FmodServer.get_audio_bus_layout().set_bus_bypass("Music", not paused)
Room reverb: add space to ambience#
func setup_room_reverb():
var reverb := FmodAudioEffectReverb.new()
reverb.room_size = 0.7
reverb.damping = 0.45
reverb.wet = 0.35
reverb.dry = 1.0
FmodServer.get_audio_bus_layout().add_bus_effect("Ambient", reverb)
Equalizer: reduce harsh frequencies#
func soften_sfx():
var eq := FmodAudioEffectEQ10.new()
# Lower the higher bands so the effect is less harsh.
eq.set_band_gain_db(7, -3.0)
eq.set_band_gain_db(8, -4.0)
FmodServer.get_audio_bus_layout().add_bus_effect("SFX", eq)
Delay: add echo to a special voice effect#
func add_echo_to_voice_bus():
var delay := FmodAudioEffectDelay.new()
delay.tap1_delay_ms = 180.0
delay.tap1_level_db = -8.0
delay.tap2_active = false
delay.feedback_active = true
delay.feedback_delay_ms = 260.0
delay.feedback_level_db = -12.0
FmodServer.get_audio_bus_layout().add_bus_effect("Voice", delay)
Spectrum analysis: read music energy#
FmodAudioEffectSpectrumAnalyzer does not change the sound. It only reads spectrum data, which is useful for music visualization or driving visuals from bass energy.
var analyzer := FmodAudioEffectSpectrumAnalyzer.new()
func _ready():
analyzer.fft_size = FmodAudioEffectSpectrumAnalyzer.FFT_SIZE_2048
FmodServer.get_audio_bus_layout().add_bus_effect("Music", analyzer)
func _process(_delta):
analyzer.update_spectrum()
var bass := analyzer.get_magnitude_for_frequency_range(
20.0,
250.0,
FmodAudioEffectSpectrumAnalyzer.MAGNITUDE_AVERAGE
)
print("bass energy: ", bass.length())
Recording: record a bus#
FmodAudioEffectRecord lets the sound pass through unchanged while caching the audio that passes through the bus when recording is enabled.
var recorder := FmodAudioEffectRecord.new()
func _ready():
recorder.format = FmodAudioEffectRecord.FORMAT_16_BITS
FmodServer.get_audio_bus_layout().add_bus_effect("Master", recorder)
func start_recording():
recorder.recording_active = true
func stop_recording() -> AudioStreamWAV:
recorder.recording_active = false
return recorder.get_recording()
Effect Order#
Multiple DSP units form a DSP Chain. Sound passes through them in order, so the order affects how it sounds.
An easy default order to understand is:
Equalizer / filter -> compressor -> distortion -> delay / reverb -> analyzer / recorder
This is not a hard rule. Distortion before reverb and reverb before distortion can sound very different. When tuning effects, change one variable at a time and listen as you adjust.
When to Use FmodDSP Directly#
FmodAudioEffect* is better for the common workflows in this guide; FmodDSP is closer to low-level FMOD.
Use FmodDSP directly only when:
You need access to raw parameter indices of FMOD built-in DSPs.
You need to manually insert a DSP into a specific Channel DSP chain.
You need custom DSP callbacks or experimental processing.
You already know the meaning and range of the corresponding DSP parameters.
A minimal example:
func add_low_level_reverb():
var system := FmodServer.main_system
var reverb := system.create_dsp_by_type(FmodDSP.DSP_TYPE_SFXREVERB)
var master := system.get_master_channel_group()
master.add_dsp(0, reverb)
Low-level DSP parameters are usually numeric indices and are less intuitive than properties such as FmodAudioEffectReverb.room_size. For regular projects, prefer effect resource classes.
Performance Tips#
Each enabled DSP adds CPU cost.
When multiple sounds share the same effect, putting it on a bus is usually cheaper.
When temporarily disabling an effect, bypassing is more stable than repeatedly adding and removing it.
FFT effects such as spectrum analysis and pitch shifting are more CPU-hungry.
Do not make large parameter jumps every frame; use interpolation or Tween when values need to change.
Troubleshooting Checklist#
If an effect does not change the sound, check:
Whether the sound is really routed to this Bus.
Whether the bus is bypassed.
Whether the effect parameters are too subtle to hear.
Whether the effect was added to the wrong bus.
Whether the order of multiple effects matches your expectation.