cocoa delay
cocoadelay · effects · schema v1Tape-style stereo delay — clean-room TypeScript port of Tilde Murray's Cocoa Delay (GPL-3.0). A 10-second stereo tape buffer read at a fractional position with 4-point Hermite interpolation; the read time is modulated two ways: an LFO (AMOUNT × sin at FREQUENCY) and a slow random DRIFT walk (AMOUNT × random, SPEED). Feedback is bipolar (−1..+1) with a STEREO offset that skews the L/R read times apart and a PAN with three modes (STATIC rotation, PING-PONG channel-swap on write, CIRCULAR rotating the wet image). DUCKING sidechains the wet level by an envelope follower on the dry input (AMOUNT, ATTACK, RELEASE). A multi-mode FILTER (1/2/4-pole or state-variable, with crossfade between modes) low-cuts + high-cuts inside the feedback path, and an Airwindows-style stateful DRIVE (PurestDrive × Spiral saturation, GAIN / MIX / FILTER, run 1–16 ITERATIONS) saturates the loop. DRY + WET set the output mix. TEMPO SYNC locks the delay time to a musical division (1/4, 1/8, dotted, triplet…) of a clock period measured from pulses on the CLOCK gate input; the CLK SRC dropdown labels whether that clock is the rack SYSTEM clock (TIMELORDE) or external MIDI (MIDICLOCK) — both arrive as the same pulse stream. When sync is Off the TIME knob is free-running milliseconds. CV inputs cover the musical params: time, feedback, mix, drive, LFO amount, drift, pan, ducking. CHARLOTTE'S ECHOS is built from four of these engines chained in series.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
inL | audio | Left audio into the delay — together with inR this is the dry signal that gets written to tape, tapped through the wet path, and summed back into the output. audio signal; L/R stereo pair with inR — L-only auto-duplicates to R |
inR | audio | Right audio into the delay; it is an independent channel, NOT normaled to inL — if you patch only inL the right side stays silent (a mono source feeds both channels only if you patch both inL and inR, e.g. via the module's stereo auto-wire). audio signal; L/R stereo pair with inL |
clock | gate | External clock/gate: when SYNC is on, the delay measures the period between rising edges (level crossing up through ~0.5) of pulses here and locks the delay time to that period times the chosen division — it takes two rising edges to establish a period, so the lock engages on the second pulse. A patched clock ALWAYS wins over both the rack SYSTEM tempo and MIDI clock; when SYNC is Off this input has no audible effect and TIME is free-running. gate / trigger |
time_cv | cv | CV modulation of the TIME knob (delayTime), summed into it with a log-scaled response so a -1..+1 CV sweeps the base delay across its full log range; sweeping it gives classic tape pitch-bend / smear on the echoes. control voltage (CV); modulates delayTime (multiplicative ≈ octaves — ±1 CV spans the param’s log range) |
feedback_cv | cv | CV modulation of FEEDBACK, summed into the knob (linear). Pushes the regeneration amount up or down per-sample; since feedback is bipolar (-1..+1), negative-direction CV can flip the feedback polarity. control voltage (CV); modulates feedback (additive offset — ±1 CV sweeps the full range, centered on the knob) |
mix_cv | cv | CV modulation of the WET output level (targets wetVolume, linear). Use it to fade the echoes in and out under control voltage; the dry level is unaffected. control voltage (CV); modulates wetVolume (additive offset — ±1 CV sweeps the full range, centered on the knob) |
drive_cv | cv | CV modulation of the in-loop saturation amount (targets driveGain, linear). Raises or lowers how hard the feedback path is driven into the stateful saturator per-sample. control voltage (CV); modulates driveGain (additive offset — ±1 CV sweeps the full range, centered on the knob) |
lfo_cv | cv | CV modulation of the LFO AMOUNT (lfoAmount, linear) — i.e. the depth with which the internal time LFO wobbles the delay read position. It does not change the LFO rate, only how much it warps the time. control voltage (CV); modulates lfoAmount (additive offset — ±1 CV sweeps the full range, centered on the knob) |
drift_cv | cv | CV modulation of DRIFT AMOUNT (driftAmount, linear), the depth of the slow random tape-drift walk applied to the read time. More CV = more wow/flutter wander. control voltage (CV); modulates driftAmount (additive offset — ±1 CV sweeps the full range, centered on the knob) |
pan_cv | cv | CV modulation of the PAN angle (pan, linear). Its audible effect depends on PAN MODE — it rotates the static placement, biases the ping-pong, or drives the circular wet-image rotation. control voltage (CV); modulates pan (additive offset — ±1 CV sweeps the full range, centered on the knob) |
duck_cv | cv | CV modulation of DUCK AMOUNT (duckAmount, linear) — how strongly the wet level is pulled down by the envelope follower riding the dry input. More CV = the echoes get out of the way harder when dry signal is present. control voltage (CV); modulates duckAmount (additive offset — ±1 CV sweeps the full range, centered on the knob) |
outputs
| id | cable | what it does |
|---|---|---|
outL | audio | Left of the stereo output: dry × DRY level + ducked wet × WET level, the left half of the combined dry+echo signal. audio signal; L/R stereo pair with outR |
outR | audio | Right of the stereo output: dry × DRY level + ducked wet × WET level, the right half of the combined dry+echo signal. audio signal; L/R stereo pair with outL |
params
| id | label | range | default | curve |
|---|---|---|---|---|
delayTime | Time | 0.001..2s | 0.2 | log |
tempoSync | Sync | 0..19 | 0 | discrete |
clockSource | Clk Src | 0..1 | 0 | discrete |
syncPeriod | SyncPer | 0..30s | 0 | linear |
lfoAmount | LFO Amt | 0..0.5 | 0 | linear |
lfoFrequency | LFO Freq | 0.1..10hz | 2 | log |
driftAmount | Drift Amt | 0..0.05 | 0.001 | linear |
driftSpeed | Drift Spd | 0.1..10 | 1 | log |
feedback | Feedback | -1..1 | 0.5 | linear |
stereoOffset | Stereo | -0.5..0.5 | 0 | linear |
pan | Pan | ?..? | 0 | linear |
panMode | Pan Mode | 0..2 | 0 | discrete |
duckAmount | Duck Amt | 0..10 | 0 | linear |
duckAttack | Attack | 0.1..100 | 10 | log |
duckRelease | Release | 0.1..100 | 10 | log |
filterMode | Filt Mode | 0..3 | 0 | discrete |
lowCut | Low Cut | 0.01..1 | 0.75 | linear |
highCut | High Cut | 0.001..0.99 | 0.001 | linear |
driveGain | Gain | 0..10 | 0.1 | linear |
driveMix | D.Mix | 0..1 | 1 | linear |
driveCutoff | D.Filt | 0.01..1 | 1 | linear |
driveIterations | Iters | 1..16 | 1 | discrete |
dryVolume | Dry | 0..2 | 1 | linear |
wetVolume | Wet | 0..2 | 0.5 | linear |
controls
| control | what it does |
|---|---|
| Clk Src | CLK SRC — picks which tempo reference SYNC follows when no clock cable is patched: SYSTEM reads the rack's TIMELORDE BPM, MIDI follows incoming MIDI clock (0xF8). Selecting MIDI is what first requests browser MIDI access; SYSTEM never prompts. A patched CLK input overrides either. |
| Time | TIME — the base delay length in seconds (0.001–2.0 s, log). Used directly when SYNC is Off; when SYNC is on it is only the fallback if no clock/tempo is available. LFO, DRIFT and STEREO offset all warp this value before the tape is read. |
| Drift Amt | DRIFT AMOUNT — depth of a slow random walk on the delay time (0–0.05), the tape wow/flutter character. Higher = more wandering, less stable pitch on the echoes. |
| Drift Spd | DRIFT SPEED — how quickly the random drift walk moves (0.1–10, log). Faster speeds give jittery flutter, slower give long lazy pitch drift. |
| D.Filt | DRIVE FILTER — post-saturator low-pass cutoff (0.01–1.0, normalized; default 1.0 = open) that tames the harshness the drive adds. |
| Gain | DRIVE GAIN — how hard the feedback path is pushed into the stateful saturator (0–10). 0 bypasses drive entirely; higher adds progressively dirtier saturation that builds up over repeats. |
| Iters | DRIVE ITERATIONS — how many times the saturate-then-filter stage is run in series per sample (1–16). More iterations stack more saturation and filtering for a thicker, more compressed drive. |
| D.Mix | DRIVE MIX — wet/dry blend across the saturator (0–1), how much of the saturated signal replaces the clean one inside the loop. |
| Dry | DRY — level of the unprocessed input passed straight to the output (0–2.0, default 1.0). Set to 0 for a fully wet send/return. |
| Duck Amt | DUCK AMOUNT — how strongly the wet level is ducked by an envelope follower on the dry input sum (0–10). At 0 there is no ducking; higher values make the echoes recede whenever dry signal is playing. |
| Attack | DUCK ATTACK — how fast the ducking envelope clamps the wet down when dry signal arrives (0.1–100, log). |
| Release | DUCK RELEASE — how fast the wet level recovers after the dry signal falls away (0.1–100, log). |
| Feedback | FEEDBACK — bipolar regeneration amount (-1..+1, default 0.5). Higher magnitude = more/longer repeats; negative values invert the polarity of each fed-back repeat for a hollower tone. |
| Filt Mode | FILTER MODE — the topology of the in-feedback-loop tone filter: 1-pole, 2-pole, 4-pole, or State-variable. Steeper poles color the repeats more; changing mode crossfades smoothly. |
| High Cut | HIGH CUT — the in-loop high-pass cutoff applied to each repeat (0.001–0.99, normalized; default 0.001 ≈ off). Raising it thins out the lows of successive echoes. (Label/role: this is the HP stage in the loop.) |
| LFO Amt | LFO AMOUNT — depth of the internal sine LFO that warps the delay read time (0–0.5). At 0 the LFO does nothing; higher values give pitch wobble / chorus-like movement on the echoes. |
| LFO Freq | LFO FREQUENCY — rate of the time-warp LFO (0.1–10 Hz, log). Sets how fast the delay-time wobble cycles. |
| Low Cut | LOW CUT — the in-loop low-pass cutoff applied to each repeat (0.01–1.0, normalized; default 0.75). Lower values darken successive echoes as they regenerate. (Despite the 'low cut' label it is the LP stage in the loop.) |
| Pan | PAN — wet-image rotation angle (-π/2..+π/2). What it does depends on PAN MODE: static placement, ping-pong bias, or the amount of circular rotation applied to the wet signal. |
| Pan Mode | PAN MODE — Static (a fixed rotation by PAN), Ping-Pong (swaps L/R as it writes to tape so repeats bounce side to side), or Circular (continuously rotates the wet stereo image). Switching modes crossfades to avoid clicks. |
| Stereo | STEREO — skews the left and right read times apart (-0.5..+0.5) by exponentiating the delay time oppositely per channel, widening the stereo image of the echoes. 0 keeps both channels at the same delay. |
| SyncPer | Internal, not on the card: the seconds-per-beat the main thread bridges in for the selected CLK SRC (SYSTEM/MIDI), since the audio worklet can't read those sources directly. 0 means none available, in which case it falls back to the free-running TIME. |
| Sync | SYNC — Off (index 0) means TIME is free-running; any other setting locks the delay to a musical division of one beat (1, dotted/triplet variants… down to 1/64T). The beat comes from a patched clock pulse, else the chosen CLK SRC tempo. |
| Wet | WET — level of the delayed/echo signal in the output (0–2.0, default 0.5), the amount ducking pulls down and what mix_cv modulates. |
source
cocoadelay.ts on GitHub.