From 03197b1ab992540b951fcbc6f841cfcd42a757f3 Mon Sep 17 00:00:00 2001 From: Joris Date: Sat, 11 Jun 2022 16:42:33 +0200 Subject: Add kick sequencer --- src/view/sequencer/play.ts | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/view/sequencer/play.ts (limited to 'src/view/sequencer/play.ts') diff --git a/src/view/sequencer/play.ts b/src/view/sequencer/play.ts new file mode 100644 index 0000000..9ff9c81 --- /dev/null +++ b/src/view/sequencer/play.ts @@ -0,0 +1,68 @@ +import h, { classNames } from 'lib/h' +import * as time from 'lib/time' +import * as soundsLib from 'sounds' + +const MIN_BPM: number = 1 +const MAX_BPM: number = 1000 + +interface Params { + onNextStep: (sounds: soundsLib.Sounds) => void, + onStop: () => void +} + +export function view({ onNextStep, onStop }: Params) { + let bpm = 60 + let isPlaying = false + let lastBeat: undefined | number = undefined + + return h('div', {}, + h('button', + { className: 'g-PlayStop', + onclick: async (e: Event) => { + const target = e.target as HTMLButtonElement + isPlaying = !isPlaying + target.innerText = isPlaying ? '■' : '▶' + + let sounds = await soundsLib.load() + let step = (timestamp: number) => { + if (lastBeat === undefined || timestamp - lastBeat > 1000 * 60 / bpm) { + lastBeat = timestamp + onNextStep(sounds) + } + + if (isPlaying) window.requestAnimationFrame(step) + } + + if (isPlaying) { + window.requestAnimationFrame(step) + } else { + onStop() + } + } + }, + '▶' + ) + , h('label', + { className: 'g-Bpm' }, + 'BPM', + h('input', + { className: 'g-Input', + type: 'number', + value: bpm, + min: MIN_BPM, + max: MAX_BPM, + oninput: time.debounce( + (e: Event) => { + const target = e.target as HTMLInputElement + const n = parseInt(target.value) + if (n >= MIN_BPM && n <= MAX_BPM) { + bpm = n + } + }, + 1000 + ) + } + ) + ) + ) +} -- cgit v1.2.3