Effects and filters¶
EFX configuration uses immutable values like the other managed playback
controls. Effects are routed through auxiliary
EffectSend values; filter is the sound's direct
filter:
from pyalsoft import EffectSend, LowPassFilter, Reverb, play
room = Reverb(
gain=0.2,
decay_time=0.6,
high_frequency_decay_ratio=0.8,
)
sound = play(
"voice.wav",
filter=LowPassFilter(high_frequency_gain=0.1),
effect_sends=(EffectSend(effect=room),),
)
The managed API covers every core ALC_EXT_EFX effect:
- Room and delay:
Reverb,EAXReverb, andEcho - Modulation:
ChorusandFlanger - Pitch and spectral processing:
FrequencyShifter,VocalMorpher,PitchShifter, andRingModulator - Tone and dynamics:
Distortion,AutoWah,Compressor, andEqualizer
DedicatedDialogue and
DedicatedLowFrequencyEffect provide
the implementation-defined dialogue and low-frequency routes from
ALC_EXT_DEDICATED.
Discrete controls use managed enums instead of native OpenAL integers. For
example, chorus and flanger share ModulationWaveform:
from pyalsoft import Chorus, EffectSend, ModulationWaveform
wide_chorus = EffectSend(
effect=Chorus(
waveform=ModulationWaveform.SINUSOID,
rate=0.8,
depth=0.3,
)
)
LowPassFilter,
HighPassFilter, and
BandPassFilter expose EFX gain controls rather than
cutoff frequencies. Band-pass filters provide independent low- and
high-frequency gains. A filter may also be placed on an EffectSend to shape
only the wet signal. Send tuple order determines the native auxiliary-send
index, and the playback device determines how many simultaneous sends it
supports.
Live sounds accept replacement values through update, including replacement
with a different effect type. Pass filter=None or an empty effect_sends
tuple to restore the dry, unfiltered signal:
from pyalsoft import Chorus, EffectSend, HighPassFilter
sound.update(filter=HighPassFilter(low_frequency_gain=0.1))
sound.update(effect_sends=(EffectSend(effect=Chorus(rate=0.8)),))
sound.update(filter=None)
sound.effect_sends = ()
The same fields are available on VoiceConfig for
explicit voices and streams. PyALSoft owns inline filters, effects, and
auxiliary slots and releases them with the voice or stream. Configuring EFX raises
AudioBackendError when the selected device does
not expose EFX or cannot provide the requested number of sends.
Reusable effect buses¶
An inline EffectSend(effect=...) owns a separate native effect and slot for
that voice. Use create_effect_bus() when many
voices should share one room, mix bus, or other effect:
from pyalsoft import (
EffectBusConfig,
EffectSend,
Reverb,
create_effect_bus,
open_playback,
play,
)
with open_playback() as playback:
room = create_effect_bus(
playback,
EffectBusConfig(effect=Reverb(decay_time=1.8), gain=0.8),
)
send = EffectSend(bus=room)
first = play(playback, first_clip, effect_sends=(send,))
second = play(playback, second_clip, effect_sends=(send,))
set_effect_bus_config() replaces a bus's
effect, gain, automatic-send behavior, and optional target while attached
voices keep using the same slot. A target chains one bus into another and
requires AL_SOFT_effect_target; cycles are rejected. A bus cannot be released
while a live voice or stream uses it or another bus targets it.
The remaining EFX source and listener controls are available through
VoiceConfig and Acoustics:
cone_outer_gain_high_frequencydirect_filter_gain_high_frequency_autoauxiliary_send_filter_gain_autoauxiliary_send_filter_gain_high_frequency_autometers_per_unit
See the runnable
play_with_reverb.py
and
cycle_effects.py,
as well as the
filter_sound.py
and
shared_effect_bus.py
examples.