Skip to content

audiojs/effect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@audio/effect

Canonical audio effect implementations.

Modulation
Phaser · Flanger · Chorus · Wah-wah · Tremolo · Vibrato · Rotary speaker · Ring mod · Frequency shifter · Pitch shifter · Auto-wah

Dynamics
moved to @audio/dynamics

Delay
Delay · Multitap · Ping-pong · Reverb

Distortion
Distortion / saturation · Exciter · Bitcrusher

Spatial
Stereo widener · Haas effect · Panner · Auto-panner

Utility
Gain · Mixer · Slew limiter · Noise shaping · Tape stop

Install

npm install @audio/effect
// import everything
import * as fx from '@audio/effect'

// pick what you need
import { phaser, flanger, chorus, wah, autoWah, ringMod, frequencyShifter } from '@audio/effect'
import { delay, multitap, pingPong }                            from '@audio/effect'
import { distortion, exciter, bitcrusher }                      from '@audio/effect'
import { gain, mixer, slewLimiter, noiseShaping }               from '@audio/effect'

// sibling families
import { compressor, limiter, gate, envelope, expander }        from '@audio/dynamics'
import { stereoWidener, haas, panner, autoPanner }              from '@audio/spatial'
import { freeverb, dattorro, convolve }                         from '@audio/reverb'

API

All effects share one shape:

effect(buffer, params)   // → buffer (modified in-place)

Takes a Float32Array/Float64Array, modifies it in-place, returns it. Pass the same params object on every call — internal state (_phase, _env, etc.) persists across blocks automatically:

let params = { rate: 1, depth: 0.7, fc: 1000, fs: 44100 }
for (let buf of stream) phaser(buf, params)

Spatial effects take two channels and return [left, right]:

stereoWidener(left, right, { width: 1.5 })   // → [left, right]
haas(left, right, { time: 0.02, fs: 44100 }) // → [left, right]
panner(left, right, { pan: -0.5 })           // → [left, right]

Modulation

LFO-driven effects that vary a parameter periodically.

Phaser

Cascade of swept allpass filters creating moving notches and peaks.

rate LFO rate in Hz (default 0.5) · depth sweep depth 0–1 (default 0.7) · stages allpass stages (default 4) · feedback 0–1 (default 0.5) · fc center frequency Hz (default 1000) · fs sample rate

import { phaser } from '@audio/effect'

let p = { rate: 0.5, depth: 0.7, stages: 4, feedback: 0.5, fc: 1000, fs: 44100 }
for (let buf of stream) phaser(buf, p)

Use when: electric guitar, synth pads, vintage phase effects
Not for: spatial positioning (use stereoWidener or haas)

Flanger

Modulated short delay (1–10 ms) with feedback — creates comb filter sweep.

rate LFO rate in Hz (default 0.3) · depth modulation depth 0–1 (default 0.7) · delay center delay in seconds (default 0.003) · feedback 0–1 (default 0.5) · fs sample rate

import { flanger } from '@audio/effect'

let p = { rate: 0.3, depth: 0.7, delay: 0.003, feedback: 0.5, fs: 44100 }
for (let buf of stream) flanger(buf, p)

Use when: jet sweeps, metallic modulation, guitar/bass
Not for: subtle pitch modulation (use vibrato)

Chorus

Multiple detuned delay voices layered over dry signal — ensemble thickening.

rate LFO rate in Hz (default 1.5) · depth modulation depth 0–1 (default 0.5) · delay center delay in seconds (default 0.02) · voices number of chorus voices (default 3) · fs sample rate

import { chorus } from '@audio/effect'

let p = { rate: 1.5, depth: 0.5, delay: 0.02, voices: 3, fs: 44100 }
for (let buf of stream) chorus(buf, p)

Use when: thickening strings, vocals, synth pads
Not for: transparent processing (adds modulation artifacts)

Wah-wah

Swept resonant bandpass filter — auto (LFO) or fixed frequency mode.

rate LFO rate in Hz (default 1.5) · depth sweep depth in octaves, 0–3 (default 0.8) · fc center frequency Hz (default 1000) · Q resonance (default 5) · mode 'auto' LFO or 'manual' fixed (default 'auto') · fs sample rate

import { wah } from '@audio/effect'

let p = { rate: 1.5, depth: 0.8, fc: 1000, Q: 5, fs: 44100 }
for (let buf of stream) wah(buf, p)

Use when: classic wah sound, filter sweeps
Not for: signal-driven wah (use autoWah)

Tremolo

