simplify playback speed code

cherrypicked from 957d46e (rework playback speed, 2024-06-29)
and d1a8e5e (simplify audioworklet, 2024-06-21)
This commit is contained in:
SArpnt 2024-08-02 23:28:53 -04:00
parent ba4742cfd8
commit 5ec0219691
Signed by: SArpnt
SSH key fingerprint: SHA256:iDMeic8KkqqEsN4wODlgsk1d/oW1ojZ/cu/MEWyfLBw
4 changed files with 77 additions and 94 deletions

View file

@ -64,13 +64,11 @@ class BytebeatProcessor extends AudioWorkletProcessor {
lastValue = [0, 0];
lastFuncValue = [null, null];
isPlaying = false;
func = null;
calcByteValue = null;
songData = { sampleRate: null, mode: null };
sampleRateDivisor = 1;
playSpeed = 1;
playSpeed = 0;
postedErrorPriority = null;
constructor() {
@ -91,7 +89,7 @@ class BytebeatProcessor extends AudioWorkletProcessor {
const data = e.data;
// set vars
for (let v of ["isPlaying", "songData", "sampleRateDivisor", "playSpeed"]) {
for (let v of ["songData", "sampleRateDivisor", "playSpeed"]) {
if (data[v] !== undefined) {
this[v] = data[v];
}
@ -219,7 +217,7 @@ class BytebeatProcessor extends AudioWorkletProcessor {
): boolean {
const chData = outputs[0];
const chDataLen = chData[0].length; // for performance
if (!chDataLen || !this.isPlaying || !this.func) {
if (!chDataLen || !this.playSpeed || !this.func) {
return true;
}

View file

@ -7,6 +7,19 @@ import { Oscillioscope } from "./oscillioscope.ts";
const timeUnits = ["t", "s"] as const;
type TimeUnit = (typeof timeUnits)[number];
// XXX: global variables
let timeUnit: TimeUnit;
let volume: number;
let byteSample = 0;
let playSpeed = 0;
let songData: {
sampleRate: number;
mode: SongMode;
} = {
sampleRate: 8000, // float32
mode: "Bytebeat",
};
const searchParams = new URLSearchParams(location.search);
const audioPromise = initAudioContext();
@ -18,35 +31,23 @@ if (globalThis.loadLibrary !== false) {
}
handleWindowResize(true);
document.defaultView.addEventListener("resize", () => handleWindowResize(false));
let volume: number;
let timeUnit: TimeUnit;
addEventListener("resize", () => handleWindowResize(false));
const { audioCtx, audioGain, audioWorklet } = await audioPromise;
loadSettings();
let urlData: Song | undefined;
if (window.location.hash && globalThis.useUrlData !== false) {
urlData = await fromUrlData(window.location.hash);
{
let urlData: Song | undefined;
if (location.hash && globalThis.useUrlData !== false) {
urlData = await fromUrlData(location.hash);
}
setSong(urlData, false);
updateCounterValue();
}
let isPlaying = false;
let playSpeed = 1;
let byteSample = 0;
let songData: {
sampleRate: number;
mode: SongMode;
} = {
sampleRate: 8000, // float32
mode: "Bytebeat",
};
setSong(urlData, false);
updateCounterValue();
// XXX: global variables
let nextErrType = null;
let nextErr = null;
let nextErrPriority = undefined;
@ -54,8 +55,8 @@ let errorPriority = -Infinity;
async function initAudioContext() {
let audioContextSampleRate = Number(searchParams.get("baseSampleRate"));
// also true for NaN
if (!(audioContextSampleRate > 0)) {
// also true for NaN
audioContextSampleRate = 48000; // TODO this should be set to an lcm > 44100
}
@ -99,7 +100,7 @@ export function setSong(songData?: StrongPartial<Song>, play = true) {
refresh();
if (play) {
resetTime();
togglePlay(true);
setPlaySpeed(1);
}
}
/// call refresh after calling this
@ -154,7 +155,7 @@ function handleMessage(e: MessageEvent<any>) {
typeof data.errorMessage.err === "string" &&
typeof (data.errorMessage.priority ?? 0) === "number"
) {
if (isPlaying) {
if (playSpeed) {
nextErrType = data.errorMessage.type;
nextErr = data.errorMessage.err;
nextErrPriority = data.errorMessage.priority;
@ -178,7 +179,6 @@ function handleWindowResize(force?: boolean) {
}
export function autoSizeCanvas(force: boolean = false) {
if (!elements.canvas.dataset["forcedWidth"]) {
const innerWidth = window.innerWidth;
// 768 is halfway between 512 and 1024, 3 added for outline
if (innerWidth >= 768 + 3) {
let width = 1024;
@ -215,21 +215,10 @@ function changeScale(amount: number) {
}
osc.showTimeCursor(timeCursorShouldBeVisible());
osc.moveTimeCursor(byteSample, playSpeed > 0);
osc.moveTimeCursor(byteSample, playSpeed >= 0);
saveSettings();
}
}
function animationFrame() {
osc.draw(byteSample, playSpeed > 0);
osc.moveTimeCursor(byteSample, playSpeed > 0);
if (nextErr) {
showErrorMessage(nextErrType, nextErr, nextErrPriority);
}
if (isPlaying) {
window.requestAnimationFrame(() => animationFrame());
}
}
function showErrorMessage(errType, err, priority = 0) {
if (elements.error && (errorPriority < 2 || priority > 0)) {
@ -259,10 +248,11 @@ function hideErrorMessage() {
function resetTime() {
setByteSample(0, true, true);
if (!isPlaying) {
if (!playSpeed) {
elements.canvasTogglePlay.classList.add("canvas-toggleplay-show");
}
}
/// TODO document
function setByteSample(value: number, send = true, clear = false) {
if (audioWorklet && isFinite(value)) {
byteSample = value;
@ -270,28 +260,47 @@ function setByteSample(value: number, send = true, clear = false) {
if (send) {
audioWorklet.port.postMessage({ setByteSample: [value, clear] });
}
osc.moveTimeCursor(byteSample, playSpeed > 0);
osc.moveTimeCursor(byteSample, playSpeed >= 0);
}
}
function setPlaySpeed(value: number) {
if (audioWorklet && value !== playSpeed) {
elements.canvasTogglePlay.classList.toggle("canvas-toggleplay-pause", !!value);
if (value) {
elements.canvasTogglePlay.classList.remove("canvas-toggleplay-show");
audioCtx.resume();
startAnimation();
} else {
//audioCtx.suspend();
stopAnimation();
}
playSpeed = value;
audioWorklet.port.postMessage({ playSpeed, updateSampleRatio: true });
}
}
function togglePlay(play: boolean = !isPlaying) {
if (audioWorklet && play !== isPlaying) {
elements.canvasTogglePlay.classList.toggle("canvas-toggleplay-pause", play);
if (play) {
elements.canvasTogglePlay.classList.remove("canvas-toggleplay-show");
if (audioCtx?.resume) {
audioCtx.resume();
}
window.requestAnimationFrame(() => animationFrame());
function togglePlay() {
setPlaySpeed(+!playSpeed);
}
{
let request = undefined as unknown as number;
function animationFrame() {
osc.draw(byteSample, playSpeed >= 0);
osc.moveTimeCursor(byteSample, playSpeed >= 0);
if (nextErr) {
showErrorMessage(nextErrType, nextErr, nextErrPriority);
}
isPlaying = play;
audioWorklet.port.postMessage({ isPlaying });
startAnimation();
}
function startAnimation() {
request = requestAnimationFrame(() => animationFrame());
}
function stopAnimation() {
animationFrame();
cancelAnimationFrame(request);
}
}

View file

@ -33,23 +33,11 @@ html(data-embed lang="en")
)
span.control-group.control-time.buttons
button#control-restart(onclick="bytebeat.resetTime()" title="Restart") &#9198;&#65038;
button#control-fr(
onclick="bytebeat.setPlaySpeed(-4); bytebeat.togglePlay(true)"
title="Fast reverse"
) &#9194;&#65038;
button#control-reverse(
onclick="bytebeat.setPlaySpeed(-1); bytebeat.togglePlay(true)"
title="Reverse"
) &#9204;&#65038;
button#control-pause(onclick="bytebeat.togglePlay(false)" title="Pause") &#9208;&#65038;
button#control-play(
onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay(true)"
title="Play"
) &#9205;&#65038;
button#control-ff(
onclick="bytebeat.setPlaySpeed(4); bytebeat.togglePlay(true)"
title="Fast Forward"
) &#9193;&#65038;
button#control-fr(onclick="bytebeat.setPlaySpeed(-4)" title="Fast reverse") &#9194;&#65038;
button#control-reverse(onclick="bytebeat.setPlaySpeed(-1)" title="Reverse") &#9204;&#65038;
button#control-pause(onclick="bytebeat.setPlaySpeed(0)" title="Pause") &#9208;&#65038;
button#control-play(onclick="bytebeat.setPlaySpeed(1)" title="Play") &#9205;&#65038;
button#control-ff(onclick="bytebeat.setPlaySpeed(4)" title="Fast Forward") &#9193;&#65038;
span.control-group.control-playback
input#control-volume(
oninput="bytebeat.setVolume()"
@ -97,7 +85,7 @@ html(data-embed lang="en")
label.control-playback(for="control-sample-rate-divisor") /
input#control-sample-rate-divisor.control-playback.control-round-left.control-round-right(
onchange="bytebeat.setSampleRateDivisor(+this.value); bytebeat.refresh()"
style="width: 3em"
style="width:3em"
value="1"
step="1"
min="1"
@ -114,7 +102,7 @@ html(data-embed lang="en")
option(value="48000")
#error
#canvas-container(
onclick="if (this.dataset.disabled !== 'true') {bytebeat.setPlaySpeed(1); bytebeat.togglePlay()}"
onclick="if (this.dataset.disabled !== 'true') {bytebeat.togglePlay()}"
)
canvas#canvas-main(height="256" width="1024" aria-label="Oscillioscope")
#canvas-timecursor

View file

@ -29,23 +29,11 @@ html(lang="en")
)
span.control-group.control-time.buttons
button#control-restart(onclick="bytebeat.resetTime()" title="Restart") &#9198;&#65038;
button#control-fr(
onclick="bytebeat.setPlaySpeed(-4); bytebeat.togglePlay(true)"
title="Fast reverse"
) &#9194;&#65038;
button#control-reverse(
onclick="bytebeat.setPlaySpeed(-1); bytebeat.togglePlay(true)"
title="Reverse"
) &#9204;&#65038;
button#control-pause(onclick="bytebeat.togglePlay(false)" title="Pause") &#9208;&#65038;
button#control-play(
onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay(true)"
title="Play"
) &#9205;&#65038;
button#control-ff(
onclick="bytebeat.setPlaySpeed(4); bytebeat.togglePlay(true)"
title="Fast Forward"
) &#9193;&#65038;
button#control-fr(onclick="bytebeat.setPlaySpeed(-4)" title="Fast reverse") &#9194;&#65038;
button#control-reverse(onclick="bytebeat.setPlaySpeed(-1)" title="Reverse") &#9204;&#65038;
button#control-pause(onclick="bytebeat.setPlaySpeed(0)" title="Pause") &#9208;&#65038;
button#control-play(onclick="bytebeat.setPlaySpeed(1)" title="Play") &#9205;&#65038;
button#control-ff(onclick="bytebeat.setPlaySpeed(4)" title="Fast Forward") &#9193;&#65038;
span.control-group.control-playback
input#control-volume(
oninput="bytebeat.setVolume()"
@ -93,7 +81,7 @@ html(lang="en")
label.control-playback(for="control-sample-rate-divisor") /
input#control-sample-rate-divisor.control-playback.control-round-left.control-round-right(
onchange="bytebeat.setSampleRateDivisor(+this.value); bytebeat.refresh()"
style="width: 3em"
style="width:3em"
value="1"
step="1"
min="1"
@ -109,7 +97,7 @@ html(lang="en")
option(value="44100")
option(value="48000")
#error
#canvas-container(onclick="bytebeat.setPlaySpeed(1); bytebeat.togglePlay()")
#canvas-container(onclick="bytebeat.togglePlay()")
canvas#canvas-main(height="256" width="1024" aria-label="Oscillioscope")
#canvas-timecursor
#canvas-toggleplay.canvas-toggleplay-show