Declare Latency
An effect that looks ahead — a limiter, a linear-phase filter — outputs each sample some time after
it gets it. Declare that delay with latency:, in samples, and the engine delays the other paths of
the mix by the same amount, so every track stays in time.
Declare it on an effect
Section titled “Declare it on an effect”use "std/instruments" { Sampler, Kit };
dsp effect LookaheadLimiter { latency: 512; param ceiling: 0.8 range(0.1, 1); param release: 0.0005 range(0.00001, 0.01); buffer buf_l(512); buffer buf_r(512); state wp: 0; state gain: 1.0; state hold: 0;
fn process(left, right) -> (out_l, out_r) { // The gain the incoming sample needs, from the louder channel. let peak = __native("max", __native("abs", left), __native("abs", right)); let target = if peak > ceiling { ceiling / peak } else { 1.0 };
// Drop at once, hold until that sample is out, then recover. if target < gain { gain = target; hold = 512.0; } else { if hold > 0.0 { hold = hold - 1.0; } else { gain = gain + (target - gain) * release; } }
// Output the sample from 512 samples ago. let delayed_l = buf_l[wp]; let delayed_r = buf_r[wp]; buf_l[wp] = left; buf_r[wp] = right; wp = (wp + 1.0) % 512.0; return (delayed_l * gain, delayed_r * gain); }}
let bass = AudioTrack("bass");bass.set_instrument(Sampler(Kit("CR-78")));bass << [bd _ bd _];bass.set_effects(#[LookaheadLimiter("limiter")]);
PLAY;The limiter sees each peak 512 samples before it outputs it, so the gain is already down when the peak goes out. The output is 512 samples late, and the block says so.
Declare it on an instrument
Section titled “Declare it on an instrument”The same line goes into a dsp instrument:
dsp instrument LatentSynth { latency: 256; voice state phase: 0.0;
fn render(note, velocity, gate) -> (out_l, out_r) { let freq = __native("mtof", note); phase = __native("fract", phase + freq * INV_SR); let sample = __native("sin", phase * TWOPI) * velocity * gate; return (sample, sample); }}Get the number right
Section titled “Get the number right”Declare the delay the block adds, and only that. The engine already knows the delay of what it
builds for you, and adds your number to it. Without a latency: line the block declares 0.
A delay that changes with a parameter can’t be declared: latency: is a fixed number of samples.
Declare the largest one, and pad the shorter settings to it.
Related
Section titled “Related”- Recording & Latency — how the engine compensates delay across the graph
- The Audio-Thread Contract — why latency is declared, not measured
- DSP Blocks — where
latency:goes