play/pause button
This commit is contained in:
+52
-2
@@ -7,7 +7,13 @@ import { requestCapture } from './capture.js';
|
||||
|
||||
const TICK_MS = 250;
|
||||
|
||||
let state = { items: [], currentId: null, background: AUTO_BACKGROUND, animation: AUTO_ANIMATION };
|
||||
let state = {
|
||||
items: [],
|
||||
currentId: null,
|
||||
background: AUTO_BACKGROUND,
|
||||
animation: AUTO_ANIMATION,
|
||||
paused: false,
|
||||
};
|
||||
let decks = [];
|
||||
let active = 0;
|
||||
let transition = null; // { until, duration, from, to } while crossfading
|
||||
@@ -87,6 +93,9 @@ async function start() {
|
||||
const current = currentItem();
|
||||
if (current) playOn(active, current, { volume: 100, opacity: 1 });
|
||||
|
||||
// Someone may have paused before this page was even opened.
|
||||
if (state.paused) applyPaused(true);
|
||||
|
||||
setInterval(tick, TICK_MS);
|
||||
setInterval(reportProgress, 1000);
|
||||
}
|
||||
@@ -121,7 +130,41 @@ function playOn(index, item, { volume, opacity }) {
|
||||
deck.setOpacity(opacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the decks down or pick them back up. A crossfade in flight is frozen
|
||||
* rather than abandoned: the ramp runs on wall-clock time, so the paused
|
||||
* stretch has to be handed back to it on the way out.
|
||||
*/
|
||||
function applyPaused(paused) {
|
||||
if (!decks.length) return;
|
||||
|
||||
if (paused) {
|
||||
if (transition) transition.pausedAt = performance.now();
|
||||
for (const deck of decks) deck.player.pauseVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (transition?.pausedAt) {
|
||||
transition.startedAt += performance.now() - transition.pausedAt;
|
||||
transition.pausedAt = null;
|
||||
}
|
||||
|
||||
// Only the decks actually in play — the idle one is stopped, not paused.
|
||||
if (decks[active].itemId) decks[active].player.playVideo();
|
||||
if (transition) {
|
||||
decks[transition.to].player.playVideo();
|
||||
rampTransition();
|
||||
}
|
||||
}
|
||||
|
||||
function onDeckState(index, code) {
|
||||
// A load can outrace the pause that arrived just before it, so a deck that
|
||||
// starts playing while we are paused has to be put back down.
|
||||
if (state.paused && code === STATE.PLAYING) {
|
||||
decks[index]?.player.pauseVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (index !== active || transition) return;
|
||||
|
||||
// Safety net: a track that ended without our tick catching it (very short
|
||||
@@ -142,6 +185,11 @@ function onDeckState(index, code) {
|
||||
function tick() {
|
||||
if (!decks.length) return;
|
||||
|
||||
// Nothing moves while paused. Above all the crossfade trigger below, which
|
||||
// reads a playhead that has stopped advancing and would fire at once if the
|
||||
// pause landed inside the last few seconds of a track.
|
||||
if (state.paused) return;
|
||||
|
||||
if (transition) {
|
||||
stepTransition();
|
||||
return;
|
||||
@@ -214,7 +262,7 @@ function beginCrossfade(item, seconds, { advance }) {
|
||||
* rAF entirely, and a half-faded handover would leave two tracks audible.
|
||||
*/
|
||||
function stepTransition() {
|
||||
if (!transition) return false;
|
||||
if (!transition || transition.pausedAt) return false;
|
||||
|
||||
const progress = Math.min((performance.now() - transition.startedAt) / transition.duration, 1);
|
||||
const outgoing = decks[transition.from];
|
||||
@@ -331,9 +379,11 @@ function onMessage(msg) {
|
||||
|
||||
const previousAnimation = state.animation;
|
||||
const previousBackground = state.background;
|
||||
const previousPaused = state.paused;
|
||||
state = msg.state;
|
||||
if (state.background !== previousBackground) backgrounds.setMode(state.background);
|
||||
if (state.animation !== previousAnimation) animations?.setMode(state.animation);
|
||||
if (state.paused !== previousPaused) applyPaused(state.paused);
|
||||
updateGate();
|
||||
pumpProbe();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user