Files
2026-01-27 02:17:57 +03:00

141 lines
3.5 KiB
JavaScript

/**
* Star Wars Hearthstone - Web Audio sound effects
*/
(function (global) {
'use strict';
let ctx = null;
function init() {
if (ctx) {
if (ctx.state === 'suspended') ctx.resume().catch(function () {});
return ctx;
}
try {
ctx = new (global.AudioContext || global.webkitAudioContext)();
} catch (e) {
return null;
}
return ctx;
}
function beep(freq, duration, type, vol) {
const c = init();
if (!c) return;
const osc = c.createOscillator();
const gain = c.createGain();
osc.connect(gain);
gain.connect(c.destination);
osc.frequency.value = freq;
osc.type = type || 'sine';
gain.gain.setValueAtTime(vol ?? 0.15, c.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, c.currentTime + duration);
osc.start(c.currentTime);
osc.stop(c.currentTime + duration);
}
function playCard() {
const c = init();
if (!c) return;
const osc = c.createOscillator();
const gain = c.createGain();
osc.connect(gain);
gain.connect(c.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(523, c.currentTime);
osc.frequency.exponentialRampToValueAtTime(784, c.currentTime + 0.08);
gain.gain.setValueAtTime(0.12, c.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, c.currentTime + 0.15);
osc.start(c.currentTime);
osc.stop(c.currentTime + 0.15);
}
function attack() {
const c = init();
if (!c) return;
const osc = c.createOscillator();
const gain = c.createGain();
osc.connect(gain);
gain.connect(c.destination);
osc.type = 'square';
osc.frequency.value = 180;
gain.gain.setValueAtTime(0.08, c.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, c.currentTime + 0.12);
osc.start(c.currentTime);
osc.stop(c.currentTime + 0.12);
}
function endTurn() {
beep(392, 0.06, 'sine', 0.1);
setTimeout(() => beep(523, 0.08, 'sine', 0.08), 80);
}
function victory() {
const notes = [523, 659, 784, 1047];
notes.forEach((f, i) => {
setTimeout(() => beep(f, 0.25, 'sine', 0.12), i * 120);
});
}
function defeat() {
const notes = [392, 349, 294];
notes.forEach((f, i) => {
setTimeout(() => beep(f, 0.2, 'sine', 0.1), i * 150);
});
}
function drawCard() {
beep(440, 0.06, 'sine', 0.08);
}
function hoverCard() {
beep(600, 0.04, 'sine', 0.05);
}
function timerWarning() {
const c = init();
if (!c) return;
const osc = c.createOscillator();
const gain = c.createGain();
osc.connect(gain);
gain.connect(c.destination);
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(220, c.currentTime);
osc.frequency.exponentialRampToValueAtTime(440, c.currentTime + 0.15);
gain.gain.setValueAtTime(0.08, c.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, c.currentTime + 0.2);
osc.start(c.currentTime);
osc.stop(c.currentTime + 0.2);
}
function timerEnd() {
const notes = [262, 330, 392];
notes.forEach((f, i) => {
setTimeout(() => beep(f, 0.1, 'square', 0.08), i * 80);
});
}
function forge() {
const c = init();
if (!c) return;
const notes = [392, 523, 659, 784];
notes.forEach((f, i) => {
setTimeout(() => beep(f, 0.2, 'sine', 0.12), i * 90);
});
}
global.Sounds = {
init,
playCard,
attack,
endTurn,
victory,
defeat,
drawCard,
hoverCard,
timerWarning,
timerEnd,
forge,
};
})(typeof window !== 'undefined' ? window : globalThis);