From eb9792a8d79b8af8efcff8056e76e010df6bce39 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 31 Oct 2025 16:28:51 +0100 Subject: [PATCH] fix firefox hanging? --- src/App/Plant/TrafficLight/TrafficLight.tsx | 1 + src/App/useAudioContext.ts | 36 +++++++++++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/App/Plant/TrafficLight/TrafficLight.tsx b/src/App/Plant/TrafficLight/TrafficLight.tsx index cfd6b47..a105f21 100644 --- a/src/App/Plant/TrafficLight/TrafficLight.tsx +++ b/src/App/Plant/TrafficLight/TrafficLight.tsx @@ -53,6 +53,7 @@ export const TrafficLight = memo(function TrafficLight({state, speed, raiseUIEve stopPlaying(); }; } + else return () => {}; }, [redOn || yellowOn || greenOn]) return <> diff --git a/src/App/useAudioContext.ts b/src/App/useAudioContext.ts index 4878ed8..7b7c2b1 100644 --- a/src/App/useAudioContext.ts +++ b/src/App/useAudioContext.ts @@ -1,5 +1,5 @@ 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. @@ -7,31 +7,33 @@ import { useCallback, useEffect, useState } from "react"; // The result is a simple Web Audio API wrapper for React: export function useAudioContext(speed: number) { - const [{ctx,hipass}] = useState(() => { - const ctx = new AudioContext(); - const hipass = ctx.createBiquadFilter(); - hipass.type = 'highpass'; - hipass.frequency.value = 20; // Hz (let's not blow up anyone's speakers) - hipass.connect(ctx.destination); - return { - ctx, - hipass, + const ref = useRef<{ctx: AudioContext, hipass: BiquadFilterNode}>(null); + + useEffect(() => { + if (!ref.current) { + const audioCtx = new AudioContext(); + const hipass = audioCtx.createBiquadFilter(); + hipass.type = 'highpass'; + hipass.frequency.value = 20; // Hz (let's not blow up anyone's speakers) + hipass.connect(audioCtx.destination); + ref.current = { ctx: audioCtx, hipass }; } - }); + }, []); + const [sounds, setSounds] = useState([]); const url2AudioBuf: (url:string) => Promise = useCallback(memoize((url: string) => { return fetch(url) .then(res => res.arrayBuffer()) - .then(buf => ctx.decodeAudioData(buf)); - }), [ctx]); + .then(buf => ref.current!.ctx.decodeAudioData(buf)); + }), [ref.current]); function play(url: string, loop: boolean) { const srcPromise = url2AudioBuf(url) .then(audioBuf => { - const src = ctx.createBufferSource(); + const src = ref.current!.ctx.createBufferSource(); src.buffer = audioBuf; - src.connect(hipass); + src.connect(ref.current!.hipass); src.playbackRate.value = speed; src.loop = loop; src.start(); @@ -50,10 +52,10 @@ export function useAudioContext(speed: number) { sounds.forEach(src => { src.playbackRate.value = speed; }); - ctx.resume(); + ref.current!.ctx.resume(); } else { - ctx.suspend(); + ref.current!.ctx.suspend(); } }, [speed]);