Composed Effects¶
Higher-level effects built by combining multiple primitives: exciter, de-esser, parallel compression, stereo delay, multiband compression, formant filtering, PSOLA pitch shifting, mastering, vocal processing chains, shimmer reverb, tape echo, lo-fi, telephone, gated reverb, and auto-pan.
Usage examples¶
Exciter¶
from nanodsp.effects import composed
from nanodsp.buffer import AudioBuffer
buf = AudioBuffer.from_file("input.wav")
# Add brightness and presence above 3 kHz
bright = composed.exciter(buf, freq=3000.0, amount=0.3)
# Subtle air boost above 8 kHz
airy = composed.exciter(buf, freq=8000.0, amount=0.15)
De-esser¶
# Tame sibilance around 6 kHz
deessed = composed.de_esser(buf, freq=6000.0, threshold_db=-20.0)
# Aggressive de-essing with higher ratio
strong = composed.de_esser(buf, freq=5000.0, threshold_db=-25.0, ratio=8.0)
Parallel compression¶
# "New York compression" -- heavy compression mixed with dry
punchy = composed.parallel_compress(buf, mix=0.5, ratio=8.0, threshold_db=-30.0)
Stereo delay¶
# Stereo delay with different left/right times
delayed = composed.stereo_delay(
buf, left_ms=250.0, right_ms=375.0, feedback=0.3, mix=0.4
)
# Ping-pong delay
pp = composed.stereo_delay(
buf, left_ms=250.0, right_ms=250.0, feedback=0.4, mix=0.5, ping_pong=True
)
Multiband compression¶
# 4-band compression with default crossovers
multi = composed.multiband_compress(buf)
# Custom crossover frequencies and per-band settings
multi = composed.multiband_compress(
buf,
crossover_freqs=[200.0, 2000.0, 8000.0],
ratios=[2.0, 4.0, 3.0, 2.0],
thresholds=[-24.0, -20.0, -18.0, -16.0],
)
Formant filter¶
# Apply vowel formant (a, e, i, o, u)
vowel_a = composed.formant_filter(buf, vowel="a")
vowel_e = composed.formant_filter(buf, vowel="e")
vowel_o = composed.formant_filter(buf, vowel="o")
PSOLA pitch shifting¶
# Pitch shift up 5 semitones (time-domain, best for monophonic)
shifted = composed.psola_pitch_shift(buf, semitones=5.0)
# Down one octave
down = composed.psola_pitch_shift(buf, semitones=-12.0)
Ping-pong delay¶
# Stereo ping-pong delay with crossed feedback
pp = composed.ping_pong_delay(buf, delay_ms=375.0, feedback=0.5, mix=0.5)
# Shorter delay, less feedback
pp = composed.ping_pong_delay(buf, delay_ms=125.0, feedback=0.3, mix=0.4)
Frequency shifter¶
# Shift all frequencies up by 100 Hz (inharmonic -- not pitch shifting)
shifted = composed.freq_shift(buf, shift_hz=100.0)
# Shift down by 50 Hz
shifted = composed.freq_shift(buf, shift_hz=-50.0)
Ring modulator¶
# Classic ring mod at 300 Hz carrier
ring = composed.ring_mod(buf, carrier_freq=300.0)
# With LFO modulating the carrier frequency
wobble = composed.ring_mod(buf, carrier_freq=300.0, lfo_freq=5.0, lfo_width=20.0)
# 50/50 dry/wet mix
subtle = composed.ring_mod(buf, carrier_freq=200.0, mix=0.5)
Shimmer reverb¶
# Ethereal octave-up shimmer reverb
shimmer = composed.shimmer_reverb(buf, mix=0.4, shimmer=0.3)
# Brighter shimmer with more pitch blend
bright = composed.shimmer_reverb(buf, shimmer=0.6, shift_semitones=12.0, preset="cathedral")
# Fifth-up shimmer for a different harmonic flavor
fifth = composed.shimmer_reverb(buf, shimmer=0.4, shift_semitones=7.0)
Tape echo¶
# Classic tape delay with darkening repeats
echo = composed.tape_echo(buf, delay_ms=300.0, feedback=0.5, tone=3000.0)
# Dark, saturated echoes
warm = composed.tape_echo(buf, delay_ms=400.0, feedback=0.6, tone=1500.0, drive=0.5)
# Fast slapback-style
slap = composed.tape_echo(buf, delay_ms=100.0, feedback=0.3, repeats=3)
Lo-fi¶
# Default lo-fi degradation
lofi = composed.lo_fi(buf)
# Heavy bitcrushing with bandwidth reduction
crushed = composed.lo_fi(buf, bit_depth=4, reduce=0.7, tone=2000.0)
Telephone¶
# Standard telephone bandpass (300-3400 Hz) with saturation
phone = composed.telephone(buf)
# AM radio simulation (wider bandwidth, less distortion)
radio = composed.telephone(buf, low_cut=500.0, high_cut=5000.0, drive=0.2)
Gated reverb¶
# Classic 80s gated reverb
gated = composed.gated_reverb(buf, preset="plate", mix=0.5)
# Tight, punchy gate
tight = composed.gated_reverb(
buf, gate_threshold_db=-20.0, gate_hold_ms=30.0, gate_release=0.01
)
Auto-pan¶
# Moderate stereo auto-panning
panned = composed.auto_pan(buf, rate=2.0, depth=1.0)
# Slow, subtle movement
gentle = composed.auto_pan(buf, rate=0.5, depth=0.5)
# Fast tremolo-like panning
fast = composed.auto_pan(buf, rate=6.0, depth=1.0)
Mastering chain¶
# Full mastering chain: DC block -> EQ -> compress -> limit -> loudness normalize
mastered = composed.master(buf, target_lufs=-14.0)
# With custom EQ settings
mastered = composed.master(buf, target_lufs=-14.0, eq={
"low_shelf_hz": 80.0,
"low_shelf_db": 1.0,
"high_shelf_hz": 12000.0,
"high_shelf_db": 0.5,
})
# Skip compression stage
mastered = composed.master(buf, compress_on=False)
Vocal processing chain¶
# Full vocal chain: de-ess -> EQ -> compress -> limit
vocals = composed.vocal_chain(buf, de_ess_freq=6000.0)
# With loudness target
vocals = composed.vocal_chain(buf, target_lufs=-16.0)
# Custom settings
vocals = composed.vocal_chain(
buf,
de_ess=True,
de_ess_freq=5500.0,
compress_on=True,
limit_on=True,
eq={"low_shelf_hz": 100.0, "low_shelf_db": -2.0},
)
API reference¶
composed
¶
Composed effects -- exciter, de-esser, mastering, vocal chain, etc.
exciter
¶
Add harmonics above freq via saturation.
Highpass-filters, saturates to generate harmonics, highpasses again to clean up, and blends back into the original.
| PARAMETER | DESCRIPTION |
|---|---|
freq
|
Crossover frequency in Hz, > 0 and < Nyquist. Typical: 2000--8000.
TYPE:
|
amount
|
Harmonic blend amount, >= 0. 0.0 = no effect, 1.0 = equal blend. Typical: 0.1--0.5.
TYPE:
|
de_esser
¶
de_esser(
buf: AudioBuffer,
freq: float = 6000.0,
threshold_db: float = -20.0,
ratio: float = 4.0,
bandwidth: float = 2.0,
) -> AudioBuffer
Reduce sibilance around freq Hz.
Extracts the sibilant band, compresses it, and replaces the original band with the compressed version.
| PARAMETER | DESCRIPTION |
|---|---|
freq
|
Center frequency of the sibilant band in Hz, > 0 and < Nyquist. Typical: 4000--10000.
TYPE:
|
threshold_db
|
Compression threshold in dB. Typical: -30 to -10.
TYPE:
|
ratio
|
Compression ratio, >= 1. Typical: 3--10.
TYPE:
|
bandwidth
|
Band width in octaves, > 0. Typical: 1--3.
TYPE:
|
parallel_compress
¶
parallel_compress(
buf: AudioBuffer,
mix: float = 0.5,
ratio: float = 8.0,
threshold_db: float = -30.0,
attack: float = 0.001,
release: float = 0.05,
) -> AudioBuffer
Blend heavily compressed signal with dry signal (New York compression).
| PARAMETER | DESCRIPTION |
|---|---|
mix
|
Wet/dry blend, 0.0--1.0 (0.0 = fully dry, 1.0 = fully compressed).
TYPE:
|
ratio
|
Compression ratio, >= 1. Typical: 4--20.
TYPE:
|
threshold_db
|
Compression threshold in dB. Typical: -40 to -10.
TYPE:
|
attack
|
Attack time in seconds, > 0. Typical: 0.001--0.01.
TYPE:
|
release
|
Release time in seconds, > 0. Typical: 0.01--0.2.
TYPE:
|
stereo_delay
¶
stereo_delay(
buf: AudioBuffer,
left_ms: float = 250.0,
right_ms: float = 375.0,
feedback: float = 0.3,
mix: float = 0.5,
ping_pong: bool = False,
) -> AudioBuffer
Stereo delay effect.
| PARAMETER | DESCRIPTION |
|---|---|
left_ms
|
Delay times for left and right channels in milliseconds.
TYPE:
|
right_ms
|
Delay times for left and right channels in milliseconds.
TYPE:
|
feedback
|
Feedback amount (0.0 to <1.0).
TYPE:
|
mix
|
Wet/dry blend (0.0 = dry, 1.0 = fully wet).
TYPE:
|
ping_pong
|
If True, feedback crosses between L/R channels.
TYPE:
|
multiband_compress
¶
multiband_compress(
buf: AudioBuffer,
crossover_freqs: list[float] | None = None,
ratios: list[float] | None = None,
thresholds: list[float] | None = None,
attack: float = 0.01,
release: float = 0.1,
) -> AudioBuffer
Split into frequency bands, compress each independently, and recombine.
| PARAMETER | DESCRIPTION |
|---|---|
crossover_freqs
|
Crossover frequencies in Hz. Defaults to [200, 2000, 8000] (4 bands).
TYPE:
|
ratios
|
Compression ratio per band (len = len(crossover_freqs) + 1). Defaults to [2.0, 3.0, 3.0, 2.0].
TYPE:
|
thresholds
|
Threshold in dB per band. Defaults to [-24, -20, -20, -18].
TYPE:
|
attack
|
Attack/release times in seconds, shared across all bands.
TYPE:
|
release
|
Attack/release times in seconds, shared across all bands.
TYPE:
|
vocoder
¶
vocoder(
modulator: AudioBuffer,
carrier: AudioBuffer,
n_bands: int = 16,
freq_range: tuple[float, float] = (80.0, 8000.0),
env_cutoff: float = 50.0,
) -> AudioBuffer
Channel vocoder.
Splits both signals into n_bands logarithmically-spaced frequency bands, extracts the amplitude envelope from each modulator band, and applies it to the corresponding carrier band. The classic "robot voice" effect when the modulator is speech and the carrier is a rich waveform (saw, noise, chord).
| PARAMETER | DESCRIPTION |
|---|---|
modulator
|
Signal whose spectral envelope shapes the output (e.g. speech).
TYPE:
|
carrier
|
Signal whose timbre fills the output (e.g. sawtooth, noise). Must have the same frame count and sample rate as modulator.
TYPE:
|
n_bands
|
Number of analysis/synthesis bands, >= 1. Typical: 8--32.
TYPE:
|
freq_range
|
(low_hz, high_hz) frequency range for the filterbank. Both must be > 0 and < Nyquist.
TYPE:
|
env_cutoff
|
Lowpass cutoff in Hz for envelope smoothing, > 0. Typical: 20--100. Lower = smoother envelopes, higher = more articulation.
TYPE:
|
formant_filter
¶
Apply vowel formant filter using cascaded bandpass biquads.
| PARAMETER | DESCRIPTION |
|---|---|
vowel
|
Vowel index (0-4) or name ('a', 'e', 'i', 'o', 'u').
TYPE:
|
psola_pitch_shift
¶
Pitch shift using PSOLA (Pitch-Synchronous Overlap-Add).
| PARAMETER | DESCRIPTION |
|---|---|
semitones
|
Pitch shift in semitones (positive = up, negative = down).
TYPE:
|
master
¶
master(
buf: AudioBuffer,
target_lufs: float = -14.0,
eq: dict | None = None,
compress_on: bool = True,
limit_on: bool = True,
dc_block_on: bool = True,
) -> AudioBuffer
Simple mastering chain.
Chain order: dc_block -> EQ -> compress -> limit -> normalize_lufs.
| PARAMETER | DESCRIPTION |
|---|---|
eq
|
Optional EQ with keys:
-
TYPE:
|
compress_on
|
Enable compression stage.
TYPE:
|
limit_on
|
Enable limiting stage.
TYPE:
|
dc_block_on
|
Enable DC blocking stage.
TYPE:
|
vocal_chain
¶
vocal_chain(
buf: AudioBuffer,
de_ess: bool = True,
de_ess_freq: float = 6000.0,
eq: dict | None = None,
compress_on: bool = True,
limit_on: bool = True,
target_lufs: float | None = None,
) -> AudioBuffer
Vocal processing chain: de-esser -> EQ -> compress -> limit -> normalize.
| PARAMETER | DESCRIPTION |
|---|---|
de_ess
|
Enable de-essing stage.
TYPE:
|
de_ess_freq
|
De-esser center frequency in Hz.
TYPE:
|
eq
|
EQ settings (same format as :func:
TYPE:
|
compress_on
|
Enable compression (ratio=4, threshold=-24dB, moderate attack/release).
TYPE:
|
limit_on
|
Enable limiter.
TYPE:
|
target_lufs
|
If set, normalize to this loudness. Requires signal >= 400ms.
TYPE:
|
ping_pong_delay
¶
ping_pong_delay(
buf: AudioBuffer,
delay_ms: float = 375.0,
feedback: float = 0.5,
mix: float = 0.5,
) -> AudioBuffer
Stereo ping-pong delay with crossed feedback.
The delayed signal bounces between left and right channels. Mono input is duplicated to stereo before processing.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio (mono or stereo).
TYPE:
|
delay_ms
|
Delay time in milliseconds (same for both channels).
TYPE:
|
feedback
|
Feedback amount (-0.99 to 0.99). Negative values invert phase.
TYPE:
|
mix
|
Dry/wet blend (0.0 = dry, 1.0 = fully wet).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AudioBuffer
|
Stereo ping-pong delayed audio. |
freq_shift
¶
Shift all frequencies by a fixed amount in Hz.
Unlike pitch shifting, frequency shifting does not preserve harmonic relationships. A 440 Hz tone shifted +100 Hz becomes 540 Hz (not the musical interval you would get from pitch shifting).
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
shift_hz
|
Shift amount in Hz. Positive = up, negative = down.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AudioBuffer
|
Frequency-shifted audio. |
ring_mod
¶
ring_mod(
buf: AudioBuffer,
carrier_freq: float = 440.0,
mix: float = 1.0,
lfo_freq: float = 0.0,
lfo_width: float = 0.0,
) -> AudioBuffer
Ring modulation -- multiply input by a carrier sine wave.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
carrier_freq
|
Carrier oscillator frequency in Hz.
TYPE:
|
mix
|
Dry/wet blend (0.0 = dry, 1.0 = fully modulated).
TYPE:
|
lfo_freq
|
LFO rate in Hz that modulates the carrier frequency.
TYPE:
|
lfo_width
|
LFO modulation depth in Hz.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AudioBuffer
|
Ring-modulated audio. |
shimmer_reverb
¶
shimmer_reverb(
buf: AudioBuffer,
mix: float = 0.4,
decay: float = 0.8,
shimmer: float = 0.3,
shift_semitones: float = 12.0,
preset: Literal[
"room", "hall", "plate", "chamber", "cathedral"
] = "hall",
) -> AudioBuffer
Reverb with a pitch-shifted shimmer layer.
Applies reverb, then pitch-shifts the reverb tail and blends the shifted layer back in. Creates the ethereal, rising-tone reverb popular in ambient and post-rock.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
mix
|
Overall wet/dry blend (0.0 = dry, 1.0 = fully wet).
TYPE:
|
decay
|
Reverb decay time (0.0 to 1.0).
TYPE:
|
shimmer
|
Blend of pitched layer within the wet signal (0.0 to 1.0).
TYPE:
|
shift_semitones
|
Pitch shift for shimmer layer in semitones (default +12 = octave up).
TYPE:
|
preset
|
Reverb preset ('room', 'hall', 'plate', 'chamber', 'cathedral').
TYPE:
|
tape_echo
¶
tape_echo(
buf: AudioBuffer,
delay_ms: float = 300.0,
feedback: float = 0.5,
repeats: int = 6,
tone: float = 3000.0,
drive: float = 0.3,
mix: float = 0.5,
) -> AudioBuffer
Multi-tap delay with progressive darkening and tape saturation.
Each repeat passes through a lowpass filter and tape-style saturation, so later echoes are progressively darker and warmer -- like a real analog tape delay unit.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
delay_ms
|
Delay time per repeat in milliseconds.
TYPE:
|
feedback
|
Gain decay per repeat (0.0 to <1.0).
TYPE:
|
repeats
|
Number of echo taps to generate.
TYPE:
|
tone
|
Lowpass cutoff in Hz applied per repeat (lower = darker tails).
TYPE:
|
drive
|
Tape saturation amount per repeat (0.0 = clean).
TYPE:
|
mix
|
Wet/dry blend (0.0 = dry, 1.0 = only echoes).
TYPE:
|
lo_fi
¶
lo_fi(
buf: AudioBuffer,
bit_depth: int = 8,
reduce: float = 0.5,
drive: float = 0.3,
tone: float = 4000.0,
) -> AudioBuffer
Lo-fi degradation: bitcrush, sample-rate reduction, saturation, lowpass.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
bit_depth
|
Bit depth for quantization (lower = crunchier).
TYPE:
|
reduce
|
Sample-rate reduction amount (0.0 = none, 1.0 = maximum).
TYPE:
|
drive
|
Tape saturation amount.
TYPE:
|
tone
|
Lowpass cutoff in Hz (simulates bandwidth reduction).
TYPE:
|
telephone
¶
telephone(
buf: AudioBuffer,
low_cut: float = 300.0,
high_cut: float = 3400.0,
drive: float = 0.4,
) -> AudioBuffer
Telephone/radio filter: tight bandpass with saturation.
Simulates the limited bandwidth and nonlinearity of a telephone codec or AM radio transmission.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
low_cut
|
Highpass cutoff in Hz (default 300 = telephone standard).
TYPE:
|
high_cut
|
Lowpass cutoff in Hz (default 3400 = telephone standard).
TYPE:
|
drive
|
Saturation amount (adds harmonic grit).
TYPE:
|
gated_reverb
¶
gated_reverb(
buf: AudioBuffer,
preset: Literal[
"room", "hall", "plate", "chamber", "cathedral"
] = "plate",
decay: float = 0.7,
gate_threshold_db: float = -30.0,
gate_hold_ms: float = 50.0,
gate_release: float = 0.02,
mix: float = 0.5,
) -> AudioBuffer
Reverb followed by a noise gate for truncated, punchy tails.
Classic 80s production technique: a dense reverb is abruptly cut by a gate, producing a powerful burst that stops dead.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio.
TYPE:
|
preset
|
Reverb preset ('room', 'hall', 'plate', 'chamber', 'cathedral').
TYPE:
|
decay
|
Reverb decay time (0.0 to 1.0).
TYPE:
|
gate_threshold_db
|
Gate threshold in dB (below this the reverb is silenced).
TYPE:
|
gate_hold_ms
|
Gate hold time in ms before release begins.
TYPE:
|
gate_release
|
Gate release time in seconds.
TYPE:
|
mix
|
Wet/dry blend (0.0 = dry, 1.0 = fully wet).
TYPE:
|
auto_pan
¶
auto_pan(
buf: AudioBuffer,
rate: float = 2.0,
depth: float = 1.0,
center: float = 0.0,
) -> AudioBuffer
LFO-driven stereo panning.
A sine LFO sweeps the signal between left and right channels using equal-power panning. Mono and stereo inputs are both supported; stereo inputs are summed to mono before panning.
| PARAMETER | DESCRIPTION |
|---|---|
buf
|
Input audio (mono or stereo).
TYPE:
|
rate
|
LFO frequency in Hz.
TYPE:
|
depth
|
Panning depth (0.0 = no movement, 1.0 = full L/R sweep).
TYPE:
|
center
|
Pan center position (-1.0 = left, 0.0 = center, 1.0 = right).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AudioBuffer
|
Stereo auto-panned audio. |