Multi-library audio effects registry with a unified chain-application API
Project description
Unified registry of 85 audio effects across 7 libraries (audiomentations, sox, torchaudio, scipy, librosa, pyloudnorm, numpy), with a clean chain-application API inspired by pedalboard.
- One call signature for every effect:
(audio, sr, **params) -> np.ndarray - JSON / YAML / pickle serialization of effect chains
- Pure data format: chains are lists of dicts, portable across languages
- Parameter ranges attached to every effect for random chain generation
Install
pip install multiafx
Requires Python ≥ 3.10.
Quickstart
import multiafx
import soundfile as sf
# Build a chain inline
chain = multiafx.FXChain([
{"effect": "sox_highpass", "params": {"frequency": 80.0, "width_q": 0.707}},
{"effect": "sox_compand", "params": {"attack_time": 0.005,
"decay_time": 0.1,
"soft_knee_db": 6.0}},
{"effect": "sox_reverb", "params": {"reverberance": 40.0,
"high_freq_damping": 50.0,
"room_scale": 60.0,
"stereo_depth": 80.0,
"pre_delay": 20.0,
"wet_gain": -6.0}},
])
# Load audio as (channels, samples) float32
audio, sr = sf.read("input.wav", always_2d=True)
audio = audio.T.astype("float32")
# Apply — pedalboard style
processed = chain(audio, sr)
sf.write("output.wav", processed.T, sr)
Loading chains from files
chain = multiafx.FXChain.load("preset.json") # auto-detect by extension
chain = multiafx.FXChain.load("preset.yaml")
chain = multiafx.FXChain.load("preset.pkl")
# or explicitly
chain = multiafx.FXChain.from_json("preset.json")
chain = multiafx.FXChain.from_yaml("preset.yaml")
chain = multiafx.FXChain.from_pickle("preset.pkl")
JSON format (preset.json):
[
{"effect": "sox_highpass", "params": {"frequency": 80.0, "width_q": 0.707}},
{"effect": "sox_compand", "params": {"attack_time": 0.005,
"decay_time": 0.1,
"soft_knee_db": 6.0}}
]
YAML format (preset.yaml):
- effect: sox_highpass
params: {frequency: 80.0, width_q: 0.707}
- effect: sox_compand
params:
attack_time: 0.005
decay_time: 0.1
soft_knee_db: 6.0
Saving is symmetric: chain.to_json(path), chain.to_yaml(path), chain.to_pickle(path).
Building chains programmatically
chain = multiafx.FXChain()
chain.add("sox_highpass", frequency=100.0, width_q=0.707)
chain.add("sox_compand", attack_time=0.005, decay_time=0.1, soft_knee_db=4.0)
chain.add("sox_reverb", reverberance=30.0, high_freq_damping=50.0, room_scale=40.0,
stereo_depth=100.0, pre_delay=15.0, wet_gain=-8.0)
# List-like mutation
chain.append({"effect": "sox_gain", "params": {"gain_db": 2.0}})
chain.insert(0, {"effect": "sox_highpass", "params": {"frequency": 40.0, "width_q": 0.7}})
del chain[-1]
chain.pop()
len(chain)
for step in chain: ...
Default parameters
Every effect has sensible defaults, so you can omit params entirely or pass
only the parameters you care about:
# All defaults — just effect names
chain = multiafx.FXChain([
{"effect": "sox_highpass"},
{"effect": "sox_compand"},
{"effect": "sox_reverb"},
])
# .add() with no kwargs also works
chain = multiafx.FXChain()
chain.add("sox_highpass")
chain.add("sox_compand")
# Override only the parameters you want; the rest fall back to defaults
chain = multiafx.FXChain([
{"effect": "sox_highpass", "params": {"frequency": 200.0}}, # width_q defaults
{"effect": "sox_compand"}, # all defaults
])
Random chain generation
import multiafx
chain = multiafx.generate_random_chain(
num_fx=8, # or (1, 8) for a random range
seed=42,
exclude_categories=["PITCH", "TIME"], # skip content-altering effects
exclude_effects=["sox_reverb"],
no_consecutive_same_category=True, # no EQ → EQ back-to-back
)
Registry introspection
import multiafx
multiafx.registry.list_effects() # all 85 names
multiafx.registry.list_effects(library="sox") # filter by library
multiafx.registry.list_effects(category="EQ") # filter by macro category
multiafx.registry.libraries() # 7 libraries
multiafx.registry.categories() # 12 MacroCategory enums
eff = multiafx.registry.get("sox_compand")
eff.name # "sox_compand"
eff.library # "sox"
eff.macro_category # <MacroCategory.DYNAMICS: 'DYNAMICS'>
eff.param_ranges # {"attack_time": ParamRange(0.001, 0.1), ...}
Effect Categories
| Category | Count | Example effects |
|---|---|---|
| EQ | 37 | sox_highpass, am_peaking_filter, ta_equalizer_biquad |
| DYNAMICS | 11 | sox_compand, sox_gain, am_normalize |
| DISTORTION | 5 | sox_overdrive, am_tanh_distortion, am_bit_crush |
| REVERB | 2 | sox_reverb, am_air_absorption |
| DELAY | 2 | sox_echo, sox_echos |
| MODULATION | 4 | sox_chorus, sox_flanger, sox_phaser, sox_tremolo |
| PITCH | 3 | sox_pitch, lib_pitch_shift, am_pitch_shift |
| TIME | 4 | sox_tempo, sox_speed, lib_time_stretch, am_time_stretch |
| SPECTRAL | 5 | sox_deemph, ta_riaa_biquad, lib_preemphasis |
| STEREO | 4 | sox_oops, sox_earwax, npy_lr_pan, npy_stereo_widener |
| NOISE | 2 | am_add_gaussian_noise, am_add_color_noise |
| OTHER | 4 | am_polarity_inversion, am_reverse, sox_dcshift, ta_dcshift |
The full effect reference is in docs/effects.md.
Audio format
- All effects take and return
np.ndarraywith shape(channels, samples)and dtypefloat32. - Sample rate is a second positional argument.
- Applying an empty chain returns the input clipped to
[-1, 1].
Development
git clone https://github.com/barry-mir/multiafx
cd multiafx
conda create -n multiafx python=3.10 -y
conda activate multiafx
pip install -e ".[dev]"
pytest tests/
The test suite runs every one of the 85 effects at min / mid / max of each parameter range. No test is expected to be skipped for any reason other than "effect has no parameters". If you add an effect, add nothing else — the parameterized tests pick it up automatically.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file multiafx-0.1.1.tar.gz.
File metadata
- Download URL: multiafx-0.1.1.tar.gz
- Upload date:
- Size: 25.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6440a2de96f060abd69ae7030280a87af3021721d99fc08700086a617685a214
|
|
| MD5 |
d3f4dd32bbb636bca1aaddea29631c73
|
|
| BLAKE2b-256 |
932598633fb72a3b018757cbe0df57160ad5ded467092c561e3047564a2cb9db
|
File details
Details for the file multiafx-0.1.1-py3-none-any.whl.
File metadata
- Download URL: multiafx-0.1.1-py3-none-any.whl
- Upload date:
- Size: 23.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9f3650616ced69d0c92fb0939cf06832835ad86d04b28b9b57467ec6ccb92db
|
|
| MD5 |
3c739797a3d9d83d41807f4923283089
|
|
| BLAKE2b-256 |
1d5df21b3405ffac7ef7f859a8445d1fd4fb184730bab2fe92b07f2eabc3fb6e
|