Hand tracking at 30fps was writing 126 params per frame to the C15 ring
buffer (capacity 512), flooding it and starving arpeggiator noteOn/noteOff
messages — causing stuck/dropped notes.
Three-part fix:
- Arpeggiator now runs in a dedicated Web Worker with direct
SharedArrayBuffer access, bypassing the main thread entirely for
note timing. Worker setInterval isn't subject to main thread jank.
- RingBufferWriter uses CAS (Atomics.compareExchange) for multi-producer
safety — both main thread (params) and worker (notes) write safely.
- routeOutputs throttles synth parameter sends: dead-zone filter
(0.2% change threshold) + rate cap (~20fps), reducing ring buffer
pressure from ~3800 msg/s to ~50-100 msg/s of actual changes.
- Insert DynamicsCompressorNode as always-on brick-wall limiter after
master gain (threshold -6dB, ratio 20:1, 2ms attack)
- Add devmode tame parameter (0-1) controlling range constraining:
- ?tame=0.7 URL param (default) or window.setTameLevel(n)
- 0 = no mitigation, 1 = strongest constraining
- Constrain 20 volume/buildup-sensitive params with safeMin/safeMax:
- Envelope release/decay2 times capped to prevent infinite ringing
- Envelope gains kept in moderate range
- All 5 drive stages (ShpA/B, FB, Out, Cabinet) capped
- Output mixer levels given floor and ceiling
- Echo feedback and reverb size limited to prevent wash buildup
- Fix Comb Filter group count (8, not 9) in comments and color generator
Adds a secondary Synth mode (toggled via collapsible left side panel)
where the NISPS ML engine's 20 outputs control curated C15 synthesizer
parameters (oscillator PM, shapers, filters, reverb, echo, flanger,
output mixer) through a WASM AudioWorklet bridge.
Includes a chord progression arpeggiator with controls for tempo (BPM),
octave range, octave offset, and 4 selectable progressions. The C15
engine runs in an AudioWorklet with lock-free SharedArrayBuffer ring
buffer communication.
New files: c15/ (WASM assets), js/synth/ (bridge, arpeggiator, param map),
serve-coop.py (COOP/COEP headers for SharedArrayBuffer support).