Skip to content

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

exciter(
    buf: AudioBuffer,
    freq: float = 3000.0,
    amount: float = 0.3,
) -> AudioBuffer

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: float DEFAULT: 3000.0

amount

Harmonic blend amount, >= 0. 0.0 = no effect, 1.0 = equal blend. Typical: 0.1--0.5.

TYPE: float DEFAULT: 0.3

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: float DEFAULT: 6000.0

threshold_db

Compression threshold in dB. Typical: -30 to -10.

TYPE: float DEFAULT: -20.0

ratio

Compression ratio, >= 1. Typical: 3--10.

TYPE: float DEFAULT: 4.0

bandwidth

Band width in octaves, > 0. Typical: 1--3.

TYPE: float DEFAULT: 2.0

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: float DEFAULT: 0.5

ratio

Compression ratio, >= 1. Typical: 4--20.

TYPE: float DEFAULT: 8.0

threshold_db

Compression threshold in dB. Typical: -40 to -10.

TYPE: float DEFAULT: -30.0

attack

Attack time in seconds, > 0. Typical: 0.001--0.01.

TYPE: float DEFAULT: 0.001

release

Release time in seconds, > 0. Typical: 0.01--0.2.

TYPE: float DEFAULT: 0.05

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: float DEFAULT: 250.0

right_ms

Delay times for left and right channels in milliseconds.

TYPE: float DEFAULT: 250.0

feedback

Feedback amount (0.0 to <1.0).

TYPE: float DEFAULT: 0.3

mix

Wet/dry blend (0.0 = dry, 1.0 = fully wet).

TYPE: float DEFAULT: 0.5

ping_pong

If True, feedback crosses between L/R channels.

TYPE: bool DEFAULT: False

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: list[float] or None DEFAULT: None

ratios

Compression ratio per band (len = len(crossover_freqs) + 1). Defaults to [2.0, 3.0, 3.0, 2.0].

TYPE: list[float] or None DEFAULT: None

thresholds

Threshold in dB per band. Defaults to [-24, -20, -20, -18].

TYPE: list[float] or None DEFAULT: None

attack

Attack/release times in seconds, shared across all bands.

TYPE: float DEFAULT: 0.01

release

Attack/release times in seconds, shared across all bands.

TYPE: float DEFAULT: 0.01

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: AudioBuffer

carrier

Signal whose timbre fills the output (e.g. sawtooth, noise). Must have the same frame count and sample rate as modulator.

TYPE: AudioBuffer

n_bands

Number of analysis/synthesis bands, >= 1. Typical: 8--32.

TYPE: int DEFAULT: 16

freq_range

(low_hz, high_hz) frequency range for the filterbank. Both must be > 0 and < Nyquist.

TYPE: tuple[float, float] DEFAULT: (80.0, 8000.0)

env_cutoff

Lowpass cutoff in Hz for envelope smoothing, > 0. Typical: 20--100. Lower = smoother envelopes, higher = more articulation.

TYPE: float DEFAULT: 50.0

formant_filter

formant_filter(
    buf: AudioBuffer, vowel: int | str = "a"
) -> AudioBuffer

Apply vowel formant filter using cascaded bandpass biquads.

PARAMETER DESCRIPTION
vowel

Vowel index (0-4) or name ('a', 'e', 'i', 'o', 'u').

TYPE: int or str DEFAULT: 'a'

psola_pitch_shift

psola_pitch_shift(
    buf: AudioBuffer, semitones: float = 0.0
) -> AudioBuffer

Pitch shift using PSOLA (Pitch-Synchronous Overlap-Add).

PARAMETER DESCRIPTION
semitones

Pitch shift in semitones (positive = up, negative = down).

TYPE: float DEFAULT: 0.0

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: - 'low_shelf': (freq_hz, gain_db) or (freq_hz, gain_db, octaves) - 'high_shelf': (freq_hz, gain_db) or (freq_hz, gain_db, octaves) - 'peak': single (freq_hz, gain_db) or (freq_hz, gain_db, octaves), or a list of such tuples for multi-band.

TYPE: dict or None DEFAULT: None

compress_on

Enable compression stage.

TYPE: bool DEFAULT: True

limit_on

Enable limiting stage.

TYPE: bool DEFAULT: True

dc_block_on

Enable DC blocking stage.

TYPE: bool DEFAULT: True

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: bool DEFAULT: True

de_ess_freq

De-esser center frequency in Hz.

TYPE: float DEFAULT: 6000.0

eq

EQ settings (same format as :func:master). Defaults to a gentle vocal-friendly EQ: highpass at 80 Hz, +2 dB presence at 3 kHz, +1 dB air shelf at 12 kHz.

TYPE: dict or None DEFAULT: None

compress_on

Enable compression (ratio=4, threshold=-24dB, moderate attack/release).

