| |
| |
| |
|
|
| let ctx = null; |
| function ensure() { if (!ctx) { try { ctx = new (window.AudioContext || window.webkitAudioContext)(); } catch (e) {} } return ctx; } |
|
|
| function tone(c, freq, when, dur = 0.45, gain = 0.18, type = 'triangle') { |
| const o = c.createOscillator(), g = c.createGain(); |
| o.type = type; o.frequency.value = freq; |
| g.gain.setValueAtTime(0, when); |
| g.gain.linearRampToValueAtTime(gain, when + 0.02); |
| g.gain.exponentialRampToValueAtTime(0.001, when + dur); |
| o.connect(g).connect(c.destination); |
| o.start(when); o.stop(when + dur + 0.05); |
| } |
|
|
| export const Cheer = { |
| enabled: true, |
| prime() { ensure(); }, |
| small() { |
| if (!this.enabled) return; |
| const c = ensure(); if (!c) return; |
| const now = c.currentTime; |
| [523.25, 659.25, 783.99, 1046.5].forEach((f, i) => tone(c, f, now + i * 0.08)); |
| }, |
| master() { |
| if (!this.enabled) return; |
| const c = ensure(); if (!c) return; |
| const now = c.currentTime; |
| [523.25, 659.25, 783.99, 1046.5, 1318.51, 1567.98, 2093.0].forEach((f, i) => |
| tone(c, f, now + i * 0.07, 0.6, 0.22, i % 2 ? 'sine' : 'triangle') |
| ); |
| }, |
| levelUp() { |
| this.master(); |
| }, |
| }; |
|
|