simvx.core.audio_effect¶
Audio effects: typed DSP nodes that attach to AudioBus.
Effects are pure-Python descriptors; backends synchronise them into their
native graph during :meth:AudioBackend.sync_bus_layout. The Python layer
owns the what (parameters, ordering, capability requirements); the
backend owns the how (ma_engine ma_node_graph for desktop, Web Audio
AudioNode chains for the browser).
Authoring::
from simvx.core import AudioBusLayout
from simvx.core.audio_effect import ReverbEffect, ParametricEQ, EQBand
layout = AudioBusLayout.get_default()
music = layout.get_bus("Music")
music.add_effect(ReverbEffect(room_size=0.7, wet=0.3))
music.add_effect(ParametricEQ(bands=[
EQBand(type="lowshelf", freq=120.0, gain_db=-3.0),
EQBand(type="peaking", freq=2500.0, q=1.4, gain_db=+2.0),
]))
Effects chain in declaration order (source → bus_effects[0] → ... → bus_effects[N-1] → send_to).
Capability gating: each effect declares required_capability.
Backends skip effects whose capability they don’t advertise; the audio
server logs a single warning per unsupported effect / backend pair.
Effects are applied on both backends. The native desktop backend builds a
per-bus ma_*_node chain (built-in ma_lpf/hpf/bpf/notch/delay plus
custom DSP nodes for freeverb reverb, parametric EQ, soft-clip distortion,
and the compressor); the web backend maps each effect to a Web Audio node.
Effect Properties also round-trip through the inspector and scene serializer.
Module Contents¶
Classes¶
Base class for all audio effects. |
|
Static gain stage. Useful for trim before downstream effects. |
|
2nd-order low-pass biquad. Attenuates frequencies above |
|
2nd-order high-pass biquad. Attenuates frequencies below |
|
2nd-order band-pass biquad. Centered on |
|
2nd-order notch biquad. Removes a narrow band around |
|
Single-tap delay with feedback. Wet/dry mix exposed for parallel sends. |
|
Schroeder-style algorithmic reverb (Jezar’s freeverb model). |
|
One band of a |
|
Multi-band parametric equalizer. Each band is an |
|
Symmetric tanh-curve soft clipping. |
|
Feed-forward compressor with soft knee. |
Data¶
API¶
- simvx.core.audio_effect.__all__¶
[‘AudioEffect’, ‘GainEffect’, ‘LowPassFilter’, ‘HighPassFilter’, ‘BandPassFilter’, ‘NotchFilter’, ‘D…
- class simvx.core.audio_effect.AudioEffect(*, enabled: bool = True)[source]¶
Base class for all audio effects.
Concrete subclasses declare typed
Propertydescriptors for their parameters; backends read parameter values via attribute access (effect.cutoff_hz,effect.wet, …).required_capabilityis the :class:Capabilitya backend must advertise to materialise this effect; backends that don’t advertise it skip the effect with a single warning per (effect, backend) pair.Nonemeans “every backend supports this”. Compares equal to the underlyingstrfor existing call sites that pattern-match on the wire-format tag.Initialization
- required_capability: ClassVar[simvx.core.audio_protocol.Capability | None]¶
None
- get_property_values() dict[str, Any][source]¶
Return a dict of (Property name → current value) for serialization.
- property effect_type: str[source]¶
Lowercased class name with the
Effect/Filtersuffix stripped.Used as the canonical type tag in backend wire protocols (
reverb,lowpass,compressor, …). Matches the switch-cases on the JS bridge inaudio_bridge.js.
- to_dict() dict[str, Any][source]¶
Serialize for cross-backend transport (JS bridge, IPC, save files).
The format is deliberately flat: backends pattern-match on
typeand readparamsdirectly. Subclasses with nested types (e.g.ParametricEQwithEQBand) override this to flatten the nesting.
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect[source]¶
Reconstruct an effect from its :meth:
to_dictpayload.Dispatches on
data["type"]via the module-level- Data:
_EFFECT_REGISTRY, then forwardsparamsplus theenabledflag to the target class’s constructor. Subclasses with nested types (e.g. :class:ParametricEQ) override this to rebuild their nested structure from the flattened payload.
Raises: InvalidStreamError:
data["type"]isn’t a known effect tag. The message lists the registered tags so the caller can spot the typo or register the missing effect class.
- class simvx.core.audio_effect.GainEffect(*, volume_db: float = 0.0, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectStatic gain stage. Useful for trim before downstream effects.
Initialization
- required_capability¶
None
- volume_db¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.LowPassFilter(*, cutoff_hz: float = 1000.0, q: float = 0.707, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect._BiquadEffect2nd-order low-pass biquad. Attenuates frequencies above
cutoff_hz.Initialization
- required_capability¶
None
- cutoff_hz¶
‘Property(…)’
- q¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.HighPassFilter(*, cutoff_hz: float = 1000.0, q: float = 0.707, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect._BiquadEffect2nd-order high-pass biquad. Attenuates frequencies below
cutoff_hz.Initialization
- required_capability¶
None
- cutoff_hz¶
‘Property(…)’
- q¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.BandPassFilter(*, cutoff_hz: float = 1000.0, q: float = 0.707, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect._BiquadEffect2nd-order band-pass biquad. Centered on
cutoff_hzwith bandwidth fromq.Initialization
- required_capability¶
None
- cutoff_hz¶
‘Property(…)’
- q¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.NotchFilter(*, cutoff_hz: float = 1000.0, q: float = 0.707, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect._BiquadEffect2nd-order notch biquad. Removes a narrow band around
cutoff_hz.Initialization
- required_capability¶
None
- cutoff_hz¶
‘Property(…)’
- q¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.DelayEffect(*, time_seconds: float = 0.25, feedback: float = 0.4, wet: float = 0.5, dry: float = 0.5, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectSingle-tap delay with feedback. Wet/dry mix exposed for parallel sends.
Initialization
- required_capability¶
None
- time_seconds¶
‘Property(…)’
- feedback¶
‘Property(…)’
- wet¶
‘Property(…)’
- dry¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.ReverbEffect(*, room_size: float = 0.5, damping: float = 0.5, wet: float = 0.3, dry: float = 0.7, width: float = 1.0, freeze: bool = False, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectSchroeder-style algorithmic reverb (Jezar’s freeverb model).
Same parameters across desktop and web. Desktop runs the freeverb algorithm in a custom
ma_node; web runs aConvolverNodewith a baked impulse response tuned to match.Initialization
- required_capability¶
None
- room_size¶
‘Property(…)’
- damping¶
‘Property(…)’
- wet¶
‘Property(…)’
- dry¶
‘Property(…)’
- width¶
‘Property(…)’
- freeze¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.EQBand[source]¶
One band of a
ParametricEQ.typeselects the shape:"peaking"(centered bell),"lowshelf"(low-frequency cut/boost),"highshelf"(high-frequency cut/boost).gain_dbis the boost (positive) or cut (negative) at the band’s centre. Peaking bands also useqfor bandwidth; shelves don’t.- type: str¶
‘peaking’
- freq: float¶
1000.0
- q: float¶
1.0
- gain_db: float¶
0.0
- class simvx.core.audio_effect.ParametricEQ(*, bands: list[simvx.core.audio_effect.EQBand] | None = None, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectMulti-band parametric equalizer. Each band is an
EQBand.Default is a 3-band EQ (low shelf, mid peaking, high shelf) at flat settings: add or modify bands to taste.
Initialization
- required_capability¶
None
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.ParametricEQ[source]¶
Rebuild bands from the flattened :meth:
to_dictpayload.
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- class simvx.core.audio_effect.SoftClipEffect(*, drive: float = 2.0, output_gain: float = 1.0, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectSymmetric tanh-curve soft clipping.
driveincreases input gain before the curve (more saturation);output_gaintrims the output.tanh(x*drive) / tanh(drive)normalises so the curve passes through (1, 1) regardless of drive.Initialization
- required_capability¶
None
- drive¶
‘Property(…)’
- output_gain¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶
- class simvx.core.audio_effect.CompressorEffect(*, threshold_db: float = -24.0, ratio: float = 4.0, attack_ms: float = 5.0, release_ms: float = 100.0, knee_db: float = 6.0, makeup_db: float = 0.0, enabled: bool = True)[source]¶
Bases:
simvx.core.audio_effect.AudioEffectFeed-forward compressor with soft knee.
Web maps this to
DynamicsCompressorNode(browser-native). Desktop runs a custom envelope-follower + gain-reduction node.Initialization
- required_capability¶
None
- threshold_db¶
‘Property(…)’
- ratio¶
‘Property(…)’
- attack_ms¶
‘Property(…)’
- release_ms¶
‘Property(…)’
- knee_db¶
‘Property(…)’
- makeup_db¶
‘Property(…)’
- classmethod __init_subclass__(**kwargs: Any) None¶
- __repr__() str¶
- get_property_values() dict[str, Any]¶
- property effect_type: str¶
- to_dict() dict[str, Any]¶
- classmethod from_dict(data: dict[str, Any]) simvx.core.audio_effect.AudioEffect¶