From 7af6188a8a6d7f713ec8c43d0ea5ecd7bba10cf0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 17 Aug 2022 21:26:00 +0200 Subject: [PATCH] move scheduler to core + move audioctx to userland --- packages/{webaudio => core}/clockworker.mjs | 2 +- .../{webaudio => core}/examples/repl.html | 64 ++++++++++++------- packages/core/index.mjs | 2 + packages/{webaudio => core}/scheduler.mjs | 28 ++++---- packages/webaudio/index.mjs | 2 - 5 files changed, 55 insertions(+), 43 deletions(-) rename packages/{webaudio => core}/clockworker.mjs (97%) rename packages/{webaudio => core}/examples/repl.html (51%) rename packages/{webaudio => core}/scheduler.mjs (65%) diff --git a/packages/webaudio/clockworker.mjs b/packages/core/clockworker.mjs similarity index 97% rename from packages/webaudio/clockworker.mjs rename to packages/core/clockworker.mjs index e1ec9005..07bd45d3 100644 --- a/packages/webaudio/clockworker.mjs +++ b/packages/core/clockworker.mjs @@ -1,6 +1,6 @@ /* clockworker.mjs - -Copyright (C) 2022 Strudel contributors - see +Copyright (C) 2022 Strudel contributors - see This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ diff --git a/packages/webaudio/examples/repl.html b/packages/core/examples/repl.html similarity index 51% rename from packages/webaudio/examples/repl.html rename to packages/core/examples/repl.html index b34d956f..037a64c4 100644 --- a/packages/webaudio/examples/repl.html +++ b/packages/core/examples/repl.html @@ -1,8 +1,8 @@ -
-
-
- - +
+ + + +
evaluate()); - - document.getElementById('start').addEventListener('click', () => scheduler.start()); + document.getElementById('start').addEventListener('click', () => { + ctx.resume(); + scheduler.start(); + }); document.getElementById('stop').addEventListener('click', () => scheduler.stop()); document.getElementById('slower').addEventListener('click', () => scheduler.setCps(scheduler.cps - 0.1)); document.getElementById('faster').addEventListener('click', () => scheduler.setCps(scheduler.cps + 0.1)); diff --git a/packages/core/index.mjs b/packages/core/index.mjs index 83c82abe..293aa614 100644 --- a/packages/core/index.mjs +++ b/packages/core/index.mjs @@ -15,6 +15,8 @@ export * from './state.mjs'; export * from './timespan.mjs'; export * from './util.mjs'; export * from './speak.mjs'; +export * from './clockworker.mjs'; +export * from './scheduler.mjs'; export { default as gist } from './gist.js'; // below won't work with runtime.mjs (json import fails) /* import * as p from './package.json'; diff --git a/packages/webaudio/scheduler.mjs b/packages/core/scheduler.mjs similarity index 65% rename from packages/webaudio/scheduler.mjs rename to packages/core/scheduler.mjs index 618fec96..ef57455f 100644 --- a/packages/webaudio/scheduler.mjs +++ b/packages/core/scheduler.mjs @@ -1,6 +1,6 @@ /* scheduler.mjs - -Copyright (C) 2022 Strudel contributors - see +Copyright (C) 2022 Strudel contributors - see This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -10,29 +10,24 @@ export class Scheduler { worker; pattern; phase; - audioContext; cps = 1; - constructor({ audioContext, interval = 0.1, onEvent, latency = 0.1 }) { - this.audioContext = audioContext; - this.worker = new ClockWorker((tick, interval) => { + constructor({ interval = 0.1, onTrigger, latency = 0.1 }) { + this.worker = new ClockWorker((_, interval) => { const begin = this.phase; const end = this.phase + interval * this.cps; this.phase = end; const haps = this.pattern.queryArc(begin, end); - haps.forEach((e) => { - if (typeof e.value?.cps === 'number') { - this.setCps(e.value?.cps); + haps.forEach((hap) => { + if (typeof hap.value?.cps === 'number') { + this.setCps(hap.value?.cps); } - if (!e.part.begin.equals(e.whole.begin)) { + if (!hap.part.begin.equals(hap.whole.begin)) { return; } - if (e.context.onTrigger) { - const ctxTime = (e.whole.begin - begin) / this.cps + this.audioContext.currentTime + latency; - e.context.onTrigger(ctxTime, e, this.audioContext.currentTime, this.cps); - } - if (onEvent) { - onEvent?.(e); - } + const deadline = (hap.whole.begin - begin) / this.cps + latency; + // TODO: use legato / duration of objectified value + const duration = hap.duration / this.cps; + onTrigger?.(hap, deadline, duration); }); }, interval); } @@ -40,7 +35,6 @@ export class Scheduler { if (!this.pattern) { throw new Error('Scheduler: no pattern set! call .setPattern first.'); } - this.audioContext.resume(); this.phase = 0; this.worker.start(); } diff --git a/packages/webaudio/index.mjs b/packages/webaudio/index.mjs index a3a321ed..5fa1e36e 100644 --- a/packages/webaudio/index.mjs +++ b/packages/webaudio/index.mjs @@ -4,7 +4,5 @@ Copyright (C) 2022 Strudel contributors - see . */ -export * from './clockworker.mjs'; -export * from './scheduler.mjs'; export * from './webaudio.mjs'; export * from './sampler.mjs';