UNPKG

asciitorium

Version:
75 lines (74 loc) 2.57 kB
import { isWebEnvironment } from './environment.js'; export class SoundManager { static setEnabled(enabled) { this.enabled = enabled; } static isEnabled() { return this.enabled; } static async playSound(soundPath, loop = false) { // Only play sounds in web environment if (!isWebEnvironment()) { return; } if (!this.enabled) { return; } try { // Check cache first let audio = this.audioCache.get(soundPath); if (!audio) { // Create new audio element audio = new Audio(`art/sounds/${soundPath}`); this.audioCache.set(soundPath, audio); } // Clone the audio element to allow overlapping sounds const audioClone = audio.cloneNode(); audioClone.loop = loop; // Track playing audio for fade operations if (loop) { this.playingAudio.set(soundPath, audioClone); // Clean up when audio ends (if it's stopped manually) audioClone.addEventListener('ended', () => { this.playingAudio.delete(soundPath); }); } await audioClone.play(); } catch (error) { console.warn(`Failed to play sound "${soundPath}":`, error); } } static fadeToStop(soundPath, durationMs = 1000) { // Only works in web environment if (!isWebEnvironment()) { return; } const audio = this.playingAudio.get(soundPath); if (!audio) { return; } // Store initial volume const initialVolume = audio.volume; const startTime = Date.now(); const fadeInterval = setInterval(() => { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / durationMs, 1); // Calculate new volume (linear fade from initial to 0) audio.volume = initialVolume * (1 - progress); // When fade is complete, stop audio and clean up if (progress >= 1) { clearInterval(fadeInterval); audio.pause(); audio.currentTime = 0; this.playingAudio.delete(soundPath); } }, 16); // ~60fps } static clearCache() { this.audioCache.clear(); } } SoundManager.audioCache = new Map(); SoundManager.playingAudio = new Map(); SoundManager.enabled = true;