diff --git a/public/index.html b/public/index.html index 266e94c..2af028d 100644 --- a/public/index.html +++ b/public/index.html @@ -320,6 +320,7 @@
현재 호출 번호
-
대기 중 0명
+ @@ -329,6 +330,49 @@ const socket = io(); let currentPin = ''; let currentRole = ''; let myTicketNumber = null; +let lastCalledCount = 0; + +// ── 소리 ────────────────────────────────────── +let audioCtx = null; +let soundMuted = false; + +function initAudio() { + if (audioCtx) return; + audioCtx = new (window.AudioContext || window.webkitAudioContext)(); +} + +function playDingDong() { + if (soundMuted || !audioCtx) return; + if (audioCtx.state === 'suspended') audioCtx.resume(); + const t = audioCtx.currentTime; + + function bell(freq, start, dur, vol) { + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + osc.type = 'sine'; + osc.frequency.setValueAtTime(freq, start); + gain.gain.setValueAtTime(0, start); + gain.gain.linearRampToValueAtTime(vol, start + 0.012); + gain.gain.exponentialRampToValueAtTime(0.0001, start + dur); + osc.start(start); + osc.stop(start + dur + 0.05); + } + + // 띵 (E5 + 옥타브 배음) + bell(659, t, 1.1, 0.40); + bell(1318, t, 1.1, 0.12); + // 동 (C5 + 옥타브 배음) — 0.45초 후 + bell(523, t + 0.45, 1.4, 0.40); + bell(1046, t + 0.45, 1.4, 0.12); +} + +document.getElementById('display-mute-btn').addEventListener('click', () => { + soundMuted = !soundMuted; + document.getElementById('display-mute-btn').textContent = + soundMuted ? '🔇 소리 꺼짐' : '🔔 소리 켜짐'; +}); // ── 유틸 ────────────────────────────────────── function showScreen(id) { @@ -376,7 +420,9 @@ document.getElementById('role-issue').addEventListener('click', () => { showScreen('screen-issue'); }); document.getElementById('role-display').addEventListener('click', () => { - currentRole = 'display'; showScreen('screen-display'); + currentRole = 'display'; + initAudio(); // 사용자 인터랙션 직후 AudioContext 생성 (autoplay 정책) + showScreen('screen-display'); }); // 역할 변경 @@ -424,8 +470,12 @@ function applyState(s) { displayEl.classList.remove('flash'); void displayEl.offsetWidth; // reflow displayEl.textContent = newVal; - if (s.calledCount > 0) displayEl.classList.add('flash'); + if (s.calledCount > 0) { + displayEl.classList.add('flash'); + if (currentRole === 'display') playDingDong(); + } } + lastCalledCount = s.calledCount; document.getElementById('display-sub').textContent = `대기 중 ${s.waitingCount}명`; }