@maruaudio/dsp/reverbs/borrowed-spring is a spring-style dispersive waveguide, a Maru original. Two delay loops, held in caller-owned ("borrowed") rings, each run through a chain of first-order allpasses y = a·x + z; z = x − a·y with a = −0.25 − 0.68 × dispersion, a one-pole damping filter and a 20 Hz DC blocker (@maru/filters-dc-block). An orthogonal two-way coupling, (L ± R)/√2, feeds the loops back with loss 10^(−3 × delayFrames / (rate × decay)); the input enters at 0.25. The chains hold max(1, round(128 × rate / 48000)) allpasses, at most 512.
Parameters
configureBorrowedSpring(state, length, decaySeconds, dispersion, dampingHz) uses clampFiniteWithFallback (@maru/math-range):
| Argument | Range | Fallback and init |
|---|---|---|
length | 0.5 to 2 × the 35 ms and 47 ms base delays | 1 |
decaySeconds | 0.3 to 8 s nominal loop decay | 2 |
dispersion | 0 to 1 | 0.6 |
dampingHz | 500 to 12,000 Hz, at most 0.45 × rate | 6000 |
Lifecycle
initBorrowedSpring(rate) (8 to 192 kHz, fallback 48 kHz) plus two prepared initFractionalFeedbackDelayNode rings, at least the configured delays plus two frames → configureBorrowedSpring → borrowedSpringTick(state, leftRing, rightRing, left, right), reading outLeft and outRight → resetBorrowedSpring with clearing both rings, outside realtime. Live clearing uses clearBorrowedSpringStep (at most 256 stores per call, done at cursor 1024) then finalizeBorrowedSpringClear. Ticks allocate nothing.
When to use it
A spring-reverb slot on guitar or drums in a chain that owns its rings and dry/wet. It is not a fitted helical spring model or a hardware match.
Limits
- Wet only. Undersized rings are refused: both outputs are 0 and the rings are untouched.
- Decay is a nominal loop-loss target; dispersion and damping make the real decay frequency-dependent.
- Length and dispersion changes need a clear; decay and damping do not.
- Input is clamped to ±16 (non-finite → 0).