feat: implement global audio effects and presence grace period

This commit is contained in:
Jannis Braun
2026-02-19 23:46:46 +01:00
parent 6784dbcbaa
commit 9a79ddf7eb
4 changed files with 270 additions and 33 deletions
+40
View File
@@ -12,6 +12,7 @@ export class AudioManager {
private isInitialized = false;
private listeners: Set<() => void> = new Set();
private soundBuffers: Map<string, AudioBuffer> = new Map();
private constructor() {}
@@ -73,6 +74,45 @@ export class AudioManager {
}
}
async loadSound(name: string): Promise<AudioBuffer | null> {
if (this.soundBuffers.has(name)) {
return this.soundBuffers.get(name)!;
}
if (!this.ctx) this.initContext();
try {
const response = await fetch(`/sounds/${name}.mp3`);
if (!response.ok) throw new Error(`Failed to load sound: ${name}`);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await this.ctx!.decodeAudioData(arrayBuffer);
this.soundBuffers.set(name, audioBuffer);
return audioBuffer;
} catch (err) {
console.error(`[AudioManager] Error loading sound ${name}:`, err);
return null;
}
}
async playSound(name: string, options: { loop?: boolean; volume?: number } = {}): Promise<AudioBufferSourceNode | null> {
await this.resumeContext();
const buffer = await this.loadSound(name);
if (!buffer || !this.ctx) return null;
const source = this.ctx.createBufferSource();
source.buffer = buffer;
source.loop = options.loop || false;
const gainNode = this.ctx.createGain();
gainNode.gain.value = options.volume ?? 0.5;
source.connect(gainNode);
gainNode.connect(this.ctx.destination);
source.start(0);
return source;
}
async setInputDevice(deviceId: string) {
if (!this.isInitialized) this.initContext();