feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
// Arpeggiator — plays chord progressions through the C15 engine
|
2026-03-24 00:42:37 +01:00
|
|
|
// Delegates to a dedicated Web Worker for reliable timing.
|
|
|
|
|
// The worker writes noteOn/noteOff directly to the SharedArrayBuffer
|
|
|
|
|
// ring buffer, bypassing main thread entirely.
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
|
|
|
|
export class Arpeggiator {
|
|
|
|
|
constructor(bridge) {
|
|
|
|
|
this.bridge = bridge;
|
2026-03-24 00:42:37 +01:00
|
|
|
this._worker = null;
|
|
|
|
|
this._playing = false;
|
|
|
|
|
this._bpm = 120;
|
|
|
|
|
this._octaves = 2;
|
|
|
|
|
this._octaveOffset = 0;
|
2026-03-30 16:05:45 +02:00
|
|
|
this._progression = 'Cmin7-rand';
|
|
|
|
|
this._direction = 'updown';
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get progressionNames() {
|
2026-03-30 16:05:45 +02:00
|
|
|
return ['Cmin7-rand', 'I-vi-IV-V', 'I-IV-vi-V', 'i-VI-III-VII', 'I-V-vi-IV'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get directionNames() {
|
|
|
|
|
return ['up', 'updown'];
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
get playing() { return this._playing; }
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
get bpm() { return this._bpm; }
|
|
|
|
|
set bpm(v) {
|
|
|
|
|
this._bpm = v;
|
|
|
|
|
this._send('set', { bpm: v });
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
get octaves() { return this._octaves; }
|
|
|
|
|
set octaves(v) {
|
|
|
|
|
this._octaves = v;
|
|
|
|
|
this._send('set', { octaves: v });
|
|
|
|
|
}
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
get octaveOffset() { return this._octaveOffset; }
|
|
|
|
|
set octaveOffset(v) {
|
|
|
|
|
this._octaveOffset = v;
|
|
|
|
|
this._send('set', { octaveOffset: v });
|
|
|
|
|
}
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
get progression() { return this._progression; }
|
|
|
|
|
set progression(v) {
|
|
|
|
|
this._progression = v;
|
|
|
|
|
this._send('set', { progression: v });
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-30 16:05:45 +02:00
|
|
|
get direction() { return this._direction; }
|
|
|
|
|
set direction(v) {
|
|
|
|
|
this._direction = v;
|
|
|
|
|
this._send('set', { direction: v });
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
_ensureWorker() {
|
|
|
|
|
if (this._worker) return;
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
this._worker = new Worker(
|
|
|
|
|
new URL('./arpeggiator-worker.js', import.meta.url),
|
|
|
|
|
{ type: 'module' }
|
|
|
|
|
);
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
this._worker.onmessage = (e) => {
|
|
|
|
|
if (e.data.type === 'state') {
|
|
|
|
|
this._playing = e.data.playing;
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
2026-03-24 00:42:37 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Pass the SharedArrayBuffer so the worker can write notes directly
|
|
|
|
|
const sab = this.bridge.sharedBuffer;
|
|
|
|
|
if (sab) {
|
|
|
|
|
this._worker.postMessage({ type: 'init', data: { sharedBuffer: sab } });
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
// Sync current settings
|
|
|
|
|
this._send('set', {
|
|
|
|
|
bpm: this._bpm,
|
|
|
|
|
octaves: this._octaves,
|
|
|
|
|
octaveOffset: this._octaveOffset,
|
|
|
|
|
progression: this._progression,
|
2026-03-30 16:05:45 +02:00
|
|
|
direction: this._direction,
|
2026-03-24 00:42:37 +01:00
|
|
|
});
|
|
|
|
|
}
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
_send(type, data) {
|
|
|
|
|
if (this._worker) {
|
|
|
|
|
this._worker.postMessage({ type, data });
|
|
|
|
|
}
|
|
|
|
|
}
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
|
2026-03-24 00:42:37 +01:00
|
|
|
start() {
|
|
|
|
|
this._ensureWorker();
|
|
|
|
|
// If bridge wasn't ready when worker was created, send the buffer now
|
|
|
|
|
const sab = this.bridge.sharedBuffer;
|
|
|
|
|
if (sab) {
|
|
|
|
|
this._worker.postMessage({ type: 'init', data: { sharedBuffer: sab } });
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
2026-03-24 00:42:37 +01:00
|
|
|
this._send('start');
|
|
|
|
|
this._playing = true; // optimistic, worker confirms
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stop() {
|
|
|
|
|
this._send('stop');
|
|
|
|
|
this._playing = false;
|
feat(playground): add C15 synth mode with NISPS-controlled parameters and arpeggiator
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).
2026-03-21 21:26:37 +01:00
|
|
|
}
|
|
|
|
|
}
|