{-# LANGUAGE Arrows #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module FRP.Rhine.Clock.Realtime.Millisecond where
import Data.Maybe (fromMaybe)
import Data.Time.Clock
import Control.Concurrent (threadDelay)
import GHC.TypeLits
import Data.Vector.Sized (Vector, fromList)
import FRP.Rhine.Clock
import FRP.Rhine.Clock.FixedStep
import FRP.Rhine.Schedule
import FRP.Rhine.ResamplingBuffer
import FRP.Rhine.ResamplingBuffer.Util
import FRP.Rhine.ResamplingBuffer.Collect
newtype Millisecond (n :: Nat) = Millisecond (RescaledClockS IO (FixedStep n) UTCTime Bool)
instance Clock IO (Millisecond n) where
type Time (Millisecond n) = UTCTime
type Tag (Millisecond n) = Bool
initClock (Millisecond cl) = initClock cl
waitClock :: KnownNat n => Millisecond n
waitClock = Millisecond $ RescaledClockS FixedStep $ \_ -> do
initTime <- getCurrentTime
let
runningClock = arrM $ \(n, ()) -> do
beforeSleep <- getCurrentTime
let
diff :: Double
diff = realToFrac $ beforeSleep `diffUTCTime` initTime
remaining = fromInteger $ n * 1000 - round (diff * 1000000)
threadDelay remaining
now <- getCurrentTime
return (now, remaining > 0)
return (runningClock, initTime)
downsampleMillisecond
:: (KnownNat n, Monad m)
=> ResamplingBuffer m (Millisecond k) (Millisecond (n * k)) a (Vector n a)
downsampleMillisecond = collect >>-^ arr (fromList >>> assumeSize)
where
assumeSize = fromMaybe $ error $ unwords
[ "You are using an incorrectly implemented schedule"
, "for two Millisecond clocks."
, "Use a correct schedule like downsampleMillisecond."
]
scheduleMillisecond :: Schedule IO (Millisecond n1) (Millisecond n2)
scheduleMillisecond = Schedule initSchedule'
where
initSchedule' (Millisecond cl1) (Millisecond cl2)
= initSchedule (rescaledScheduleS scheduleFixedStep) cl1 cl2