diff --git a/examples/worker-repl/main.js b/examples/worker-repl/main.js index 35454787..059d2065 100644 --- a/examples/worker-repl/main.js +++ b/examples/worker-repl/main.js @@ -1,89 +1,34 @@ -import workerUrl from './worker.mjs?url'; -import { samples, superdough } from 'superdough'; +import { createClock, seq } from '@strudel/core'; +import { getAudioContext, initAudioOnFirstClick, samples, superdough } from 'superdough'; +import { setInterval, clearInterval } from 'worker-timers'; // comment out this line to test with window.setInterval -let ctx; -document.addEventListener('click', async () => { - ctx = new AudioContext(); - await samples('github:tidalcycles/dirt-samples'); - initWorker(); -}); - -function initWorker() { - if (!globalThis.Worker) { - throw new Error('initWorker: Worker not supported in this environment'); - } - const worker = new Worker(workerUrl); - worker.postMessage({ origin: performance.timeOrigin }); - // worker.postMessage(1); - let origin; - let minLatency = 0.05; - - let init = performance.now(); - - // performance.timeOrigin; // unix timestamp when the page loads - // Date.now() // unix timestamp (ms since January 1st 1970) - // performance.timeOrigin // unix timestamp when the page loaded - // performance.now() // precise ms since the page loaded - // performance.timeOrigin + performance.now() ~= Date.now() - - // worker: performance.now() // precise ms since the worker loaded - // worker: performance.timeOrigin // unix timestamp when the worker loaded - - worker.onmessage = (e) => { - const { contextTime, performanceTime } = ctx.getOutputTimestamp(); - console.log('e', e.timeStamp, performance.now()); - /* // clock offsets - const { contextTime: t } = outputTimestamp; // audio clock time in seconds - const { performanceTime: now } = outputTimestamp; // estimated system clock time for contextTime - const { origin: workerOrigin } = e.data; // seconds when the worker was loaded - const { phase } = e.data; // target time in seconds of current tick (relative to system clock) - - let workerOriginDiffMs = workerOrigin - performance.timeOrigin; - // console.log('worker created after seconds:', workerOriginDiffMs); - - let workerOriginDiffSeconds = workerOriginDiffMs / 1000; - - let workerPhaseSeconds = phase + workerOriginDiffSeconds; - let nowSeconds = now / 1000; - - let workerDeadline = workerPhaseSeconds - nowSeconds; */ - - // console.log('workerDeadline', workerDeadline); - - // superdough({ s: 'bd' }, workerDeadline); - - e.data.forEach((event, i) => { - let phase = event.phase * 1000; - //let phase = event.tick * 100 + origin; - let diff = (phase - performanceTime) / 1000; - superdough({ s: 'bd' }, contextTime + diff + 2); - }); - - /* const deadline = phase - now; - - const { tickOrigin } = e.data; // ms when the first tick happened - - const { tick, begin, end, haps, cps } = e.data; - - // console.log('phase', phase); - if (tick === 0) { - console.log('set origin', t); - origin = t; - } - // console.log('tick', tick, begin, end, phase, origin); - haps.forEach((hap) => { - let hapBegin = hap.whole.begin; - hapBegin = (hapBegin.s * hapBegin.n) / hapBegin.d; - const stamp = ctx.getOutputTimestamp(); - - let targetTime = origin + hapBegin * cps; - let deadline = t - targetTime + minLatency; - // console.log('--hap, begin:', begin, 'deadline', deadline); - // console.log('hap', hap.value, begin, deadline); - superdough(hap.value, deadline); - }); */ - - // const stamp = ctx?.getOutputTimestamp(); - // console.log('stamp', stamp); - }; +let loaded = samples('github:tidalcycles/dirt-samples'); +async function run() { + // let pat = seq('hh').s().fast(25.2); + let pat = seq('bd', ['hh', 'hh'], 'jvbass').s().fast(1.92); + await initAudioOnFirstClick(); + await loaded; + const ctx = getAudioContext(); + let last = 0; + const clock = createClock( + () => ctx.currentTime, + (phase, duration, tick, t) => { + const [begin, end] = [last, (last = tick * duration)]; + console.log('q', begin.toFixed(2), end.toFixed(2), phase.toFixed(2)); + let haps = pat.queryArc(begin, end).filter((h) => h.hasOnset()); + // console.log('phase', phase, haps.length); + haps.forEach((hap) => { + superdough(hap.value, '=' + String(hap.whole.begin + 0.1)); + }); + }, + 0.025, // duration of each cycle + 0.1, // interval between callbacks + 0.4, // overlap between callbacks + setInterval, + clearInterval, + false, + ); + clock.start(); } + +run(); diff --git a/examples/worker-repl/package.json b/examples/worker-repl/package.json index 742b0683..9f430b26 100644 --- a/examples/worker-repl/package.json +++ b/examples/worker-repl/package.json @@ -11,5 +11,8 @@ "devDependencies": { "vite": "^5.2.0" }, - "dependencies": {"superdough":"workspace:*"} + "dependencies": { + "superdough": "workspace:*", + "worker-timers": "^7.1.4" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61c2f2e7..5bcd702a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,6 +142,9 @@ importers: superdough: specifier: workspace:* version: link:../../packages/superdough + worker-timers: + specifier: ^7.1.4 + version: 7.1.4 devDependencies: vite: specifier: ^5.2.0 @@ -2194,6 +2197,13 @@ packages: regenerator-runtime: 0.14.1 dev: true + /@babel/runtime@7.24.1: + resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: false + /@babel/template@7.22.15: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} engines: {node: '>=6.9.0'} @@ -7587,6 +7597,14 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + /fast-unique-numbers@8.0.13: + resolution: {integrity: sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==} + engines: {node: '>=16.1.0'} + dependencies: + '@babel/runtime': 7.24.1 + tslib: 2.6.2 + dev: false + /fast-xml-parser@4.3.3: resolution: {integrity: sha512-coV/D1MhrShMvU6D0I+VAK3umz6hUaxxhL0yp/9RjfiYUfAv14rDhGQL+PLForhMdr0wq3PiV07WtkkNjJjNHg==} hasBin: true @@ -12008,7 +12026,6 @@ packages: /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} @@ -13430,7 +13447,6 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} requiresBuild: true - optional: true /tsutils@3.21.0(typescript@5.3.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -14433,6 +14449,31 @@ packages: workbox-core: 7.0.0 dev: true + /worker-timers-broker@6.1.4: + resolution: {integrity: sha512-y3D+Yfj37lrItEMIlcfCm/IRueYtYKgpLlTG2wgTIZ9PSw0n/K4kweilgk3gTC4ahbQNVGT90lU+Rf7W4M5bsw==} + dependencies: + '@babel/runtime': 7.24.1 + fast-unique-numbers: 8.0.13 + tslib: 2.6.2 + worker-timers-worker: 7.0.67 + dev: false + + /worker-timers-worker@7.0.67: + resolution: {integrity: sha512-0ZP2+v2fyiiiGaCEdWxMRUk5YxGFwWdRGB12ZfQy13vw8/27Xd+MW3ua56qlcM30nzjpddXXzLuEpHhGW+Pz7w==} + dependencies: + '@babel/runtime': 7.24.1 + tslib: 2.6.2 + dev: false + + /worker-timers@7.1.4: + resolution: {integrity: sha512-8PRtiPAyeYukrY+iOUL+0tq4Zn5qyCHrTqFTtHxcESfIxGyulxNwyzQkybrYBKhnMWmx0bku3wxRfE1hts5R6Q==} + dependencies: + '@babel/runtime': 7.24.1 + tslib: 2.6.2 + worker-timers-broker: 6.1.4 + worker-timers-worker: 7.0.67 + dev: false + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'}