mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 21:58:37 +00:00
117 lines
3.6 KiB
JavaScript
117 lines
3.6 KiB
JavaScript
// used to consistently schedule events
|
|
const createClock = (
|
|
getTime,
|
|
callback, // called slightly before each cycle
|
|
duration = 0.05, // duration of each cycle
|
|
interval = 0.1, // interval between callbacks
|
|
overlap = 0.1, // overlap between callbacks
|
|
) => {
|
|
let tick = 0; // counts callbacks
|
|
let phase = 0; // next callback time
|
|
let precision = 10 ** 4; // used to round phase
|
|
let minLatency = 0;
|
|
const setDuration = (setter) => (duration = setter(duration));
|
|
overlap = overlap || interval / 2;
|
|
const onTick = () => {
|
|
const t = getTime();
|
|
const lookahead = t + interval + overlap; // the time window for this tick
|
|
if (phase === 0) {
|
|
phase = t + minLatency;
|
|
}
|
|
// callback as long as we're inside the lookahead
|
|
while (phase < lookahead) {
|
|
// phase = Math.round(phase * precision) / precision;
|
|
phase >= t && callback(phase, duration, tick, t);
|
|
phase < t && console.log('TOO LATE', phase); // what if latency is added from outside?
|
|
phase += duration; // increment phase by duration
|
|
tick++;
|
|
}
|
|
};
|
|
let intervalID;
|
|
const start = () => {
|
|
clear(); // just in case start was called more than once
|
|
onTick();
|
|
intervalID = setInterval(onTick, interval * 1000);
|
|
};
|
|
const clear = () => intervalID !== undefined && clearInterval(intervalID);
|
|
const pause = () => clear();
|
|
const stop = () => {
|
|
tick = 0;
|
|
phase = 0;
|
|
clear();
|
|
};
|
|
const getPhase = () => phase;
|
|
// setCallback
|
|
return { setDuration, start, stop, pause, duration, interval, getPhase, minLatency };
|
|
};
|
|
|
|
onmessage = async function (e) {
|
|
console.log('Worker: Message received from main script', e);
|
|
|
|
/* const { seq } = await import('@strudel/core');
|
|
let pat = seq('bd').fast(4).s(); */
|
|
if (!e.data.origin) {
|
|
console.log('no origin');
|
|
return;
|
|
}
|
|
console.log('start!', e.data.origin);
|
|
// e.data.origin = unix ms when main document was created
|
|
// performance.timeOrigin = unix ms when worker was created
|
|
let originDiff = (performance.timeOrigin - e.data.origin) / 1000;
|
|
let firstTick;
|
|
console.log('originDiff', originDiff);
|
|
|
|
let precision = 10 ** 4;
|
|
let cps = 0.5;
|
|
let interval = 0.05;
|
|
let tickOrigin;
|
|
let lastEnd = 0;
|
|
let bag = [];
|
|
let clock = createClock(
|
|
() => performance.now() / 1000,
|
|
(phase, duration, tick, t) => {
|
|
if (tick === 0) {
|
|
firstTick = t;
|
|
console.log('firstTick', t);
|
|
}
|
|
// let durationInCycles = duration * cps;
|
|
/* phase = lastEnd; */
|
|
// phase = Math.round(phase * precision) / precision;
|
|
|
|
bag.push({ tick, duration, phase, cps, origin: performance.timeOrigin });
|
|
//postMessage({ tick, phase, cps, origin: performance.timeOrigin });
|
|
let pack = 4;
|
|
if (bag.length === pack) {
|
|
console.log('send', performance.now());
|
|
postMessage(bag);
|
|
bag = [];
|
|
}
|
|
|
|
/* phase += duration;
|
|
lastEnd = phase; */
|
|
/*if (tick === 0) {
|
|
tickOrigin = performance.now();
|
|
}
|
|
let begin = lastEnd || 0;
|
|
let end = begin + duration * cps;
|
|
lastEnd = end;
|
|
//console.log('query', begin, phase);
|
|
const haps = pat.queryArc(begin, end).filter((hap) => hap.hasOnset());
|
|
if (haps.length) {
|
|
postMessage({ tick, phase, begin, end, haps, cps, tickOrigin, origin: performance.timeOrigin });
|
|
}
|
|
*/
|
|
/* console.log(
|
|
'tick',
|
|
phase,
|
|
`${begin.toFixed(2)}-${end.toFixed(2)}: ${haps
|
|
.map((h) => `${h.value.s}:${(h.whole.begin + 0).toFixed(2)}`)
|
|
.join(' ')}`,
|
|
); */
|
|
},
|
|
interval,
|
|
interval,
|
|
);
|
|
clock.start();
|
|
};
|