61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
|
|
|
|
export class SoundPlayer {
|
|
public sounds = ['sword slash', 'knock - wood'];
|
|
private ctx = new AudioContext();
|
|
private cache = new Map<string, AudioBuffer>();
|
|
private cacheOptions = new Map<string, string[]>();
|
|
|
|
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();
|
|
}
|
|
}
|
|
|