Amplitude modulation via LFO — periodic volume pulsing.

rate LFO rate in Hz (default 5) · depth modulation depth 0–1 (default 0.5) · fs sample rate

import { tremolo } from '@audio/effect'

let p = { rate: 5, depth: 0.7, fs: 44100 }
for (let buf of stream) tremolo(buf, p)

Use when: vintage amp tremolo, rhythmic pulsing, guitar effects
Not for: pitch modulation (use vibrato)

Vibrato

Pitch modulation via modulated delay line — periodic pitch wobble.

rate LFO rate in Hz (default 5) · depth modulation depth 0–1, scales a max ~6ms delay-time swing (default 0.5) · fs sample rate

import { vibrato } from '@audio/effect'

let p = { rate: 5, depth: 0.5, fs: 44100 }
for (let buf of stream) vibrato(buf, p)

Use when: vocal vibrato, string wobble, instrument simulation
Not for: amplitude variation (use tremolo)

Rotary speaker

Leslie cabinet simulation — a treble horn and bass drum spin at independent, inertia-limited rates below a crossover split, each producing Doppler pitch modulation and directivity amplitude modulation as they turn past two virtual mics. Mono in, stereo out.

hornSpeed/drumSpeed rotor rates in Hz (default 0.8/0.7 chorale · 6.7/5.9 tremolo · 0/0 off) · crossover horn/drum split in Hz (default 800) · depth modulation intensity 0–1 (default 1) · hornInertia/drumInertia spin-up/down time constants in seconds (default 0.6/2.5 — the heavier drum lags the horn) · micSpread angle between the two virtual mics in radians (default π/2) · mix wet/dry 0–1 (default 1) · fs sample rate

import { rotary } from '@audio/effect'

// mono in, stereo out: pre-fill both channels with the same dry signal
let left = Float64Array.from(mono), right = Float64Array.from(mono)
let p = { hornSpeed: 6.7, drumSpeed: 5.9, fs: 44100 }
rotary(left, right, p)   // left, right now hold the two virtual-mic outputs

Switching hornSpeed/drumSpeed mid-stream glides through the inertia model instead of snapping — the classic chorale↔tremolo swell.

Use when: organ/guitar Leslie emulation, spinning-speaker swells
Not for: plain stereo chorus (use chorus) or static stereo widening (use @audio/spatial)

Ring mod

Multiplies signal by a carrier oscillator — produces sum and difference frequencies.

fc carrier frequency Hz (default 440) · mix wet/dry 0–1 (default 1) · fs sample rate

import { ringMod } from '@audio/effect'

let p = { fc: 300, mix: 1, fs: 44100 }
for (let buf of stream) ringMod(buf, p)

Use when: metallic/robotic tones, experimental textures, AM synthesis
Not for: clean frequency shifting

Frequency shifter

Single-sideband frequency shift via Hilbert transform. Every frequency moves by a constant offset (unlike ring mod, which produces sum/difference pairs; unlike pitch shifter, which preserves harmonic ratios). Breaks harmonic relationships → inharmonic, metallic, clangorous.

shift shift in Hz (default 100 · positive = up, negative = down) · mix wet/dry 0–1 (default 1) · taps Hilbert FIR length, must be odd (default 65) · fs sample rate

import { frequencyShifter } from '@audio/effect'

let p = { shift: 200, fs: 44100 }
for (let buf of stream) frequencyShifter(buf, p)

Use when: clangorous barber-pole tones, Bode-style modulation, Moog-style frequency shifting
Not for: musical transposition (use pitch shifter or the @audio/shift package)

Pitch shifter

Moved to @audio/shift — 15 algorithms from granular to phase-vocoder to PSOLA:

import { granular } from '@audio/shift'

let out = granular(buf, { ratio: 1.5 })

Auto-wah

Envelope follower drives a resonant bandpass filter — signal level controls the sweep.

base minimum cutoff Hz (default 300) · range sweep range Hz (default 3000) · Q resonance (default 5) · attack envelope attack seconds (default 0.002) · release envelope release seconds (default 0.1) · sens input sensitivity multiplier (default 2) · fs sample rate

import { autoWah } from '@audio/effect'

let p = { base: 300, range: 3000, Q: 5, sens: 2, fs: 44100 }
for (let buf of stream) autoWah(buf, p)

Use when: funk guitar, touch-sensitive filter sweeps, envelope filter
Not for: LFO-driven wah (use wah with mode: 'auto')

Dynamics

