1 module RMCA.Global.Clock where
3 import Control.Concurrent
6 import Data.ReactiveValue
11 -- The initial value is arbitrary but never appears because the switch
13 metronome :: SF Tempo (Event Beat)
14 metronome = switch (repeatedly (tempoToQNoteIvl 120) ()
17 where metronome' :: Tempo -> SF Tempo (Event Beat)
18 metronome' t = switch (repeatedly (tempoToQNoteIvl t) ()
22 -- Tempo is the number of quarter notes per minute.
23 tempoToQNoteIvl :: Tempo -> DTime
24 tempoToQNoteIvl = (15/) . fromIntegral
26 type TickingClock = (CBMVar (), ThreadId)
28 -- Make a clock that will execute any IO when it updates.
29 mkClockGeneric :: IO () -> DTime -> IO TickingClock
30 mkClockGeneric io d = do
32 tid <- forkIO $ forever $ do
37 where dInt = floor $ d * 1000
39 -- Ticking clock in the IO monad, sending callbacks every t milliseconds.
40 mkClock :: DTime -> IO TickingClock
41 mkClock = mkClockGeneric (return ())
43 -- For debugging purposes.
44 mkClockDebug :: DTime -> IO TickingClock
45 mkClockDebug = mkClockGeneric (putStrLn "Ping !")
47 clockRV :: TickingClock -> ReactiveFieldRead IO ThreadId
48 clockRV (mvar, tid) = ReactiveFieldRead (return tid)
49 (installCallbackCBMVar mvar)
51 mkClockRV :: DTime -> IO (ReactiveFieldRead IO ThreadId)
52 mkClockRV d = clockRV <$> mkClock d
54 stopClock :: TickingClock -> IO ()
55 stopClock (_,t) = killThread t