From 46f39fa93fa99eef2691d6dc905b9d083eb170cb Mon Sep 17 00:00:00 2001 From: Joris Date: Tue, 21 Jun 2022 07:59:57 +0200 Subject: Add more drum sounds --- README.md | 29 +++++++++----- public/sounds/bass.opus | Bin 1743 -> 0 bytes public/sounds/crash.opus | Bin 0 -> 20320 bytes public/sounds/hit-hat-closed.opus | Bin 3920 -> 1753 bytes public/sounds/hit-hat-open.opus | Bin 0 -> 4097 bytes public/sounds/kick.opus | Bin 0 -> 1743 bytes public/sounds/ride.opus | Bin 0 -> 16721 bytes public/sounds/snare.opus | Bin 5577 -> 2138 bytes public/sounds/tom-floor.opus | Bin 0 -> 3137 bytes public/sounds/tom-high.opus | Bin 0 -> 7658 bytes public/sounds/tom-medium.opus | Bin 0 -> 6578 bytes src/lib/dict.ts | 21 +++++++++++ src/sounds.ts | 77 +++++++++++++++++++++++++++++--------- src/view/sequencer.ts | 40 ++++++-------------- 14 files changed, 111 insertions(+), 56 deletions(-) delete mode 100644 public/sounds/bass.opus create mode 100644 public/sounds/crash.opus create mode 100644 public/sounds/hit-hat-open.opus create mode 100644 public/sounds/kick.opus create mode 100644 public/sounds/ride.opus create mode 100644 public/sounds/tom-floor.opus create mode 100644 public/sounds/tom-high.opus create mode 100644 public/sounds/tom-medium.opus create mode 100644 src/lib/dict.ts diff --git a/README.md b/README.md index b50e068..118475c 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,26 @@ Then, open your browser at `http://localhost:8000`. # Sounds -- hit-hat (closed): https://lasonotheque.org/detail-2302-charleston-fermee-7.html -- snare: https://lasonotheque.org/detail-2304-caisse-claire-1.html - bass: https://freesound.org/people/karolist/sounds/371192/ +- snare: https://lasonotheque.org/detail-2304-caisse-claire-1.html +- hit-hat: + - open: https://lasonotheque.org/detail-2295-charleston-1.html + - closed: https://lasonotheque.org/detail-2302-charleston-fermee-7.html +- cymbals: + - 40 cm: https://lasonotheque.org/detail-2311-cymbale-40cm-1.html + - ryde: https://lasonotheque.org/detail-2323-cymbale-ride-51cm-1.html +- tom: + - floor: https://lasonotheque.org/detail-2338-tom-grave-1.html + - medium: https://lasonotheque.org/detail-2333-tom-medium-1.html + - high: https://lasonotheque.org/detail-2329-tom-aigu-1.html # Todo -Multi-sound sequencer: - -- [ ] Sub divide beats ? - -Working on increasing tempo: - -- [ ] Add / Remove beat integrated into sequencer -- [ ] Augment the BPM by X after Y cycles +- Start and stop pressing space +- Rename to `drum.guyonvarch.me` +- Sub divide beats +- Add / Remove beat integrated into sequencer +- Augment the BPM by X after Y cycles +- Prefill with Rock, Jazz, Funk, …, rythms +- Control volume of individual blocks +- Load & save (json files ? URL ?) diff --git a/public/sounds/bass.opus b/public/sounds/bass.opus deleted file mode 100644 index 40a8d60..0000000 Binary files a/public/sounds/bass.opus and /dev/null differ diff --git a/public/sounds/crash.opus b/public/sounds/crash.opus new file mode 100644 index 0000000..a219130 Binary files /dev/null and b/public/sounds/crash.opus differ diff --git a/public/sounds/hit-hat-closed.opus b/public/sounds/hit-hat-closed.opus index 1513a5e..c7569b4 100644 Binary files a/public/sounds/hit-hat-closed.opus and b/public/sounds/hit-hat-closed.opus differ diff --git a/public/sounds/hit-hat-open.opus b/public/sounds/hit-hat-open.opus new file mode 100644 index 0000000..dec1c7b Binary files /dev/null and b/public/sounds/hit-hat-open.opus differ diff --git a/public/sounds/kick.opus b/public/sounds/kick.opus new file mode 100644 index 0000000..40a8d60 Binary files /dev/null and b/public/sounds/kick.opus differ diff --git a/public/sounds/ride.opus b/public/sounds/ride.opus new file mode 100644 index 0000000..7d2cae9 Binary files /dev/null and b/public/sounds/ride.opus differ diff --git a/public/sounds/snare.opus b/public/sounds/snare.opus index 1808dd3..0efe32e 100644 Binary files a/public/sounds/snare.opus and b/public/sounds/snare.opus differ diff --git a/public/sounds/tom-floor.opus b/public/sounds/tom-floor.opus new file mode 100644 index 0000000..b09c607 Binary files /dev/null and b/public/sounds/tom-floor.opus differ diff --git a/public/sounds/tom-high.opus b/public/sounds/tom-high.opus new file mode 100644 index 0000000..05d6f19 Binary files /dev/null and b/public/sounds/tom-high.opus differ diff --git a/public/sounds/tom-medium.opus b/public/sounds/tom-medium.opus new file mode 100644 index 0000000..659c531 Binary files /dev/null and b/public/sounds/tom-medium.opus differ diff --git a/src/lib/dict.ts b/src/lib/dict.ts new file mode 100644 index 0000000..43b9f02 --- /dev/null +++ b/src/lib/dict.ts @@ -0,0 +1,21 @@ +type Key = string | number | symbol + +export function fromList(xs: Array<{key: Key, value: V}>): Record { + let res: any = {} + xs.forEach(o => res[o.key] = o.value) + return res as Record +} + +export function toList(record: Record): Array<{key: Key, value: V}> { + return Object.keys(record) + .map(key => ({ key: key, value: record[key] })) +} + +type EnumObject = {[key: string]: number | string}; +type EnumObjectEnum = E extends {[key: string]: infer ET | string} ? ET : never; + +export function values(enumObject: E): EnumObjectEnum[] { + return Object.keys(enumObject) + .filter(key => Number.isNaN(Number(key))) + .map(key => enumObject[key] as EnumObjectEnum) +} diff --git a/src/sounds.ts b/src/sounds.ts index 5e4c68a..f906a70 100644 --- a/src/sounds.ts +++ b/src/sounds.ts @@ -1,13 +1,46 @@ +import * as dict from 'lib/dict' + export type Sounds = Record export enum Sound { - Bass, - Snare, + Crash, + Ride, + TomHigh, + TomMedium, + TomFloor, + HitHatOpen, HitHatClosed, + Snare, + Kick, } export function all(): Array { - return [Sound.HitHatClosed, Sound.Snare, Sound.Bass] + return dict.values(Sound) +} + +export function record(f: (sound: Sound) => T): Record { + let res: any = {} + + all().forEach(async sound => { + res[sound] = f(sound) + }) + + return (res as Record) +} + +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() @@ -17,27 +50,37 @@ export async function load(): Promise { if (lazy !== undefined) { return lazy } else { - let [bass, snare, hitHatClosed] = await Promise.all([ - fetchSound('/sounds/bass.opus'), - fetchSound('/sounds/snare.opus'), - fetchSound('/sounds/hit-hat-closed.opus') - ]) - - lazy = { - [Sound.Bass]: bass, - [Sound.Snare]: snare, - [Sound.HitHatClosed]: hitHatClosed - } - return lazy + 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(name: string): Promise { - return await fetch(name) +async function fetchSound(sound: Sound): Promise { + 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] diff --git a/src/view/sequencer.ts b/src/view/sequencer.ts index bc26e69..f7e397f 100644 --- a/src/view/sequencer.ts +++ b/src/view/sequencer.ts @@ -7,27 +7,15 @@ import * as block from 'view/sequencer/block' export function view() { let index = -1 - let columns = [{ - [Sound.Bass]: true, - [Sound.Snare]: false, - [Sound.HitHatClosed]: false, - }] + let columns = [soundsLib.record(sound => sound == Sound.Kick)] let blocksNode = h('div', { className: 'g-Sequencer__Blocks' }, - block.column([ - { - checked: false, - onCheck: checked => columns[0][Sound.HitHatClosed] = checked - }, - { - checked: false, - onCheck: checked => columns[0][Sound.Snare] = checked - }, - { - checked: true, - onCheck: checked => columns[0][Sound.Bass] = checked - } - ]) + block.column( + soundsLib.all().map(sound => ({ + checked: sound == Sound.Kick, + onCheck: checked => columns[0][sound] = checked + })) + ) ) let onNextStep = (sounds: soundsLib.Sounds) => { @@ -69,11 +57,7 @@ export function view() { columns.pop() }, onAdd: index => { - columns.push({ - [Sound.Bass]: false, - [Sound.Snare]: false, - [Sound.HitHatClosed]: false, - }) + columns.push(soundsLib.record(sound => false)) blocksNode.appendChild(block.column( soundsLib.all().map(sound => ({ checked: false, @@ -86,9 +70,7 @@ export function view() { { className: 'g-Sequencer__Grid' }, h('ol', { className: 'g-Sequencer__Column' }, - soundItem('Hit-hat (closed)', Sound.HitHatClosed), - soundItem('Snare', Sound.Snare), - soundItem('Bass', Sound.Bass) + ...soundsLib.all().map(soundItem) ), blocksNode ) @@ -97,13 +79,13 @@ export function view() { return sequencer } -function soundItem(name: string, sound: Sound): Element { +function soundItem(sound: Sound): Element { return h('li', { onclick: async () => { let sounds = await soundsLib.load() soundsLib.play(sounds, sound) } }, - name + soundsLib.toString(sound) ) } -- cgit v1.2.3