ringback
ringback · effectsStereo 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.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
in_l | audio | Left-channel audio into the crush ring buffer. (A mono source is mirrored to both channels.) audio signal |
in_r | audio | Right-channel audio into the crush ring buffer. audio signal |
rate | cv | CV 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) |
size | cv | CV 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) |
feedback | cv | CV 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) |
mix | cv | CV 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
| id | cable | what it does |
|---|---|---|
out_l | audio | Left channel of the crushed stereo output (dry blended with the crushed ring read-back per MIX). audio signal |
out_r | audio | Right channel of the crushed stereo output. audio signal |
params
| id | label | range | default | curve |
|---|---|---|---|---|
rate | Rate | ?..? | — | linear |
size | Size | ?..?smp | — | log |
feedback | Feedback | ?..? | — | linear |
mix | Mix | ?..? | — | linear |
controls
| control | what it does |
|---|---|
| Feedback | How 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. |
| Mix | Dry / 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. |
| Rate | The 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. |
| Size | Ring 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.