{-# LANGUAGE Arrows #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module FRP.Rhine.Clock.Realtime.Audio (
AudioClock (..),
AudioRate (..),
PureAudioClock (..),
PureAudioClockF,
pureAudioClockF,
)
where
import Control.Arrow
import Data.Time.Clock
import GHC.Float (double2Float)
import GHC.TypeLits (KnownNat, Nat, natVal)
import Control.Monad.IO.Class
import Data.Automaton
import Data.Automaton.Trans.Except hiding (step)
import Data.TimeDomain (diffTime)
import FRP.Rhine.Clock
import FRP.Rhine.Clock.Proxy
data AudioRate
= Hz44100
| Hz48000
| Hz96000
rateToIntegral :: (Integral a) => AudioRate -> a
rateToIntegral :: forall a. Integral a => AudioRate -> a
rateToIntegral AudioRate
Hz44100 = a
44100
rateToIntegral AudioRate
Hz48000 = a
48000
rateToIntegral AudioRate
Hz96000 = a
96000
data AudioClock (rate :: AudioRate) (bufferSize :: Nat) = AudioClock
class AudioClockRate (rate :: AudioRate) where
theRate :: AudioClock rate bufferSize -> AudioRate
theRateIntegral :: (Integral a) => AudioClock rate bufferSize -> a
theRateIntegral = AudioRate -> a
forall a. Integral a => AudioRate -> a
rateToIntegral (AudioRate -> a)
-> (AudioClock rate bufferSize -> AudioRate)
-> AudioClock rate bufferSize
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AudioClock rate bufferSize -> AudioRate
forall (bufferSize :: Nat). AudioClock rate bufferSize -> AudioRate
forall (rate :: AudioRate) (bufferSize :: Nat).
AudioClockRate rate =>
AudioClock rate bufferSize -> AudioRate
theRate
theRateNum :: (Num a) => AudioClock rate bufferSize -> a
theRateNum = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a)
-> (AudioClock rate bufferSize -> Integer)
-> AudioClock rate bufferSize
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AudioClock rate bufferSize -> Integer
forall a (bufferSize :: Nat).
Integral a =>
AudioClock rate bufferSize -> a
forall (rate :: AudioRate) a (bufferSize :: Nat).
(AudioClockRate rate, Integral a) =>
AudioClock rate bufferSize -> a
theRateIntegral
instance AudioClockRate Hz44100 where
theRate :: forall (bufferSize :: Nat).
AudioClock 'Hz44100 bufferSize -> AudioRate
theRate AudioClock 'Hz44100 bufferSize
_ = AudioRate
Hz44100
instance AudioClockRate Hz48000 where
theRate :: forall (bufferSize :: Nat).
AudioClock 'Hz48000 bufferSize -> AudioRate
theRate AudioClock 'Hz48000 bufferSize
_ = AudioRate
Hz48000
instance AudioClockRate Hz96000 where
theRate :: forall (bufferSize :: Nat).
AudioClock 'Hz96000 bufferSize -> AudioRate
theRate AudioClock 'Hz96000 bufferSize
_ = AudioRate
Hz96000
theBufferSize ::
(KnownNat bufferSize, Integral a) =>
AudioClock rate bufferSize ->
a
theBufferSize :: forall (bufferSize :: Nat) a (rate :: AudioRate).
(KnownNat bufferSize, Integral a) =>
AudioClock rate bufferSize -> a
theBufferSize = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a)
-> (AudioClock rate bufferSize -> Integer)
-> AudioClock rate bufferSize
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AudioClock rate bufferSize -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal
instance
(MonadIO m, KnownNat bufferSize, AudioClockRate rate) =>
Clock m (AudioClock rate bufferSize)
where
type Time (AudioClock rate bufferSize) = UTCTime
type Tag (AudioClock rate bufferSize) = Maybe Double
initClock :: AudioClock rate bufferSize
-> RunningClockInit
m
(Time (AudioClock rate bufferSize))
(Tag (AudioClock rate bufferSize))
initClock AudioClock rate bufferSize
audioClock = do
let
step :: DiffTime
step =
Integer -> DiffTime
picosecondsToDiffTime (Integer -> DiffTime) -> Integer -> DiffTime
forall a b. (a -> b) -> a -> b
$
Double -> Integer
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Double
10 Double -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
12 :: Integer) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ AudioClock rate bufferSize -> Double
forall a (bufferSize :: Nat).
Num a =>
AudioClock rate bufferSize -> a
forall (rate :: AudioRate) a (bufferSize :: Nat).
(AudioClockRate rate, Num a) =>
AudioClock rate bufferSize -> a
theRateNum AudioClock rate bufferSize
audioClock :: Double)
bufferSize :: Int
bufferSize = AudioClock rate bufferSize -> Int
forall (bufferSize :: Nat) a (rate :: AudioRate).
(KnownNat bufferSize, Integral a) =>
AudioClock rate bufferSize -> a
theBufferSize AudioClock rate bufferSize
audioClock
runningClock :: (MonadIO m) => UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
runningClock :: forall (m :: Type -> Type).
MonadIO m =>
UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
runningClock UTCTime
initialTime Maybe Double
maybeWasLate = AutomatonExcept () (UTCTime, Maybe Double) m Void
-> Automaton m () (UTCTime, Maybe Double)
forall (m :: Type -> Type) a b.
Monad m =>
AutomatonExcept a b m Void -> Automaton m a b
safely (AutomatonExcept () (UTCTime, Maybe Double) m Void
-> Automaton m () (UTCTime, Maybe Double))
-> AutomatonExcept () (UTCTime, Maybe Double) m Void
-> Automaton m () (UTCTime, Maybe Double)
forall a b. (a -> b) -> a -> b
$ do
UTCTime
bufferFullTime <- Automaton (ExceptT UTCTime m) () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime
forall (m :: Type -> Type) e a b.
Monad m =>
Automaton (ExceptT e m) a b -> AutomatonExcept a b m e
try (Automaton (ExceptT UTCTime m) () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime)
-> Automaton (ExceptT UTCTime m) () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime
forall a b. (a -> b) -> a -> b
$ proc () -> do
Int
n <- Automaton (ExceptT UTCTime m) () Int
forall n (m :: Type -> Type) a. (Num n, Monad m) => Automaton m a n
count -< ()
let nextTime :: UTCTime
nextTime = (DiffTime -> NominalDiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac DiffTime
step NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
* Int -> NominalDiffTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
n :: Int)) NominalDiffTime -> UTCTime -> UTCTime
`addUTCTime` UTCTime
initialTime
()
_ <- Automaton (ExceptT UTCTime m) (Bool, UTCTime) ()
forall (m :: Type -> Type) e.
Monad m =>
Automaton (ExceptT e m) (Bool, e) ()
throwOn' -< (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
bufferSize, UTCTime
nextTime)
Automaton
(ExceptT UTCTime m) (UTCTime, Maybe Double) (UTCTime, Maybe Double)
forall (a :: Type -> Type -> Type) b. Arrow a => a b b
returnA -< (UTCTime
nextTime, if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Maybe Double
maybeWasLate else Maybe Double
forall a. Maybe a
Nothing)
UTCTime
currentTime <- m UTCTime -> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime
forall (m :: Type -> Type) e a b.
Monad m =>
m e -> AutomatonExcept a b m e
once_ (m UTCTime -> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime)
-> m UTCTime
-> AutomatonExcept () (UTCTime, Maybe Double) m UTCTime
forall a b. (a -> b) -> a -> b
$ IO UTCTime -> m UTCTime
forall a. IO a -> m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
let
lateDiff :: Diff UTCTime
lateDiff = UTCTime
currentTime UTCTime -> UTCTime -> Diff UTCTime
forall time. TimeDomain time => time -> time -> Diff time
`diffTime` UTCTime
bufferFullTime
late :: Maybe Double
late = if Double
Diff UTCTime
lateDiff Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 then Double -> Maybe Double
forall a. a -> Maybe a
Just Double
Diff UTCTime
lateDiff else Maybe Double
forall a. Maybe a
Nothing
Automaton m () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m Void
forall (m :: Type -> Type) a b e.
Monad m =>
Automaton m a b -> AutomatonExcept a b m e
safe (Automaton m () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m Void)
-> Automaton m () (UTCTime, Maybe Double)
-> AutomatonExcept () (UTCTime, Maybe Double) m Void
forall a b. (a -> b) -> a -> b
$ UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
forall (m :: Type -> Type).
MonadIO m =>
UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
runningClock UTCTime
bufferFullTime Maybe Double
late
UTCTime
initialTime <- IO UTCTime -> m UTCTime
forall a. IO a -> m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
(Automaton m () (UTCTime, Maybe Double), UTCTime)
-> m (Automaton m () (UTCTime, Maybe Double), UTCTime)
forall a. a -> m a
forall (m :: Type -> Type) a. Monad m => a -> m a
return
( UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
forall (m :: Type -> Type).
MonadIO m =>
UTCTime -> Maybe Double -> Automaton m () (UTCTime, Maybe Double)
runningClock UTCTime
initialTime Maybe Double
forall a. Maybe a
Nothing
, UTCTime
initialTime
)
instance GetClockProxy (AudioClock rate bufferSize)
data PureAudioClock (rate :: AudioRate) = PureAudioClock
class PureAudioClockRate (rate :: AudioRate) where
thePureRate :: PureAudioClock rate -> AudioRate
thePureRateIntegral :: (Integral a) => PureAudioClock rate -> a
thePureRateIntegral = AudioRate -> a
forall a. Integral a => AudioRate -> a
rateToIntegral (AudioRate -> a)
-> (PureAudioClock rate -> AudioRate) -> PureAudioClock rate -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PureAudioClock rate -> AudioRate
forall (rate :: AudioRate).
PureAudioClockRate rate =>
PureAudioClock rate -> AudioRate
thePureRate
thePureRateNum :: (Num a) => PureAudioClock rate -> a
thePureRateNum = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a)
-> (PureAudioClock rate -> Integer) -> PureAudioClock rate -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PureAudioClock rate -> Integer
forall a. Integral a => PureAudioClock rate -> a
forall (rate :: AudioRate) a.
(PureAudioClockRate rate, Integral a) =>
PureAudioClock rate -> a
thePureRateIntegral
instance (Monad m, PureAudioClockRate rate) => Clock m (PureAudioClock rate) where
type Time (PureAudioClock rate) = Double
type Tag (PureAudioClock rate) = ()
initClock :: PureAudioClock rate
-> RunningClockInit
m (Time (PureAudioClock rate)) (Tag (PureAudioClock rate))
initClock PureAudioClock rate
audioClock =
(Automaton m () (Double, ()), Double)
-> m (Automaton m () (Double, ()), Double)
forall a. a -> m a
forall (m :: Type -> Type) a. Monad m => a -> m a
return
( (() -> Double) -> Automaton m () Double
forall b c. (b -> c) -> Automaton m b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr (Double -> () -> Double
forall a b. a -> b -> a
const (Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ PureAudioClock rate -> Double
forall a. Num a => PureAudioClock rate -> a
forall (rate :: AudioRate) a.
(PureAudioClockRate rate, Num a) =>
PureAudioClock rate -> a
thePureRateNum PureAudioClock rate
audioClock)) Automaton m () Double
-> Automaton m Double (Double, ()) -> Automaton m () (Double, ())
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Automaton m Double Double
forall (m :: Type -> Type) v s.
(Monad m, VectorSpace v s) =>
Automaton m v v
sumS Automaton m Double Double
-> Automaton m Double () -> Automaton m Double (Double, ())
forall b c c'.
Automaton m b c -> Automaton m b c' -> Automaton m b (c, c')
forall (a :: Type -> Type -> Type) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& (Double -> ()) -> Automaton m Double ()
forall b c. (b -> c) -> Automaton m b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr (() -> Double -> ()
forall a b. a -> b -> a
const ())
, Double
0
)
instance GetClockProxy (PureAudioClock rate)
type PureAudioClockF (rate :: AudioRate) = RescaledClock (PureAudioClock rate) Float
pureAudioClockF :: PureAudioClockF rate
pureAudioClockF :: forall (rate :: AudioRate). PureAudioClockF rate
pureAudioClockF =
RescaledClock
{ unscaledClock :: PureAudioClock rate
unscaledClock = PureAudioClock rate
forall (rate :: AudioRate). PureAudioClock rate
PureAudioClock
, rescale :: Rescaling (PureAudioClock rate) Float
rescale = Double -> Float
Rescaling (PureAudioClock rate) Float
double2Float
}