TYPE: bool DEFAULT: True

limit_on

Enable limiter.

TYPE: bool DEFAULT: True

target_lufs

If set, normalize to this loudness. Requires signal >= 400ms.

TYPE: float or None DEFAULT: None

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: AudioBuffer

delay_ms

Delay time in milliseconds (same for both channels).

TYPE: float DEFAULT: 375.0

feedback

Feedback amount (-0.99 to 0.99). Negative values invert phase.

TYPE: float DEFAULT: 0.5

mix

Dry/wet blend (0.0 = dry, 1.0 = fully wet).

TYPE: float DEFAULT: 0.5

RETURNS DESCRIPTION
AudioBuffer

Stereo ping-pong delayed audio.

freq_shift

freq_shift(
    buf: AudioBuffer, shift_hz: float = 100.0
) -> AudioBuffer

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: AudioBuffer

shift_hz

Shift amount in Hz. Positive = up, negative = down.

TYPE: float DEFAULT: 100.0

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: AudioBuffer

carrier_freq

Carrier oscillator frequency in Hz.

TYPE: float DEFAULT: 440.0

mix

Dry/wet blend (0.0 = dry, 1.0 = fully modulated).

TYPE: float DEFAULT: 1.0

lfo_freq

LFO rate in Hz that modulates the carrier frequency.

TYPE: float DEFAULT: 0.0

lfo_width

LFO modulation depth in Hz.

TYPE: float DEFAULT: 0.0

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: AudioBuffer

mix

Overall wet/dry blend (0.0 = dry, 1.0 = fully wet).

TYPE: float DEFAULT: 0.4

decay

Reverb decay time (0.0 to 1.0).

TYPE: float DEFAULT: 0.8

shimmer

Blend of pitched layer within the wet signal (0.0 to 1.0).

TYPE: float DEFAULT: 0.3

shift_semitones

Pitch shift for shimmer layer in semitones (default +12 = octave up).

TYPE: float DEFAULT: 12.0

preset

Reverb preset ('room', 'hall', 'plate', 'chamber', 'cathedral').

TYPE: str DEFAULT: 'hall'

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: AudioBuffer

delay_ms

Delay time per repeat in milliseconds.

TYPE: float DEFAULT: 300.0

feedback

Gain decay per repeat (0.0 to <1.0).

TYPE: float DEFAULT: 0.5

repeats

Number of echo taps to generate.

TYPE: int DEFAULT: 6

tone

Lowpass cutoff in Hz applied per repeat (lower = darker tails).

TYPE: float DEFAULT: 3000.0

drive

Tape saturation amount per repeat (0.0 = clean).

TYPE: float DEFAULT: 0.3

mix

Wet/dry blend (0.0 = dry, 1.0 = only echoes).

TYPE: float DEFAULT: 0.5

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: AudioBuffer

bit_depth

Bit depth for quantization (lower = crunchier).

TYPE: int DEFAULT: 8

reduce

Sample-rate reduction amount (0.0 = none, 1.0 = maximum).

TYPE: float DEFAULT: 0.5

drive

Tape saturation amount.

TYPE: float DEFAULT: 0.3

tone

Lowpass cutoff in Hz (simulates bandwidth reduction).

TYPE: float DEFAULT: 4000.0

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: AudioBuffer

low_cut

Highpass cutoff in Hz (default 300 = telephone standard).

TYPE: float DEFAULT: 300.0

high_cut

Lowpass cutoff in Hz (default 3400 = telephone standard).

TYPE: float DEFAULT: 3400.0

drive

Saturation amount (adds harmonic grit).

TYPE: float DEFAULT: 0.4

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: AudioBuffer

preset

Reverb preset ('room', 'hall', 'plate', 'chamber', 'cathedral').

TYPE: str DEFAULT: 'plate'

decay

Reverb decay time (0.0 to 1.0).

TYPE: float DEFAULT: 0.7

gate_threshold_db

Gate threshold in dB (below this the reverb is silenced).

TYPE: float DEFAULT: -30.0

gate_hold_ms

Gate hold time in ms before release begins.

TYPE: float DEFAULT: 50.0

gate_release

Gate release time in seconds.

TYPE: float DEFAULT: 0.02

mix

Wet/dry blend (0.0 = dry, 1.0 = fully wet).

TYPE: float DEFAULT: 0.5

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: AudioBuffer

rate

LFO frequency in Hz.

TYPE: float DEFAULT: 2.0

depth

Panning depth (0.0 = no movement, 1.0 = full L/R sweep).

TYPE: float DEFAULT: 1.0

center

Pan center position (-1.0 = left, 0.0 = center, 1.0 = right).

TYPE: float DEFAULT: 0.0

RETURNS DESCRIPTION
AudioBuffer

Stereo auto-panned audio.