-
Notifications
You must be signed in to change notification settings - Fork 4
/
metronome.js
67 lines (54 loc) · 1.6 KB
/
metronome.js
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
'use strict'
define(function (require) {
var metronome = {}
var beatDuration = 60 / 110
var lastBeatAt = 0
var count = 0
var nextBeatAt = 0
let beatReadouts
let time = 0
metronome.beatTime = (now) => {
return count + (now - lastBeatAt) / (nextBeatAt - lastBeatAt)
}
metronome.nextBeatAt = function () {
return nextBeatAt
}
metronome.bpm = function (bpm) {
if (bpm) {
beatDuration = 60/bpm
if (window.bpmChanged) { window.bpmChanged(60/beatDuration) }
}
return 60/beatDuration
}
metronome.beatDuration = function (d) {
if (d) { beatDuration = d; }
return beatDuration
}
metronome.advance = () => 0.1*beatDuration
metronome.lastBeat = () => metronome._lastBeat
metronome.update = function (now) {
time = now
if (now > nextBeatAt - metronome.advance()) { // Process just BEFORE the next beat to make sure that events composed ON the beat can be scheduled accurately
count += 1
metronome._lastBeat = {
now: now,
beatTime: metronome.beatTime(now),
time: nextBeatAt,
duration: beatDuration,
count: count,
}
lastBeatAt = nextBeatAt
let numBeats = Math.ceil((now-nextBeatAt+metronome.advance())/beatDuration) // Skip multiple beats; this might happen after losing focus
if (numBeats > 1) { console.log(`Skipping ${numBeats-1} beats`) }
nextBeatAt += numBeats*beatDuration
return metronome._lastBeat
}
}
metronome.timeNow = () => time
metronome.setBeatReadouts = (v) => beatReadouts = v
metronome.getBeatReadouts = () => beatReadouts
// For debugging/testing
metronome.setCount = (c) => count=c
metronome.setTime = (t) => time=t
return metronome
})