packages feed

live-sequencer-0.0.1: src/Time.hs

{-# LANGUAGE EmptyDataDecls #-}
module Time where

import Control.Concurrent ( threadDelay )
import qualified Data.Monoid as Mn


newtype Time factor a = Time a
    deriving (Eq, Ord, Show)

instance Functor (Time factor) where
    fmap f (Time a) = Time (f a)


instance (Num a) => Mn.Monoid (Time factor a) where
    mempty = Time 0
    mappend (Time x) (Time y) = Time (x+y)

sub :: Num a => Time factor a -> Time factor a -> Time factor a
sub (Time x) (Time y) = Time (x-y)


data One
data EM3 a

type Milli = EM3 One
type Micro = EM3 Milli
type Nano  = EM3 Micro

type Seconds      a = Time One   a
type Milliseconds a = Time Milli a  -- unit in Wait constructor
type Microseconds a = Time Micro a  -- unit of threadDelay
type Nanoseconds  a = Time Nano  a  -- unit of ALSA realtime


up :: Num a => Time factor a -> Time (EM3 factor) a
up (Time a) = Time (1000*a)


class Factor factor where
    seconds :: Num a => a -> Time factor a

instance Factor One where
    seconds = Time

instance Factor factor => Factor (EM3 factor) where
    seconds = up . seconds


mul3 :: Time factor a -> Time (EM3 factor) a
mul3 (Time t) = Time t

milliseconds ::
    (Factor factor, Num a) =>
    a -> Time (EM3 factor) a
milliseconds =
    mul3 . seconds

nanoseconds ::
    (Factor factor, Num a) =>
    a -> Time (EM3 (EM3 (EM3 factor))) a
nanoseconds =
    mul3 . mul3 . mul3 . seconds


pause :: Time Micro Int -> IO ()
pause (Time t) = threadDelay t



-- | we check by the types whether we can format the time value or not
class Format factor where
    formatUnit :: Time factor a -> String

instance Format One where
    formatUnit = const "s"


class Format1 factor where
    formatUnit1 :: Time (EM3 factor) a -> String

instance Format1 One where
    formatUnit1 = const "ms"

instance Format1 factor => Format (EM3 factor) where
    formatUnit = formatUnit1


class Format2 factor where
    formatUnit2 :: Time (EM3 (EM3 factor)) a -> String

instance Format2 One where
    formatUnit2 = const "us"

instance Format2 factor => Format1 (EM3 factor) where
    formatUnit1 = formatUnit2


class Format3 factor where
    formatUnit3 :: Time (EM3 (EM3 (EM3 factor))) a -> String

instance Format3 One where
    formatUnit3 = const "ns"

instance Format3 factor => Format2 (EM3 factor) where
    formatUnit2 = formatUnit3


format :: (Format factor, Show a) => Time factor a -> String
format time@(Time t) = show t ++ formatUnit time