From 91876d11e30af080541275e1b2d034383fe7081a Mon Sep 17 00:00:00 2001 From: Speedauge <192351844+Speedauge@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:34:32 +0200 Subject: [PATCH] fix : sound overlap issue (#38) --- src/lib/sounds.ts | 59 +++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/lib/sounds.ts b/src/lib/sounds.ts index 077a0ad..d4c4076 100644 --- a/src/lib/sounds.ts +++ b/src/lib/sounds.ts @@ -1,37 +1,40 @@ import { Move } from "chess.js"; -let audioContext: AudioContext | null = null; -let audio: HTMLAudioElement | null = null; +let ctx: AudioContext | null = null; +const bufferCache = new Map(); -const playSound = async (url: string) => { - if (!audio) { - audioContext = new AudioContext(); - audio = new Audio(); - const source = audioContext.createMediaElementSource(audio); - const volume = audioContext.createGain(); - volume.gain.value = 0.3; - source.connect(volume); - volume.connect(audioContext.destination); - } +const urls = { + move: "/sounds/move.mp3", + capture: "/sounds/capture.mp3", + illegal: "/sounds/illegal-move.mp3" +} as const; +type Sound = keyof typeof urls; - audio.src = url; +async function play(sound: Sound) { try { - await audio.play(); + ctx ??= new (window.AudioContext || (window as any).webkitAudioContext)(); + if (ctx.state === "suspended") await ctx.resume(); + let buf = bufferCache.get(urls[sound]); + if (!buf) { + const res = await fetch(urls[sound]); + buf = await ctx.decodeAudioData(await res.arrayBuffer()); + bufferCache.set(urls[sound], buf); + } + const src = ctx.createBufferSource(); + src.buffer = buf; + src.connect(ctx.destination); + src.start(); } catch { - console.warn("Audio play failed"); + if ("vibrate" in navigator) navigator.vibrate(50); } -}; +} -export const playCaptureSound = () => playSound("/sounds/capture.mp3"); -export const playIllegalMoveSound = () => playSound("/sounds/error.mp3"); -export const playMoveSound = () => playSound("/sounds/move.mp3"); +export const playCaptureSound = () => play("capture"); +export const playIllegalMoveSound = () => play("illegal"); +export const playMoveSound = () => play("move"); -export const playSoundFromMove = async (move: Move | null) => { - if (!move) { - playIllegalMoveSound(); - } else if (move.captured) { - playCaptureSound(); - } else { - playMoveSound(); - } -}; +export async function playSoundFromMove(move: Move | null) { + if (!move) return playIllegalMoveSound(); + if (move.captured) return playCaptureSound(); + return playMoveSound(); +} \ No newline at end of file