export class SoundPlayer { public sounds = ['sword slash', 'knock - wood']; private ctx = new AudioContext(); private cache = new Map(); private cacheOptions = new Map(); constructor() { } async play(sound: string) { if (this.sounds.includes(sound)) { const options = await this.fetchSoundOptions(sound); const randomOption = options[Math.floor(Math.random() * options.length)]; const soundBuffer = await this.fetchSound(sound, randomOption); this.playBuffer(soundBuffer); console.log(`Playing sound: ${sound}`); } else { console.log(`Sound not found: ${sound}`); } } async fetchSoundOptions(sound: string) { const url = `/soundfx/${sound}/`; const dir = fetch(url) .then((res) => res.json()) .then((dir) => { this.cacheOptions.set(url, dir.map(({name}: any) => name) as string[]); }); if (!this.cacheOptions.has(url)) { await dir; } return this.cacheOptions.get(url)!; } async fetchSound(sound: string, options: string) { const url = `/soundfx/${sound}/${options}`; if (this.cache.has(url)) { return this.cache.get(url)!; } console.log(`Fetching sound: ${sound}/${options}`); const arrayBuffer = await (await fetch(url)).arrayBuffer(); const audioBuffer = await this.ctx.decodeAudioData(arrayBuffer); this.cache.set(url, audioBuffer); return audioBuffer; } async playBuffer(buffer: AudioBuffer) { const source = this.ctx.createBufferSource(); const panner = this.ctx.createStereoPanner(); // panner.pan.value = Math.random() > 0.5 ? 1 : -1; source.buffer = buffer; source.connect(panner); panner.connect(this.ctx.destination); source.start(); } }