@maruaudio/dsp/delays/cross-feed is a stereo delay of two fractional lines, each with its own time, whose feedback splits into a same-side and a cross-side gain. Each line writes seed + same·ownOut + cross·otherOut through an in-loop RBJ high-pass and low-pass (@maru/filters-biquad) and the saturator x / (1 + |x|) (unity slope at zero, |y| < 1). Reads interpolate linearly and swing with a quadrature sine pair. A time change crossfades the old read into the new one over 48 ms at equal power (sin/cos), without a pitch glide.
const state = initCrossFeedDelayNode(48000, 2) // capacity in seconds
setCrossFeedDelayLeftSeconds(state, 0.375)
setCrossFeedCross(state, 0.4)
crossFeedDelayNodeTick(state, left, right)
const wetL = crossFeedDelayLeft(state), wetR = crossFeedDelayRight(state)Parameters
| Setter | Range the setter enforces | Default | Unit |
|---|---|---|---|
setCrossFeedDelayLeftSeconds / …RightSeconds | 0 to 30 s, then 1 sample to the capacity | 0.25 / 0.5 | s |
setCrossFeedSame / setCrossFeedCross | 0 to 0.98 each | 0 / 0 | linear |
setCrossFeedLowCut / setCrossFeedHighCut | Biquad clamp, 10 Hz to 0.45 × rate | 220 / 6000 | Hz |
setCrossFeedTone48 | 12 or 48 dB/oct loop filters; call before rendering | 12 dB/oct | flag |
setCrossFeedModRate / …ModDepthSeconds | 0 to 40 Hz / 0 to 0.05 s peak swing | 0 / 0 | Hz, s |
Lifecycle
initCrossFeedDelayNode(sampleRate, maxSeconds) allocates both lines once (capacity 0.01 to 30 s plus 50 ms headroom; a bad rate gives 48 kHz) → setters → crossFeedDelayNodeTick(state, seedL, seedR) → read the two outputs. resetCrossFeedDelayNode clears all synchronously, outside realtime; in realtime, clearCrossFeedDelayNodeStep zeroes at most 256 samples per call up to crossFeedDelayClearStoreCount, then finalize…Clear resets fades, phase and filters. Controls and capacity are kept.
When to use it
Tempo-synced stereo echoes that bounce or stay on their side, filtered each pass, re-landing on the grid when the tempo or division changes.
Limits
- Stereo, wet only. Same and cross clamp separately, so their sum can reach 1.96; the saturator bounds the loop. A retune mid-fade adopts the current target.