Dynamics processing lives in @audio/dynamics — compressor, limiter, gate, expander, deesser, ducker, softclip, compand, multiband, character models (fet/opto/vca/varimu), leveler. See its README for the accurate API (note: dynamics kernels read sampleRate, not fs, and attack/release are in ms).

Delay

Time-based echo and reverberation effects.

Delay

Simple delay — dry signal mixed with delayed copy and optional feedback.

time delay time in seconds (default 0.25) · feedback echo decay 0–1 (default 0.3) · mix wet/dry 0–1 (default 0.5) · fs sample rate

import { delay } from '@audio/effect'

let p = { time: 0.25, feedback: 0.4, mix: 0.5, fs: 44100 }
for (let buf of stream) delay(buf, p)

Use when: slap-back echo, rhythmic delays, tape delay emulation
Not for: diffuse reverberation (use reverb)

Multitap

Multiple independent delay taps at different times with individual gains.

taps array of { time, gain } objects · fs sample rate

import { multitap } from '@audio/effect'

let p = {
  taps: [{ time: 0.1, gain: 0.6 }, { time: 0.25, gain: 0.4 }, { time: 0.4, gain: 0.2 }],
  fs: 44100
}
for (let buf of stream) multitap(buf, p)

Use when: complex rhythmic echo patterns, vintage tape echo with multiple heads
Not for: simple single echo (use delay)

Ping-pong

Cross-fed stereo delay — left echo bounces to right, right to left.

time delay time in seconds (default 0.25) · feedback 0–1 (default 0.3) · mix wet/dry 0–1 (default 0.5) · fs sample rate

import { pingPong } from '@audio/effect'

let p = { time: 0.15, feedback: 0.5, mix: 0.5, fs: 44100 }
for (let [L, R] of stereoStream) pingPong(L, R, p)

Use when: stereo width from delays, spatial depth, rhythmic bounce effects
Not for: mono output

Reverb

Promoted to @audio/reverb — Schroeder, Freeverb, Dattorro, convolution, FDN, spring, shimmer:

import { freeverb } from '@audio/reverb'

let out = freeverb(buf, { decay: 0.84, damping: 0.5, mix: 0.3, fs: 44100 })

Distortion

Non-linear waveshaping effects.

Distortion / saturation

Four waveshaping types: cubic soft clip, hard clip, tanh saturation, and wavefolding.

drive distortion amount 0–1 (default 0.5, maps to 1–10× input gain) · type 'soft' | 'hard' | 'tanh' | 'foldback' (default 'soft') · mix wet/dry 0–1 (default 1) · fs sample rate

import { distortion } from '@audio/effect'

// Soft saturation
let p = { drive: 0.6, type: 'soft', fs: 44100 }
for (let buf of stream) distortion(buf, p)

// Hard clip
distortion(buf, { drive: 0.8, type: 'hard' })

// Tanh (asymptotically smooth, never clips hard)
distortion(buf, { drive: 0.5, type: 'tanh' })

// Wavefolding (metallic/harsh)
distortion(buf, { drive: 0.7, type: 'foldback' })
type character clamps at ±1
soft cubic saturation, smooth knee yes
hard brickwall clip, harsh yes
tanh asymptotically smooth approaches 1
foldback metallic, complex harmonics yes

Use when: guitar overdrive, tube saturation, lo-fi crunch, harmonic enrichment
Not for: transparent limiting (use limiter)

Exciter

Aphex-style aural exciter. Extracts the high band via SVF highpass, runs it through tanh saturation to synthesize harmonics, then mixes the harmonic residue back into the dry signal. Adds perceived "air" and "presence" without EQ boost.

freq highpass cutoff Hz (default 3000) · drive saturation amount 0–1 (default 0.5, maps to 1–10× gain) · amount mix-in level 0–1 (default 0.5) · fs sample rate

import { exciter } from '@audio/effect'

let p = { freq: 4000, drive: 0.6, amount: 0.4, fs: 44100 }
for (let buf of stream) exciter(buf, p)

Use when: dull vocals, lifeless cymbals, mastering polish, restoring high-end after compression
Not for: spectral shaping (use a shelf/EQ from @audio/filter) — exciter adds harmonics, not gain

Bitcrusher

Sample-rate reduction (zero-order hold) + bit-depth quantization.

bits target bit depth 1–24 (default 8) · rate sample rate ratio 0–1 (default 0.25, quarter rate) · fs sample rate

import { bitcrusher } from '@audio/effect'

