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
|
import * as dict from 'lib/dict'
export type Sounds = Record<Sound, AudioBuffer>
export enum Sound {
Crash,
Ride,
TomHigh,
TomMedium,
TomFloor,
HitHatOpen,
HitHatClosed,
Snare,
Kick,
}
export function all(): Array<Sound> {
return dict.values(Sound)
}
export function record<T>(f: (sound: Sound) => T): Record<Sound, T> {
let res: any = {}
all().forEach(async sound => {
res[sound] = f(sound)
})
return (res as Record<Sound, T>)
}
export function toString(sound: Sound): string {
switch (sound) {
case Sound.Kick: return 'Kick'
case Sound.Snare: return 'Snare'
case Sound.HitHatOpen: return 'Hit-hat open'
case Sound.HitHatClosed: return 'Hit-hat closed'
case Sound.Ride: return 'Ride'
case Sound.Crash: return 'Crash'
case Sound.TomFloor: return 'Tom floor'
case Sound.TomMedium: return 'Tom medium'
case Sound.TomHigh: return 'Tom high'
default: throw `Sound ${sound} is unknown.`
}
}
const audioContext = new AudioContext()
let lazy: undefined | Sounds = undefined
export async function load(): Promise<Sounds> {
if (lazy !== undefined) {
return lazy
} else {
let sounds = dict.fromList(await Promise.all(dict.toList(record(fetchSound)).map(async obj => {
let value = await obj.value
return { key: obj.key, value }
}))) as Sounds
lazy = sounds
return sounds
}
}
async function fetchSound(sound: Sound): Promise<AudioBuffer> {
return await fetch(path(sound))
.then(res => res.arrayBuffer())
.then(ArrayBuffer => audioContext.decodeAudioData(ArrayBuffer))
}
function path(sound: Sound): string {
switch (sound) {
case Sound.Kick: return 'sounds/kick.opus'
case Sound.Snare: return 'sounds/snare.opus'
case Sound.HitHatOpen: return 'sounds/hit-hat-open.opus'
case Sound.HitHatClosed: return 'sounds/hit-hat-closed.opus'
case Sound.Ride: return 'sounds/ride.opus'
case Sound.Crash: return 'sounds/crash.opus'
case Sound.TomFloor: return 'sounds/tom-floor.opus'
case Sound.TomMedium: return 'sounds/tom-medium.opus'
case Sound.TomHigh: return 'sounds/tom-high.opus'
default: throw `Sound ${sound} is unknown.`
}
}
export function play(sounds: Sounds, sound: Sound): void {
const source = audioContext.createBufferSource()
source.buffer = sounds[sound]
source.connect(audioContext.destination)
source.start()
}
|