"use client"; /** * Chip-bank movement sounds for the fixed Chip Bank card. Independent of the * table sound engines (the card lives on both the poker and blackjack pages, * outside any table). Best-effort autoplay: if the browser blocks the * AudioContext until a gesture, these simply stay silent. */ let ctx: AudioContext | null = null; function getCtx(): AudioContext | null { if (typeof window === "undefined") return null; try { if (!ctx) { const Ctor = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext; if (!Ctor) return null; ctx = new Ctor(); } if (ctx.state === "suspended") { void ctx.resume().catch(() => undefined); } return ctx; } catch { return null; } } function tone( frequency: number, nextFrequency: number, duration: number, delay: number, volume = 0.14, ): void { const context = getCtx(); if (!context) return; try { const start = context.currentTime + delay; const oscillator = context.createOscillator(); const gain = context.createGain(); oscillator.type = "sine"; oscillator.frequency.setValueAtTime(frequency, start); oscillator.frequency.exponentialRampToValueAtTime(Math.max(1, nextFrequency), start + duration); gain.gain.setValueAtTime(0.0001, start); gain.gain.exponentialRampToValueAtTime(volume, start + 0.015); gain.gain.exponentialRampToValueAtTime(0.0001, start + duration); oscillator.connect(gain); gain.connect(context.destination); oscillator.start(start); oscillator.stop(start + duration + 0.05); } catch { // Sound is best-effort; never throw from a balance indicator. } } /** Chips arriving: short rising pair. */ export function playChipBankUp(): void { tone(523, 523, 0.09, 0); tone(784, 784, 0.12, 0.09); } /** Chips leaving: short falling pair. */ export function playChipBankDown(): void { tone(392, 392, 0.09, 0); tone(262, 262, 0.14, 0.09); }