summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-12 15:36:15 -0500
committerAndrew Cady <d@jerkface.net>2015-12-12 15:36:15 -0500
commitd372f8ba1f6852fce5a5ac8eec4a9371828617c5 (patch)
tree4e61c3a26f72c5e2661d2f59b90f85489fe85dcb
parent0f499626ab45d730fcdda5a6bc834a7127cb525a (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.hs21
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
231tsMod :: forall a. Num a => TimeSpec -> TimeSpec -> a 230tsMod :: forall a. Num a => TimeSpec -> TimeSpec -> a
232tsMod x y = fromInteger (timeSpecAsNanoSecs x `mod` timeSpecAsNanoSecs y) 231tsMod 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 }
312processCommand "C'" = do 311processCommand "C'" = do