ringback

ringback · effects

Stereo crush effect — the TWOTRACKS record-time artifact, extracted and made intentional. While TWOTRACKS fresh-records it writes the live input into INTEGER ring-buffer cells (sample-quantized) at a fractional, varispeed write/read cursor, then reads those same cells back with LINEAR INTERPOLATION at the fractional cursor; the integer-cell write versus the interpolated read makes the read-back a decimated, aliased copy of the input — a metallic "bitcrushed" tone. (That read-back used to leak into TWOTRACKS' monitor while recording, which was a bug; RINGBACK packages the EXACT same mechanism as a deliberate effect.) Stereo in (L IN / R IN) → stereo out (L OUT / R OUT); a mono input is mirrored to both channels. Two independent ring channels (L + R) run the per-sample loop: read = interp(buf, cursor); write buf cells [cursor, cursor+RATE) = input + FEEDBACK·read; cursor += RATE (wrapping the small ring); out = (1−MIX)·input + MIX·read. Four knobs expose the character, all derived directly from the mechanism: RATE (0.05..4, default 0.5) is the write/read cursor advance per sample and the "amount" of the artifact — 1 is the mildest, below 1 the read-back stair-steps and aliases hardest; SIZE (2..4096 samples, default 64, log) is the ring length — a few samples ring like a comb/short metallic resonance, larger sizes become a grainy short-delay smear; FEEDBACK (0..0.98, default 0.3) re-injects the read-back into the ring (the regen "ring" tail), clamped strictly below 1 so it can never self-amplify to infinity; MIX (0..1, default 1) is the dry/wet blend between the clean input and the crushed read-back (0 passes the input through unchanged). The DSP is pure and deterministic (no RNG, no time dependence) so it is stable for VRT/ART; the worklet runs the shared RingChannel core in ringback-core.ts (unit-tested), the same no-mirror discipline as the TWOTRACKS engine. Patch any stereo (or mono) source through it for lo-fi grit, comb-ring resonance, or — at high feedback and small size — a self-oscillating metallic drone.

A stereo crush effect built from the exact glitch that used to make TWOTRACKS' monitor sound bitcrushed while recording, turned into a deliberate instrument. Each channel writes the input into a short ring buffer at an integer-cell varispeed (set by RATE) and reads it back with fractional interpolation at the same moving cursor, with FEEDBACK re-injecting the read-back into the ring. The mismatch between the stair-stepped write and the smooth read produces a crushed, comb-filtered, grainy texture whose character ranges from subtle aliasing to harsh digital smear. RATE sets the crush hardness, SIZE the ring length, FEEDBACK the regenerating tail, and MIX the dry/wet — but RATE and SIZE are really one control in two halves, because the ring laps every SIZE / RATE input samples and it is that RATIO, not either knob alone, that sets the comb pitch you hear. It ships FULLY WET (MIX 1), so it is at its most extreme the instant you patch it in. All four params are a-rate AND read once per sample, and the CV path has no smoothing in it, so these are true audio-rate jacks: an oscillator into RATE frequency-modulates the crush rather than automating it.

the faceplate

ringbackin_laudioin_raudioratecvsizecvfeedbackcvmixcvout_laudioout_raudioaudiocvgatepitch
6 inputs · 2 outputs · 4 params

inputs

idcablewhat it does
in_laudioLeft-channel audio into the crush ring buffer. (A mono source is mirrored to both channels.)
audio signal
in_raudioRight-channel audio into the crush ring buffer.
audio signal
ratecvCV that displaces the RATE knob (linear), modulating the varispeed write rate — sweep it for shifting crush intensity and pitched-comb artifacts. Genuinely AUDIO-RATE: the worklet declares this param a-rate and reads it once per SAMPLE, and the CV reaches it through an unsmoothed shaper, so an oscillator patched here frequency-modulates the crush itself rather than nudging it at envelope rate.
control voltage (CV); modulates rate (additive offset — ±1 CV sweeps the full range, centered on the knob)
sizecvCV that displaces the SIZE knob (log-scaled), modulating the ring length live (comb-filter pitch ↔ grain size). Audio-rate like the other three, and the most violent of them: the ring length is re-clamped every sample, so a fast modulation re-points the read head mid-lap and shreds the tail.
control voltage (CV); modulates size (multiplicative ≈ octaves — ±1 CV spans the param’s log range)
feedbackcvCV that displaces the FEEDBACK knob, modulating how much read-back re-injects (the regenerating tail amount). Audio-rate, so it doubles as a ring modulator on the regeneration path.
control voltage (CV); modulates feedback (additive offset — ±1 CV sweeps the full range, centered on the knob)
mixcvCV that displaces the MIX knob, modulating the dry/wet crush balance. Audio-rate: at audio frequencies this crossfade between the clean and crushed copies becomes its own timbre rather than an automation.
control voltage (CV); modulates mix (additive offset — ±1 CV sweeps the full range, centered on the knob)

outputs

idcablewhat it does
out_laudioLeft channel of the crushed stereo output (dry blended with the crushed ring read-back per MIX).
audio signal
out_raudioRight channel of the crushed stereo output.
audio signal

params

idlabelrangedefaultcurve
rateRate?..?linear
sizeSize?..?smplog
feedbackFeedback?..?linear
mixMix?..?linear

controls

controlwhat it does
FeedbackHow much of the read-back is re-injected into the ring (0..0.98). Each LAP of the cursor around the ring multiplies the stored signal by this amount, so the tail is a geometric decay and the knob reads it in laps: 1 PASS at 0 (the crushed copy is heard once and overwritten), 6 LAPS at the 0.3 default, 66 LAPS at 0.9, and RINGING once the tail outlasts 100 laps (about 0.933 up) — the regime where the ring stops decaying audibly and settles into the metallic drone. It is hard-clamped strictly below 1, so it can never self-amplify without bound.
MixDry / wet balance (0..1): 0 is the clean input, 1 is full crush, between blends the two. It defaults to 1 — a freshly spawned RINGBACK is FULLY WET, which is unusual for an insert effect and is why the knob names its ends (DRY / 99% WET / WET) rather than printing a bare fraction. Turning it down is the only control that makes the module quieter rather than different.
RateThe ring cursor's advance in CELLS PER INPUT SAMPLE (0.05..4) — the mismatch that IS this module. Below 1 the cursor moves less than a cell per sample, so 1/RATE consecutive input samples land in the same integer cell and only the last one survives: the wet path is decimated to RATE × the sample rate with no anti-alias filter anywhere, which is why the knob reads SR/2.0 at its default and SR/20 at the bottom. At and above 1 nothing is discarded and the knob reads FULL SR — but that is a claim about decimation, not about cleanliness. Measured on the real per-sample core over a C4 saw, the output is at its SMOOTHEST at the INTEGER rates (normalised roughness 0.29 / 0.26 / 0.24 / 0.22 at 1 / 2 / 3 / 4, against the dry saw's own 0.26) and rough again in between (0.81 at 1.25, 0.73 at 1.5), because a fractional cursor smears the write across a fractional cell span and reads back interpolated. So the harsh region is roughly 0.1–0.9 plus every non-integer setting above 1, and the four integer settings (1, 2, 3, 4) are the closest this module gets to a clean short comb. They are not detented — the knob will not snap to them and there is no tick to aim at; you have to read the number.
SizeRing buffer length in samples, log-scaled 2..4096. Tiny sizes give a high-pitched comb-filter tone; larger sizes spread into a grainy, smeared echo-like texture. Two things worth knowing: the DSP ROUNDS this to a whole number of cells (a knob at 63.7 runs as 64), and the pitch you actually hear is not SIZE alone — the ring laps every SIZE / RATE input samples, so the comb frequency is set by the RATIO of the two knobs and halving RATE drops the ring an octave without touching SIZE. That is also why this control carries no persistent readout: the number that matters is a product of two params, and a per-knob readout cannot show it.

source

ringback.ts on GitHub.

Generated from packages/web/src/lib/{audio,video}/module-registry.ts · repo