From eec3752b5a9b2ba0318029fbe4c51e03e9bf4dc7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 23:57:09 +0200 Subject: [PATCH 1/7] cleanup --- packages/superdough/dspworklet.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs index 1c109452..deff485a 100644 --- a/packages/superdough/dspworklet.mjs +++ b/packages/superdough/dspworklet.mjs @@ -14,7 +14,6 @@ class MyProcessor extends AudioWorkletProcessor { if(e.data==='stop') { this.stopped = true; } else if(e.data?.dough) { - const deadline = e.data.time-currentTime; __q.push(e.data) } else { msg?.(e.data) From 62743edf4540356e7e7aae474ff4adbf4a3bfe53 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 25 Sep 2023 23:57:19 +0200 Subject: [PATCH 2/7] bump superdough to 0.9.9 --- packages/superdough/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/package.json b/packages/superdough/package.json index 69ba6f8c..387749c8 100644 --- a/packages/superdough/package.json +++ b/packages/superdough/package.json @@ -1,6 +1,6 @@ { "name": "superdough", - "version": "0.9.8", + "version": "0.9.9", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "main": "index.mjs", "type": "module", From cf72e3bba5f22a6109c381af47634ebb34c2141a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 21:25:30 +0200 Subject: [PATCH 3/7] fix: add conditional imports to eval scope + fire postMessage on start --- website/src/repl/Repl.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index fe32e741..4002eba8 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -33,7 +33,7 @@ const supabase = createClient( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); -const modules = [ +let modules = [ import('@strudel.cycles/core'), import('@strudel.cycles/tonal'), import('@strudel.cycles/mini'), @@ -45,13 +45,13 @@ const modules = [ import('@strudel.cycles/csound'), ]; if (isTauri()) { - modules.concat([ + modules = modules.concat([ import('@strudel/desktopbridge/loggerbridge.mjs'), import('@strudel/desktopbridge/midibridge.mjs'), import('@strudel/desktopbridge/oscbridge.mjs'), ]); } else { - modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); + modules = modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]); } const modulesLoading = evalScope( @@ -153,6 +153,8 @@ export function Repl({ embedded = false }) { if (!play) { cleanupDraw(false); window.postMessage('strudel-stop'); + } else { + window.postMessage('strudel-start'); } }, drawContext, From 68ab43b3ab2c79691e55e3cf2ca288573bc00e72 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 21:26:24 +0200 Subject: [PATCH 4/7] support midi clock via "clock" control (not on desktop yet) --- packages/core/controls.mjs | 1 + packages/midi/midi.mjs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6cac6e54..62cfdd46 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1066,6 +1066,7 @@ const generic_params = [ */ ['waveloss'], // TODO: midi effects? + ['clock'], ['dur'], // ['modwheel'], ['expression'], diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 98509b46..32583d75 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -90,6 +90,13 @@ Pattern.prototype.midi = function (output) { enableWebMidi({ onEnabled: ({ outputs }) => { const device = getDevice(output, outputs); + if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (e.data === 'strudel-stop') { + device.sendStop(); + } + }); + } const otherOutputs = outputs.filter((o) => o.name !== device.name); logger( `Midi enabled! Using "${device.name}". ${ @@ -103,6 +110,7 @@ Pattern.prototype.midi = function (output) { return this.onTrigger((time, hap, currentTime, cps) => { if (!WebMidi.enabled) { + console.log('not enabled'); return; } const device = getDevice(output, WebMidi.outputs); @@ -113,7 +121,7 @@ Pattern.prototype.midi = function (output) { const timeOffsetString = `+${offset}`; // destructure value - const { note, nrpnn, nrpv, ccn, ccv, midichan = 1 } = hap.value; + const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, clock } = hap.value; const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity // note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length @@ -125,7 +133,7 @@ Pattern.prototype.midi = function (output) { time: timeOffsetString, }); } - if (ccv && ccn) { + if (ccv !== undefined && ccn !== undefined) { if (typeof ccv !== 'number' || ccv < 0 || ccv > 1) { throw new Error('expected ccv to be a number between 0 and 1'); } @@ -135,5 +143,12 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } + const begin = hap.whole.begin + 0; + if (begin === 0) { + device.sendStart({ time: timeOffsetString }); + } + if (clock) { + device.sendClock({ time: timeOffsetString }); + } }); }; From dea1c31701a9ad8b0bbb081c85401b088f480f88 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:10:21 +0200 Subject: [PATCH 5/7] use midicmd instead of clock --- packages/core/controls.mjs | 2 +- packages/midi/midi.mjs | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 62cfdd46..d1a9ce7f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1066,7 +1066,7 @@ const generic_params = [ */ ['waveloss'], // TODO: midi effects? - ['clock'], + ['midicmd'], ['dur'], // ['modwheel'], ['expression'], diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index 32583d75..ee111d7e 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -90,13 +90,6 @@ Pattern.prototype.midi = function (output) { enableWebMidi({ onEnabled: ({ outputs }) => { const device = getDevice(output, outputs); - if (typeof window !== 'undefined') { - window.addEventListener('message', (e) => { - if (e.data === 'strudel-stop') { - device.sendStop(); - } - }); - } const otherOutputs = outputs.filter((o) => o.name !== device.name); logger( `Midi enabled! Using "${device.name}". ${ @@ -121,7 +114,7 @@ Pattern.prototype.midi = function (output) { const timeOffsetString = `+${offset}`; // destructure value - const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, clock } = hap.value; + const { note, nrpnn, nrpv, ccn, ccv, midichan = 1, midicmd } = hap.value; const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity // note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length @@ -143,12 +136,14 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } - const begin = hap.whole.begin + 0; - if (begin === 0) { - device.sendStart({ time: timeOffsetString }); - } - if (clock) { + if (['clock', 'midiClock'].includes(midicmd)) { device.sendClock({ time: timeOffsetString }); + } else if (['start'].includes(midicmd)) { + device.sendStart({ time: timeOffsetString }); + } else if (['stop'].includes(midicmd)) { + device.sendStop({ time: timeOffsetString }); + } else if (['continue'].includes(midicmd)) { + device.sendContinue({ time: timeOffsetString }); } }); }; From f11462bf41ee9898cac562970e6252035cdd77a4 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:28:52 +0200 Subject: [PATCH 6/7] sync start / stop automatically too --- packages/midi/midi.mjs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index ee111d7e..e3ce0b3e 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -78,6 +78,20 @@ function getDevice(output, outputs) { return IACOutput ?? outputs[0]; } +// send start/stop messages to outputs when repl starts/stops +if (typeof window !== 'undefined') { + window.addEventListener('message', (e) => { + if (!WebMidi?.enabled) { + return; + } + if (e.data === 'strudel-stop') { + WebMidi.outputs.forEach((output) => output.sendStop()); + } else if (e.data === 'strudel-start') { + WebMidi.outputs.forEach((output) => output.sendStart()); + } + }); +} + Pattern.prototype.midi = function (output) { if (isPattern(output)) { throw new Error( From 4eb0a7b7c0606acd5469b93f5275481dff86132a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 27 Sep 2023 22:42:35 +0200 Subject: [PATCH 7/7] send start with accurate timing --- packages/midi/midi.mjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index e3ce0b3e..07e6e65c 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -86,9 +86,8 @@ if (typeof window !== 'undefined') { } if (e.data === 'strudel-stop') { WebMidi.outputs.forEach((output) => output.sendStop()); - } else if (e.data === 'strudel-start') { - WebMidi.outputs.forEach((output) => output.sendStart()); } + // cannot start here, since we have no timing info, see sendStart below }); } @@ -150,6 +149,10 @@ Pattern.prototype.midi = function (output) { const scaled = Math.round(ccv * 127); device.sendControlChange(ccn, scaled, midichan, { time: timeOffsetString }); } + if (hap.whole.begin + 0 === 0) { + // we need to start here because we have the timing info + device.sendStart({ time: timeOffsetString }); + } if (['clock', 'midiClock'].includes(midicmd)) { device.sendClock({ time: timeOffsetString }); } else if (['start'].includes(midicmd)) {