aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/.client/audio/AudioController.ts
blob: 6ed618051388a8cece1db5bbb5b335979f1edf96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { SoundEffect, getFileUrl } from "./SoundEffect";

export class AudioController {
	audioElements: Record<SoundEffect, HTMLAudioElement | null>;

	constructor() {
		this.audioElements = {
			finish: null,
			winner_1: null,
			winner_2: null,
			good_1: null,
			good_2: null,
			good_3: null,
			good_4: null,
			new_score_1: null,
			new_score_2: null,
			new_score_3: null,
			compile_error_1: null,
			compile_error_2: null,
		};
	}

	loadAll(): Promise<void> {
		return new Promise((resolve) => {
			const files = Object.keys(this.audioElements).map(
				(se) => [se as SoundEffect, getFileUrl(se as SoundEffect)] as const,
			);
			const totalCount = files.length;
			let loadedCount = 0;

			files.forEach(([se, fileUrl]) => {
				const audio = new Audio(fileUrl);

				audio.addEventListener(
					"canplaythrough",
					() => {
						loadedCount++;
						this.audioElements[se] = audio;
						if (loadedCount === totalCount) {
							resolve();
						}
					},
					{ once: true },
				);

				audio.addEventListener("error", () => {
					console.log(`Failed to load audio file: ${fileUrl}`);
					// Ignore the error and continue loading other files.
				});
			});
		});
	}

	async playSoundEffect(soundEffect: SoundEffect): Promise<void> {
		const audio = this.audioElements[soundEffect];
		if (!audio) {
			return;
		}
		audio.currentTime = 0;
		await audio.play();
	}

	async playSoundEffectFinish(): Promise<void> {
		await this.playSoundEffect("finish");
	}

	async playSoundEffectWinner(winner: 1 | 2): Promise<void> {
		await this.playSoundEffect(`winner_${winner}`);
	}

	async playSoundEffectGood(): Promise<void> {
		const variant = Math.floor(Math.random() * 4) + 1;
		if (variant !== 1 && variant !== 2 && variant !== 3 && variant !== 4) {
			return; // unreachable
		}
		return await this.playSoundEffect(`good_${variant}`);
	}

	async playSoundEffectNewScore(): Promise<void> {
		const variant = Math.floor(Math.random() * 3) + 1;
		if (variant !== 1 && variant !== 2 && variant !== 3) {
			return; // unreachable
		}
		return await this.playSoundEffect(`new_score_${variant}`);
	}

	async playSoundEffectCompileError(): Promise<void> {
		const variant = Math.floor(Math.random() * 2) + 1;
		if (variant !== 1 && variant !== 2) {
			return; // unreachable
		}
		return await this.playSoundEffect(`compile_error_${variant}`);
	}
}