From d372f8ba1f6852fce5a5ac8eec4a9371828617c5 Mon Sep 17 00:00:00 2001 From: Andrew Cady Date: Sat, 12 Dec 2015 15:36:15 -0500 Subject: 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 --- midi-dump.hs | 21 ++++++++++----------- 1 file 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 where f (Metronome start interval ticked) = do now <- getAbsTime - let next = now + interval - (now `tsMod` interval) - when (next > ticked) $ do + let next = ticked + interval + prequeue = 0::Int + when (now > next - (interval * TimeSpec (fromIntegral prequeue) 0)) $ do let delay = next - now - delayNoteEv delay $ metronote 127 - -- delayNoteEv (metroDuration + delay) $ metronote 0 - modify $ \s -> s { _metronome = Just $ Metronome start interval next } + forM_ [0..prequeue] $ fromIntegral >>> \n -> alsaDelayNoteEv (delay + interval * TimeSpec n 0) $ metronote 127 + modify $ \s -> s { _metronome = Just $ Metronome start interval (next + interval * TimeSpec (fromIntegral prequeue) 0) } metronote vel = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 9) (Event.Pitch 37) (Event.Velocity vel) - -- metroDuration = TimeSpec 0 (1*10^(6::Integer)) tsMod :: forall a. Num a => TimeSpec -> TimeSpec -> a tsMod x y = fromInteger (timeSpecAsNanoSecs x `mod` timeSpecAsNanoSecs y) @@ -297,16 +296,16 @@ processCommand "M-m" = do now <- getAbsTime m <- gets _metronome times <- takeNoteTimes 8 <$> gets _replay - let deltas = drop 1 $ toDeltas times + let deltas = drop 1 . map negate . toDeltas $ times deltas' = dropOutliers deltas len = length deltas' - dropOutliers xs@(x:_) = takeWhile ((2 * x) >) xs + dropOutliers xs@(x:_) = takeWhile (< TimeSpec 2 0 * x) xs dropOutliers [] = [] if isNothing m && (len >= 3) then do let interval = sum deltas' `tsDiv` fromIntegral len - nextTick = now + interval - (now `tsMod` interval) - lastTick = nextTick - interval - modify $ \s -> s { _metronome = Just $ Metronome lastTick interval nextTick } + nextBeat = now - now `tsMod` interval + interval + lastBeat = nextBeat - interval + modify $ \s -> s { _metronome = Just $ Metronome lastBeat interval nextBeat } else modify $ \s -> s { _metronome = Nothing } processCommand "C'" = do -- cgit v1.2.3