-- | Thread operations.
module Sound.Osc.Time.Thread where

import Control.Concurrent {- base -}
import Control.Monad {- base -}

import qualified Sound.Osc.Time as Time {- hosc -}

{- | The 'pauseThread' limit (in seconds).
  Values larger than this require a different thread delay mechanism, see 'sleepThread'.
  The value is the number of microseconds in @maxBound::Int@.
-}
pauseThreadLimit :: Fractional n => n
pauseThreadLimit :: forall n. Fractional n => n
pauseThreadLimit = Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
maxBound :: Int) n -> n -> n
forall a. Fractional a => a -> a -> a
/ n
1e6

-- | Pause current thread for the indicated duration (in seconds), see 'pauseThreadLimit'.
pauseThreadFor :: RealFrac n => n -> IO ()
pauseThreadFor :: forall n. RealFrac n => n -> IO ()
pauseThreadFor n
n = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
> n
0) (Int -> IO ()
threadDelay (n -> Int
forall b. Integral b => n -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (n
n n -> n -> n
forall a. Num a => a -> a -> a
* n
1e6)))

-- | Pause current thread until the given time, see 'pauseThreadLimit'.
pauseThreadUntilTime :: RealFrac n => n -> IO ()
pauseThreadUntilTime :: forall n. RealFrac n => n -> IO ()
pauseThreadUntilTime n
t = n -> IO ()
forall n. RealFrac n => n -> IO ()
pauseThreadFor (n -> IO ()) -> (NtpReal -> n) -> NtpReal -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n
t n -> n -> n
forall a. Num a => a -> a -> a
-) (n -> n) -> (NtpReal -> n) -> NtpReal -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NtpReal -> n
forall a b. (Real a, Fractional b) => a -> b
realToFrac (NtpReal -> IO ()) -> IO NtpReal -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO NtpReal
Time.currentTime

{- | Sleep current thread for the indicated duration (in seconds).
  Divides long sleeps into parts smaller than 'pauseThreadLimit'.
-}
sleepThreadFor :: RealFrac n => n -> IO ()
sleepThreadFor :: forall n. RealFrac n => n -> IO ()
sleepThreadFor n
n =
  if n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
>= n
forall n. Fractional n => n
pauseThreadLimit
    then
      let n' :: n
n' = n
forall n. Fractional n => n
pauseThreadLimit n -> n -> n
forall a. Num a => a -> a -> a
- n
1
      in n -> IO ()
forall n. RealFrac n => n -> IO ()
pauseThreadFor n
n' IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> n -> IO ()
forall n. RealFrac n => n -> IO ()
sleepThreadFor (n
n n -> n -> n
forall a. Num a => a -> a -> a
- n
n')
    else n -> IO ()
forall n. RealFrac n => n -> IO ()
pauseThreadFor n
n

{- | Sleep current thread until the given time.
  Divides long sleeps into parts smaller than 'pauseThreadLimit'.
-}
sleepThreadUntilTime :: RealFrac n => n -> IO ()
sleepThreadUntilTime :: forall n. RealFrac n => n -> IO ()
sleepThreadUntilTime n
t = n -> IO ()
forall n. RealFrac n => n -> IO ()
sleepThreadFor (n -> IO ()) -> (NtpReal -> n) -> NtpReal -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n
t n -> n -> n
forall a. Num a => a -> a -> a
-) (n -> n) -> (NtpReal -> n) -> NtpReal -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NtpReal -> n
forall a b. (Real a, Fractional b) => a -> b
realToFrac (NtpReal -> IO ()) -> IO NtpReal -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO NtpReal
Time.currentTime