initial
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// One-shot call sound effects via WebAudio. Generated on the fly so no
|
||||
// binary assets needed. Intentionally short + low-volume — these fire
|
||||
// multiple times per call and shouldn't feel intrusive.
|
||||
|
||||
type Sfx = 'join' | 'leave' | 'end';
|
||||
|
||||
let ctx: AudioContext | null = null;
|
||||
|
||||
function getCtx(): AudioContext | null {
|
||||
if (ctx) return ctx;
|
||||
const AudioCtx =
|
||||
window.AudioContext ??
|
||||
(window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
|
||||
if (!AudioCtx) return null;
|
||||
ctx = new AudioCtx();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
function beep(freq: number, durationSec: number, delaySec: number, gain = 0.15): void {
|
||||
const c = getCtx();
|
||||
if (!c) return;
|
||||
const osc = c.createOscillator();
|
||||
const g = c.createGain();
|
||||
osc.type = 'sine';
|
||||
osc.frequency.value = freq;
|
||||
osc.connect(g);
|
||||
g.connect(c.destination);
|
||||
const t0 = c.currentTime + delaySec;
|
||||
g.gain.setValueAtTime(0, t0);
|
||||
g.gain.linearRampToValueAtTime(gain, t0 + 0.02);
|
||||
g.gain.exponentialRampToValueAtTime(0.001, t0 + durationSec);
|
||||
osc.start(t0);
|
||||
osc.stop(t0 + durationSec + 0.02);
|
||||
}
|
||||
|
||||
export async function playSfx(kind: Sfx): Promise<void> {
|
||||
const c = getCtx();
|
||||
if (!c) return;
|
||||
if (c.state === 'suspended') {
|
||||
try {
|
||||
await c.resume();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
switch (kind) {
|
||||
case 'join':
|
||||
// Rising two-note chirp — someone entered.
|
||||
beep(523.25, 0.12, 0, 0.16); // C5
|
||||
beep(783.99, 0.18, 0.1, 0.16); // G5
|
||||
break;
|
||||
case 'leave':
|
||||
// Falling two-note — someone left.
|
||||
beep(659.25, 0.12, 0, 0.14); // E5
|
||||
beep(329.63, 0.18, 0.1, 0.14); // E4
|
||||
break;
|
||||
case 'end':
|
||||
// Soft descending thud — call ended.
|
||||
beep(440, 0.18, 0, 0.14); // A4
|
||||
beep(293.66, 0.26, 0.14, 0.14); // D4
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function playJoinBeep(): Promise<void> {
|
||||
return playSfx('join');
|
||||
}
|
||||
export function playLeaveBeep(): Promise<void> {
|
||||
return playSfx('leave');
|
||||
}
|
||||
export function playEndBeep(): Promise<void> {
|
||||
return playSfx('end');
|
||||
}
|
||||
Reference in New Issue
Block a user