this repo has no description
at main 65 lines 1.8 kB view raw
1let audioCtx: AudioContext | null = null; 2 3function getAudioContext(): AudioContext { 4 if (!audioCtx) { 5 audioCtx = new AudioContext(); 6 } 7 if (audioCtx.state === 'suspended') { 8 audioCtx.resume(); 9 } 10 return audioCtx; 11} 12 13function playTone( 14 ctx: AudioContext, 15 frequency: number, 16 startTime: number, 17 duration: number, 18 type: OscillatorType = 'sine', 19 volume = 0.3, 20) { 21 const osc = ctx.createOscillator(); 22 const gain = ctx.createGain(); 23 24 osc.type = type; 25 osc.frequency.value = frequency; 26 gain.gain.setValueAtTime(volume, startTime); 27 gain.gain.exponentialRampToValueAtTime(0.001, startTime + duration); 28 29 osc.connect(gain); 30 gain.connect(ctx.destination); 31 osc.start(startTime); 32 osc.stop(startTime + duration); 33} 34 35export function playCorrectSound() { 36 try { 37 const ctx = getAudioContext(); 38 const now = ctx.currentTime; 39 // Cheerful ascending two-note ding 40 playTone(ctx, 523.25, now, 0.15, 'sine', 0.25); // C5 41 playTone(ctx, 659.25, now + 0.12, 0.2, 'sine', 0.25); // E5 42 } catch { /* audio unavailable */ } 43} 44 45export function playIncorrectSound() { 46 try { 47 const ctx = getAudioContext(); 48 const now = ctx.currentTime; 49 // Gentle descending two-note 50 playTone(ctx, 330, now, 0.15, 'triangle', 0.2); // E4 51 playTone(ctx, 262, now + 0.12, 0.25, 'triangle', 0.2); // C4 52 } catch { /* audio unavailable */ } 53} 54 55export function playCompletionSound() { 56 try { 57 const ctx = getAudioContext(); 58 const now = ctx.currentTime; 59 // Ascending fanfare 60 playTone(ctx, 523.25, now, 0.15, 'sine', 0.2); // C5 61 playTone(ctx, 659.25, now + 0.1, 0.15, 'sine', 0.2); // E5 62 playTone(ctx, 783.99, now + 0.2, 0.15, 'sine', 0.2); // G5 63 playTone(ctx, 1046.5, now + 0.3, 0.35, 'sine', 0.25); // C6 64 } catch { /* audio unavailable */ } 65}