// 8-bit, quarter sample rate (lo-fi)
let p = { bits: 8, rate: 0.25, fs: 44100 }
for (let buf of stream) bitcrusher(buf, p)

// Bit depth only, no rate reduction
bitcrusher(buf, { bits: 4, rate: 1 })

Use when: lo-fi aesthetics, game audio, retro console sound, stutter effects
Not for: smooth saturation (use distortion)

Spatial

Stereo image and positioning effects. All take (left, right, params) and return [left, right].

Stereo widener

Mid/side processing to widen or narrow the stereo image.

width 0 = mono, 1 = unchanged, 2 = full side emphasis (default 1.5)

import { stereoWidener } from '@audio/spatial'

let p = { width: 1.5 }
for (let [L, R] of stereoStream) stereoWidener(L, R, p)

Use when: widening narrow mixes, mono-compatibility check (width=0), mastering
Not for: positioning a single source (use panner)

Haas effect

Delays one channel by 1–35 ms — creates phantom stereo from mono source.

time delay in seconds (default 0.02 = 20 ms) · channel 'left' or 'right' (default 'right') · fs sample rate

import { haas } from '@audio/spatial'

let p = { time: 0.015, channel: 'right', fs: 44100 }
for (let [L, R] of stereoStream) haas(L, R, p)

Use when: mono-to-stereo widening, spatial placement, drum room simulation
Not for: large delays (use ping-pong delay instead)

Panner

Constant-power stereo panning using cos/sin law.

pan −1 = full left, 0 = center, +1 = full right (default 0)

import { panner } from '@audio/spatial'

let p = { pan: -0.3 }
for (let [L, R] of stereoStream) panner(L, R, p)

Use when: placing sources in the stereo field
Not for: 3D spatial audio

Auto-panner

LFO-driven constant-power pan — signal sweeps between speakers periodically.

rate LFO rate in Hz (default 0.5) · depth sweep depth 0–1 (default 1, full excursion) · fs sample rate

import { autoPanner } from '@audio/spatial'

let p = { rate: 0.5, depth: 1, fs: 44100 }
for (let [L, R] of stereoStream) autoPanner(L, R, p)

Use when: rhythmic stereo motion, ambient spatialization, auto-panning leads
Not for: static placement (use panner)

Utility

Signal conditioning and mixing tools.

Gain

Simple level adjustment in decibels.

dB gain in dB (default 0)

import { gain } from '@audio/effect'

for (let buf of stream) gain(buf, { dB: -6 })

Mixer

Sums an array of buffers with individual gain multipliers.

channels array of { buffer, gain } objects

import { mixer } from '@audio/effect'

let out = mixer([
  { buffer: drums,  gain: 0.8 },
  { buffer: bass,   gain: 0.7 },
  { buffer: synth,  gain: 0.5 },
])

Use when: combining signals, bus summing, stem mixing

Slew limiter

Clips the derivative — limits how fast the signal can change.

rise maximum rise rate in units/second (default 1000) · fall maximum fall rate (default 1000) · fs sample rate

import { slewLimiter } from '@audio/effect'

let p = { rise: 5000, fall: 5000, fs: 44100 }
for (let buf of stream) slewLimiter(buf, p)

Use when: click removal, smoothing control signals, limiting slew on CVs
Not for: dynamic range control

Noise shaping

Error-feedback quantization — shapes quantization noise out of the audible band.

bits target bit depth (default 16)

import { noiseShaping } from '@audio/effect'

for (let buf of stream) noiseShaping(buf, { bits: 16 })

Use when: dithering before bit-depth reduction, quantization to lower bit depths
Not for: audio compression (unrelated to lossy codecs)

Tape stop

Variable-rate playback with a decelerating (or accelerating) read pointer — turntable power-off / tape-deck stop, and the reverse spin-up. Whole-buffer effect: needs the full signal in one call, not a per-block stream.

at when the stop/start begins, in seconds (default 0) · time ramp duration in seconds (default 1) · curve speed-profile exponent — 1 = physical constant-torque linear decay, >1 = faster initial drop, <1 = held then dropping (default 1) · direction 'stop' or 'start' (default 'stop') · flutter 0–1 random rate wobble during the ramp (default 0)

import { tapeStop } from '@audio/effect'

tapeStop(buf, { at: 2, time: 1.5, direction: 'stop', fs: 44100 })

Use when: DJ/turntable power-off, tape-deck stop/start, transition sweeps
Not for: continuous pitch modulation (use vibrato) or tempo-locked time-stretch

About

Canonical audio effects collection

Resources

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors