diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-12 15:36:15 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-12 15:36:15 -0500 |
commit | d372f8ba1f6852fce5a5ac8eec4a9371828617c5 (patch) | |
tree | 4e61c3a26f72c5e2661d2f59b90f85489fe85dcb | |
parent | 0f499626ab45d730fcdda5a6bc834a7127cb525a (diff) |
Metronome bugfixes.
Turns out:
(1) I was using a negative interval because I generated the deltas
without reversing the list.
(2) Insanely, 2 * TimeSpec 1 0 == TimeSpec 0 2
The new metronome code has the capacity to prequeue beats, by changing
the constant "prequeue" (currently 0), but there is no capacity to clear
the queue of upcoming events, so this is currently disabled.
It also doesn't seem to be necessary. Or rather, it doesn't seem to
help: either way, sometimes the program cannot keep up with real time.
:(
k
-rw-r--r-- | midi-dump.hs | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/midi-dump.hs b/midi-dump.hs index 0adef56..369ee9c 100644 --- a/midi-dump.hs +++ b/midi-dump.hs | |||
@@ -218,15 +218,14 @@ metronome = gets _metronome >>= mapM_ f | |||
218 | where | 218 | where |
219 | f (Metronome start interval ticked) = do | 219 | f (Metronome start interval ticked) = do |
220 | now <- getAbsTime | 220 | now <- getAbsTime |
221 | let next = now + interval - (now `tsMod` interval) | 221 | let next = ticked + interval |
222 | when (next > ticked) $ do | 222 | prequeue = 0::Int |
223 | when (now > next - (interval * TimeSpec (fromIntegral prequeue) 0)) $ do | ||
223 | let delay = next - now | 224 | let delay = next - now |
224 | delayNoteEv delay $ metronote 127 | 225 | forM_ [0..prequeue] $ fromIntegral >>> \n -> alsaDelayNoteEv (delay + interval * TimeSpec n 0) $ metronote 127 |
225 | -- delayNoteEv (metroDuration + delay) $ metronote 0 | 226 | modify $ \s -> s { _metronome = Just $ Metronome start interval (next + interval * TimeSpec (fromIntegral prequeue) 0) } |
226 | modify $ \s -> s { _metronome = Just $ Metronome start interval next } | ||
227 | 227 | ||
228 | metronote vel = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 9) (Event.Pitch 37) (Event.Velocity vel) | 228 | metronote vel = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 9) (Event.Pitch 37) (Event.Velocity vel) |
229 | -- metroDuration = TimeSpec 0 (1*10^(6::Integer)) | ||
230 | 229 | ||
231 | tsMod :: forall a. Num a => TimeSpec -> TimeSpec -> a | 230 | tsMod :: forall a. Num a => TimeSpec -> TimeSpec -> a |
232 | tsMod x y = fromInteger (timeSpecAsNanoSecs x `mod` timeSpecAsNanoSecs y) | 231 | tsMod x y = fromInteger (timeSpecAsNanoSecs x `mod` timeSpecAsNanoSecs y) |
@@ -297,16 +296,16 @@ processCommand "M-m" = do | |||
297 | now <- getAbsTime | 296 | now <- getAbsTime |
298 | m <- gets _metronome | 297 | m <- gets _metronome |
299 | times <- takeNoteTimes 8 <$> gets _replay | 298 | times <- takeNoteTimes 8 <$> gets _replay |
300 | let deltas = drop 1 $ toDeltas times | 299 | let deltas = drop 1 . map negate . toDeltas $ times |
301 | deltas' = dropOutliers deltas | 300 | deltas' = dropOutliers deltas |
302 | len = length deltas' | 301 | len = length deltas' |
303 | dropOutliers xs@(x:_) = takeWhile ((2 * x) >) xs | 302 | dropOutliers xs@(x:_) = takeWhile (< TimeSpec 2 0 * x) xs |
304 | dropOutliers [] = [] | 303 | dropOutliers [] = [] |
305 | if isNothing m && (len >= 3) then do | 304 | if isNothing m && (len >= 3) then do |
306 | let interval = sum deltas' `tsDiv` fromIntegral len | 305 | let interval = sum deltas' `tsDiv` fromIntegral len |
307 | nextTick = now + interval - (now `tsMod` interval) | 306 | nextBeat = now - now `tsMod` interval + interval |
308 | lastTick = nextTick - interval | 307 | lastBeat = nextBeat - interval |
309 | modify $ \s -> s { _metronome = Just $ Metronome lastTick interval nextTick } | 308 | modify $ \s -> s { _metronome = Just $ Metronome lastBeat interval nextBeat } |
310 | else | 309 | else |
311 | modify $ \s -> s { _metronome = Nothing } | 310 | modify $ \s -> s { _metronome = Nothing } |
312 | processCommand "C'" = do | 311 | processCommand "C'" = do |