Everything you need to know about using, hacking, and understanding Resample-Lab.
Resample-Lab is a browser-based audio mutation lab. Upload any sound, pick a DSP preset, dial in the amount of chaos, and download a sample pack. The entire processing pipeline runs in a Web Worker using raw Float32Array math — no server, no AI, no WebAudio nodes, no external dependencies.
It was built to scratch a specific creative itch: fast, destructive, interesting sample generation that doesn't require loading a DAW, patching a modular synth, or praying to a model. Every parameter is deterministic. Every effect is a known DSP technique. If you want to know exactly why an output sounds the way it does, the code will tell you.
Local-first: All audio is decoded via AudioContext.decodeAudioData(), processed in a Web Worker, encoded to WAV, and zipped — all in the browser tab. Your files never leave your machine.
Zero AI: No neural networks, no black boxes. Every sample is produced by explicit signal processing: biquad filters, overlap-add time-stretching, granular slicing, convolution, and a dozen other classic techniques.
Chaos-driven: A single 0–1 knob modulates every parameter in the active preset simultaneously, letting you dial in anything from subtle texture to total destruction.
Every preset follows the same architecture: source → mutation → tape/tone → delay/reverb → finishing rack → output. Chaos maps into 8 lanes per preset (mutation, degradation, space, modulation, instability, finish, stereo, tail), so each preset responds differently to the same chaos value.
WSOLA time-stretch from 8× (clean) to 20× (illegal texture), followed by tape warmth, modulated hall reverb, and finishing rack. Chaos prioritizes space, tail, modulation, and stereo width — not degradation.
| Output | Chain | Character |
|---|---|---|
| cathedral_bed | WSOLA → tape(warm) → modulatedHall → finish(gentle) | Lush, cinematic, warm drone |
| toxic_air | Resample → reverse → diffusionDelay → darkRoom → tape(warm) → finish(gentle) | Smeared reverse wash with diffusion |
| doom_choir_drift | Lowpass → tape(cinematic_dark) → convolutionSmear → finish(warm) | Heavy, dark, convolution-soaked pad |
| submerged_pad | Lowpass → tape(sub_heavy) → modulatedHall → finish(gentle) | Deep, sub-heavy, underwater |
| reverse_bloom_long | Reverse → reverseBloom → tape(warm) → finish(gentle, long tail) | Swelling reverse bloom with warm tape |
Reverse-based effects with reverse delays, diffusion clouds, dark rooms, and metallic textures. Chaos prioritizes space, mutation, and tail extension.
| Output | Chain | Character |
|---|---|---|
| pre_impact_suck | Reverse → reverseDelay → darkRoom → tape(warm) → finish(gentle) | Short reverse pre-impact with suck |
| ghost_swell_long | Resample → reverse → darkRoom → tape(warm) → finish(gentle, long fade) | Long swelling ghost reverse |
| reverse_delay_cloud | Reverse → diffusionDelay → convolutionSmear → tape(subtle) → finish(gentle) | Diffused reverse delay into cloud |
| haunted_room_tail | Reverse → dirtyMetallic → tape(degraded) → finish(gentle) | Haunted metallic reverse decay |
Two engine modes: Concatenative shards (slices audio at 4 window sizes: 40–200ms, shuffles with seeded LCG PRNG, per-grain processing) and cloud mode (overlap-add with Hann/Tukey envelopes, random pan, pitch distribution, reverse probability, density/jitter control). Chaos prioritizes mutation, pan spread, and instability.
— Shard mode —
— Cloud mode —
Musical degradation — not just digital fracture. Tape loss (speed/age-dependent HF rolloff), cassette flutter, metallic reverb, and convolution smear. Chaos strongly prioritizes degradation, instability, and modulation.
| Output | Chain |
|---|---|
| rotted_room_loop | Downsample → bitcrush → tape(degraded) → darkRoom → finish |
| cassette_collapse | Downsample → tape(destroyed) → dirtyMetallic → finish(degraded) |
| speaker_cone_tear | Soft clip → bandpass → noise → dirtyMetallic → finish(limited) |
| bitcrushed_tail | Bitcrush → downsample → convolutionSmear → tape(degraded) → finish |
Pitch mutation via linear resampling with tape processing and convolution wash. Octave shifts are ±12–24 semitones. Chaos controls mutation intensity and instability.
Heuristic energy analysis finds loop-worthy sections. Sliding-window RMS, boundary correlation, transient scoring, and crossfade smoothing. Each candidate gets multiple finishing treatments.
Cinematic impact design. Filter sweeps, convolution reverb, reverse blooms, metallic hits, and sub-heavy collapses. Chaos amplifies tail length, space, and mutation. All outputs are peak-limited for safety.
Curated multi-preset mashup. Runs 7 sub-recipes with adjusted chaos, picking the most interesting output from each. Seven flavors of controlled entropy.
The chaos knob is a single 0–1 float that simultaneously modulates every parameter in the active preset. It's not a simple "more effect" knob — it shifts the behavior of each DSP transform along a spectrum from subtle to extreme.
| Label | Value | Stretch | Reverb | Bitcrush | Downsample | Drive | Pitch Range |
|---|---|---|---|---|---|---|---|
| Clean | 0.00 | 8× | 0.4 | 8 bit | 4× | 0.2 | ±4 st |
| Weird | 0.33 | 12× | 0.57 | 6 bit | 8× | 0.37 | ±11 st |
| Broken | 0.66 | 16× | 0.73 | 4 bit | 12× | 0.53 | ±17 st |
| Illegal Texture | 1.00 | 20× | 0.90 | 2 bit | 14× | 0.70 | ±24 st |
Values are approximate — actual parameter ranges depend on the preset. Chaos also affects less obvious parameters: reverb decay time, filter cutoff frequencies, tape wow depth/rate, feedback amounts, noise levels, loop durations, and stereo width.
A length mode controls how long each generated sample can be and how much silence extends the tail. Longer modes produce bigger files and take more processing time. Each preset has a default mode tuned to its character — you can override it for shorter snippets or maximal drone textures.
| Mode | Max Duration | Tail Extend | Use Case |
|---|---|---|---|
| Short | 15s | None | Quick one-shots, tight loops |
| Medium | 45s | 0.3s | Versatile default for most material |
| Long | 90s | 0.5s | Extended pads, ambient tails |
| Absurd | 120s | 1.0s | Maximal drones, large file sizes |
Note:"Absurd" mode can produce output files over 20 MB each, and ZIP downloads may be substantial. Chaos also slightly extends tails — higher chaos adds up to 0.5s of extra tail.
Every transform is implemented in pure TypeScript using Float32Array buffers. No WebAudio nodes, no WASM, no external DSP libraries. Deterministic, browser-safe, reviewable.
Every preset output flows through a consistent architecture:
source → mutation → tape/tone → delay/reverb → finishing rack → output
1. Mutation — WSOLA stretch, resample, reverse, bitcrush, etc.
2. Tape/Tone — DC block, head bump, tape loss (speed/age HF rolloff),
tone tilt, wow/flutter, soft saturation
3. Delay/Reverb — Dark room, modulated hall, dirty metallic,
reverse bloom, convolution smear, ping-pong delay,
diffusion delay, reverse delay, multi-tap
4. Finishing — Trim silence, DC block, EQ profile, stereo width,
soft clip, peak limiter, normalize, fades, tail extendShared post-processing applied to every output. Order: trim silence → DC block → EQ profile (gentle/warm/bright/ degraded) → stereo width → soft clip → peak limiter → normalize to –1 dBFS → fades (5ms in, 20ms out) → tail extend. The limiter uses tanh-based soft-knee saturation above 85% of ceiling.
Implemented from first principles — no GPL code, no CHOWTapeModel port. 6 profiles: subtle, warm, degraded, destroyed, cinematic_dark, sub_heavy. Each profile includes DC blocker (single-pole IIR, R≈0.997), input highpass/ lowpass, head bump (peaking EQ at 45–120 Hz with configurable Q), tape loss (speed/age-dependent HF rolloff via first-order lowpass), tone tilt (dark/neutral/bright/ sub_heavy), optional wow/flutter (delegates to sinusoidal fractional delay modulation), and optional soft saturation. Chaos pushes parameters toward more degradation: lower speed, older age, deeper wow, more drive.
5 delay types, all with bounded feedback (≤0.95) and full tail rendering. Mono delay with optional LPF/HPF in the feedback path. Stereo ping-pong with cross-channel feedback. Diffusion delay with cascaded allpass smearing (2–6 stages). Reverse delay that reads the buffer backwards for pre-echo effects. Multi-tap delay with per-tap gain and stereo pan. All delays normalize to 0.95 peak and guarantee finite output.
5 reverb engines with damping, stereo spread, and rendered tails. Dark room: 4-comb + 2-allpass FDN with heavy LPF damping. Modulated hall: sinusoidal delay-read modulation for cloud/bloom effects, extended tail. Dirty metallic: 6 shorter combs with configurable brightness for ringy textures. Reverse bloom: input reversed → FDN → reversed back for swelling pre-effects. Convolution smear: O(n·k) with procedurally generated exponential-decay noise IR (LPF-damped). All reverbs guarantee peak ≤1.0 and finite output.
Shard mode: Slices at 4 window sizes (40–200ms), shuffles with seeded LCG PRNG, concatenates with per-grain processing (pitch shift, bitcrush, reverb, saturation). Cloud mode: Overlap-add with Hann/Tukey envelopes, random grain position, pitch (±semitone range), pan per grain, reverse probability, density (grains/sec), jitter. Freeze mode sustains a short window via dense overlapping grains. Delay swarm feeds grains into a feedback delay network. Reverb bloom applies exponential decay envelopes for grain-to-wash transitions. All modes are deterministic for a given seed.
Waveform-Similarity Overlap-Add. 30ms frames with Hann window, hop ratio from stretch factor. Falls back to simple resample at extreme ratios (20×+). Source capped at 60s before stretching.
Direct Form II transposed. LP/HP at Q=0.707 (Butterworth); bandpass Q from bandwidth ratio. Cutoff clamped to [20Hz, Nyquist–1Hz]. Coefficients pre-computed, state per-instance.
Classic 4-comb (31/37/43/53ms) + cascaded allpass (5ms). Feedback gain set by decay. Output normalized to peak 1.0. Used as a lightweight option where more expensive reverbs aren't needed.
O(n·k) direct convolution with exponential-decay noise IR. IR generated procedurally and LPF-damped. Input capped at 5s, IR typically 0.5–4s. Used for transient smear and cinematic wash effects.
Heuristic sliding-window finder with adaptive step size. Scores on RMS energy, peak-to-RMS ratio, front-loaded energy, tail energy, and boundary correlation. Top non-overlapping candidates selected; fallback to middle section if none pass threshold.
The single 0–1 chaos knob maps into 8 per-preset lanes: mutation, degradation, space, modulation, instability, finish, stereo, tail. Each preset defines its own lane weights. Ambient Stretch prioritizes space and tail; Bitrot Dirt prioritizes degradation and instability; Impact/Riser prioritizes space, tail, and stereo. Chaos is applied as chaos × laneWeight for each lane.
Sinusoidal LFO modulating a fractional delay line. Linear interpolation between samples. Separate from the broader tape emulation module — this is the raw pitch modulation primitive.
Two-stage: lowpass at Nyquist/factor → zero-order-hold decimation, then uniform quantization to N bits (1–16). N ≥ 16 passes through.
Per-channel random delay (1–12ms) for precedence-effect stereo widening. Randomized per-call. Combined with warm chain (HP20 + LP60 + soft clip + normalize) for the watchyourtemper® character chain.
No. All processing happens in your browser tab. The app has no backend — it's a static site. Your files never leave your computer.
Yes, after the first page load. The entire DSP engine is client-side JavaScript. No API calls are made at runtime.
Convolution uses direct O(n·k) convolution. The impulse response length scales with reverb time (up to 4s at high chaos = ~192k samples). Input is capped to bound the operation count. On a modern laptop this typically takes 2–5 seconds. Consider this a tradeoff for deterministic, dependency-free convolution.
Outputs use the sample rate of the source audio (decoded by the browser). Most browsers output 48 kHz, but the DSP handles any rate transparently.
Every output passes validation (RMS ≥ 10⁻⁷, length ≥ 20 samples, no NaN/Infinity) via validateOutput() before it's included. If the processed audio is silent or corrupted, it's skipped to avoid broken WAV files. The finishing rack also clamps NaN to 0 and limits peaks, so skipped outputs are rare with normal source material.
A signature processing chain: Haas-effect stereo widening (random 1–12 ms per-channel delay) followed by the finishing rack (DC block, EQ profile, stereo width, soft clip saturation, limiter, peak normalize, fades). Every output passes through the finishing rack. The earlier warm chain (HP20 → LP60 → soft clip) is still available as finalWarm() but most presets now use the full finishing rack.
Yes. See the contributing guide for the recipe API and conventions.
No. Every sample is produced by explicit, deterministic DSP. No neural networks, no machine learning — just biquad filters, overlap-add, convolution, and other classic signal processing.
git clone https://github.com/achuthanmukundan00/Resample-Lab.git cd Resample-Lab/apps/web pnpm install pnpm dev # → http://localhost:3000No backend, no database, no environment variables. The dev server starts in seconds.
pnpm build # static export → out/ pnpm start # serve locallyOutputs a fully self-contained static site. Deploy to Cloudflare Pages, Vercel, Netlify, S3, or any web server.
apps/web/lib/dsp/ # DSP engine
├── transforms.ts # 40+ atomic audio transforms
├── presets.ts # 8 preset recipes + registry
├── finish.ts # Finishing rack (DC block, EQ, limiter, fades)
├── tape.ts # Tape emulation (6 profiles, loss, head bump)
├── delay.ts # Delay effects (mono, ping-pong, diffusion, reverse)
├── reverb.ts # Reverb engines (dark, hall, metallic, bloom, convolution)
├── granular.ts # Granular synthesis (cloud, freeze, swarm, bloom)
├── packWorker.ts # Web Worker entry point
├── wav.ts # 16-bit WAV encoding
├── zip.ts # ZIP builder (stored, no compression)
├── constants.ts # Centralized limits
├── types.ts # Shared types
└── __tests__/ # 92 DSP tests
└── dsp.test.tsAll transforms live in transforms.ts and follow a consistent signature:
// Input: Float32Array[] channels, sample rate, params
// Output: New Float32Array[] (never mutate inputs)
export function myEffect(
channels: Float32Array[],
sr: number,
intensity: number,
): Float32Array[] {
return channels.map((ch) => {
const out = new Float32Array(ch.length);
for (let i = 0; i < ch.length; i++) {
out[i] = ch[i] * intensity; // your processing here
}
return out;
});
}npx tsx apps/web/lib/dsp/__tests__/dsp.test.ts114+ tests covering transforms, finishing rack, tape emulation, delays, reverbs, granular engine, stereo/mono compatibility, and audio analysis utilities.
Generate every preset × every source file × 3 chaos values × 4 length modes and produce a structured report. Useful for evaluating output quality across source material.
npx tsx scripts/render-dsp-corpus.ts --input ./my-wavsOutput goes to .render-audit/ with a structured folder tree, report.json, and a human-readable report.md.
Recommended source material for listen-testing:
Automated browser test that exercises the full UI: upload, preset selection, chaos slider, length mode, and generation. Can also record a screencast for the README.
# Install (one-time) pnpm add -D playwright npx playwright install # Start dev server (new terminal) pnpm dev # Smoke test (no video) node scripts/demo-recorder.mjs # Record demo video node scripts/demo-recorder.mjs --recordRequires a test.wav file at the repo root and the dev server running on port 3000. The recorded video is saved to docs/assets/demo.webm.
AudioContext.decodeAudioData()worker.postMessage() — the UI renders a real-time progress barpresets.tsmakeSample() helper handles stereo conversion, validation, sanitization, and peak normalization