fix firefox hanging?

This commit is contained in:
Joeri Exelmans 2025-10-31 16:28:51 +01:00
parent 6a12ba5341
commit eb9792a8d7
2 changed files with 20 additions and 17 deletions

View file

@ -53,6 +53,7 @@ export const TrafficLight = memo(function TrafficLight({state, speed, raiseUIEve
stopPlaying(); stopPlaying();
}; };
} }
else return () => {};
}, [redOn || yellowOn || greenOn]) }, [redOn || yellowOn || greenOn])
return <> return <>

View file

@ -1,5 +1,5 @@
import { memoize } from "@/util/util"; import { memoize } from "@/util/util";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
// I was trying to get the 'microwave running' sound to play gapless on Chrome, and the Web Audio API turned out to be the only thing that worked properly. It has some nice bonus features as well, such as setting the playback rate, and audio filters. // I was trying to get the 'microwave running' sound to play gapless on Chrome, and the Web Audio API turned out to be the only thing that worked properly. It has some nice bonus features as well, such as setting the playback rate, and audio filters.
@ -7,31 +7,33 @@ import { useCallback, useEffect, useState } from "react";
// The result is a simple Web Audio API wrapper for React: // The result is a simple Web Audio API wrapper for React:
export function useAudioContext(speed: number) { export function useAudioContext(speed: number) {
const [{ctx,hipass}] = useState(() => { const ref = useRef<{ctx: AudioContext, hipass: BiquadFilterNode}>(null);
const ctx = new AudioContext();
const hipass = ctx.createBiquadFilter(); useEffect(() => {
if (!ref.current) {
const audioCtx = new AudioContext();
const hipass = audioCtx.createBiquadFilter();
hipass.type = 'highpass'; hipass.type = 'highpass';
hipass.frequency.value = 20; // Hz (let's not blow up anyone's speakers) hipass.frequency.value = 20; // Hz (let's not blow up anyone's speakers)
hipass.connect(ctx.destination); hipass.connect(audioCtx.destination);
return { ref.current = { ctx: audioCtx, hipass };
ctx,
hipass,
} }
}); }, []);
const [sounds, setSounds] = useState<AudioBufferSourceNode[]>([]); const [sounds, setSounds] = useState<AudioBufferSourceNode[]>([]);
const url2AudioBuf: (url:string) => Promise<AudioBuffer> = useCallback(memoize((url: string) => { const url2AudioBuf: (url:string) => Promise<AudioBuffer> = useCallback(memoize((url: string) => {
return fetch(url) return fetch(url)
.then(res => res.arrayBuffer()) .then(res => res.arrayBuffer())
.then(buf => ctx.decodeAudioData(buf)); .then(buf => ref.current!.ctx.decodeAudioData(buf));
}), [ctx]); }), [ref.current]);
function play(url: string, loop: boolean) { function play(url: string, loop: boolean) {
const srcPromise = url2AudioBuf(url) const srcPromise = url2AudioBuf(url)
.then(audioBuf => { .then(audioBuf => {
const src = ctx.createBufferSource(); const src = ref.current!.ctx.createBufferSource();
src.buffer = audioBuf; src.buffer = audioBuf;
src.connect(hipass); src.connect(ref.current!.hipass);
src.playbackRate.value = speed; src.playbackRate.value = speed;
src.loop = loop; src.loop = loop;
src.start(); src.start();
@ -50,10 +52,10 @@ export function useAudioContext(speed: number) {
sounds.forEach(src => { sounds.forEach(src => {
src.playbackRate.value = speed; src.playbackRate.value = speed;
}); });
ctx.resume(); ref.current!.ctx.resume();
} }
else { else {
ctx.suspend(); ref.current!.ctx.suspend();
} }
}, [speed]); }, [speed]);