const MUTE_KEY = "lelab.recording.muted"; let ctx: AudioContext | null = null; const getCtx = (): AudioContext => { if (!ctx) ctx = new AudioContext(); return ctx; }; export const getMuted = (): boolean => { return localStorage.getItem(MUTE_KEY) === "1"; }; export const setMuted = (value: boolean): void => { localStorage.setItem(MUTE_KEY, value ? "1" : "0"); }; const playTone = (frequency: number, durationMs: number, startOffsetMs = 0) => { if (getMuted()) return; const c = getCtx(); const osc = c.createOscillator(); const gain = c.createGain(); osc.frequency.value = frequency; osc.type = "sine"; gain.gain.value = 0; osc.connect(gain); gain.connect(c.destination); const start = c.currentTime + startOffsetMs / 1000; const stop = start + durationMs / 1000; gain.gain.setValueAtTime(0, start); gain.gain.linearRampToValueAtTime(0.2, start + 0.01); gain.gain.setValueAtTime(0.2, stop - 0.02); gain.gain.linearRampToValueAtTime(0, stop); osc.start(start); osc.stop(stop); }; export const playRecordingStartCue = (): void => { playTone(660, 80, 0); playTone(880, 80, 90); }; export const playResetStartCue = (): void => { playTone(660, 80, 0); playTone(440, 80, 90); }; export const playAutoAdvanceWarning = (): void => { playTone(880, 70, 0); playTone(880, 70, 1000); playTone(880, 70, 2000); };