2026-04-03 18:30:28 +02:00
|
|
|
// Arpeggiator — plays chord progressions through any SynthEngine.
|
2026-03-24 00:42:37 +01:00
|
|
|
// Delegates to a dedicated Web Worker for reliable timing.
|
2026-04-03 18:30:28 +02:00
|
|
|
// The worker posts noteOn/noteOff messages back to the main thread, which
|
|
|
|
|
// forwards them through the active SynthEngine. This keeps the arpeggiator
|
|
|
|
|
// decoupled from C15's SharedArrayBuffer ring buffer so any engine works.
|
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 {
|
2026-04-03 18:30:28 +02:00
|
|
|
/**
|
|
|
|
|
* @param {import('./engine-interface.js').SynthEngine} engine
|
|
|
|
|
*/
|
|
|
|
|
constructor(engine) {
|
|
|
|
|
this.engine = engine;
|
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) => {
|
2026-04-03 18:30:28 +02:00
|
|
|
const { type, data } = e.data;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'state':
|
|
|
|
|
this._playing = data.playing;
|
|
|
|
|
break;
|
|
|
|
|
case 'noteOn':
|
|
|
|
|
this.engine.noteOn(data.note, data.velocity);
|
|
|
|
|
break;
|
|
|
|
|
case 'noteOff':
|
|
|
|
|
this.engine.noteOff(data.note);
|
|
|
|
|
break;
|
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
|
|
|
};
|
|
|
|
|
|
2026-04-03 18:30:28 +02:00
|
|
|
// Sync current settings to worker
|
2026-03-24 00:42:37 +01:00
|
|
|
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();
|
|
|
|
|
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
|
|
|
}
|
2026-04-03 18:30:28 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hot-swap the engine without restarting the worker.
|
|
|
|
|
* Called by setActiveEngine() in a-app.js.
|
|
|
|
|
* @param {import('./engine-interface.js').SynthEngine} engine
|
|
|
|
|
*/
|
|
|
|
|
setEngine(engine) {
|
|
|
|
|
this.engine = engine;
|
|
|
|
|
}
|
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
|
|
|
}
|