React
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
function noteDurationToMs (bpm, dur, type) {
return 60000 * 4 * dur * type / bpm
}
function scheduleNote(ac, time, dur) {
var osc = ac.createOscillator();
osc.connect( ac.destination );
osc.start(time);
osc.stop(time + dur);
}
const ac = new AudioContext();
let to, lastNote = 0;
const Metronome = () => {
const [bpm, setBpm] = React.useState(100);
const [dur, setDur] = React.useState(1);
const [type, setType] = React.useState(1);
const [run, setRun] = React.useState(false);
const handleChangeBPM = (e) => {
setBpm(e.target.value)
}
const handleChangeDur = (e) => {
setDur(e.target.value)
}
const handleChangeType = (e) => {
setType(e.target.value)
}
const step = noteDurationToMs(bpm, dur, type) / 1000;
const lookAhead = step / 2;
const timer = () => {
const diff = ac.currentTime - lastNote;
if (diff >= lookAhead) {
const nextNote = lastNote + step;
scheduleNote(ac, nextNote, 0.025)
lastNote = nextNote;
}
}
const start = () => {
setRun(true);
}
const stop = () => {
clearInterval(to);
setRun(false);
}
const toggle = () => {
run?stop():start();
}
React.useEffect(() => {
if (run) {
clearInterval(to);
to = setInterval(timer, step / 4);
}
});
return <div>
<label for="bpm">BPM:</label>
<input id="bpm" type="number" onChange={handleChangeBPM} value={bpm} />
<label for="dur">Duration:</label>
<select id="dur" onChange={handleChangeDur} value={dur}>
<option value={1}>Whole</option>
<option value={1 / 2}>Half</option>
<option value={1 / 4}>Quarter</option>
<option value={1 / 8}>Eigth </option>
<option value={1 / 16}>Sixteenth</option>
<option value={1 / 32}>Thirtysecond</option>
</select>
<label for="typ">Type:</label>
<select id="typ" onChange={handleChangeType} value={type}>
<option...