{-# LANGUAGE ScopedTypeVariables #-}

module Sound.Tidal.EspGrid (tidalEspGridLink,cpsEsp,espgrid) where

import Control.Concurrent.MVar
import Control.Concurrent (forkIO,threadDelay)
import Control.Monad (forever)
import Control.Exception
import Sound.OSC.FD
import Sound.Tidal.Tempo
import Sound.Tidal.Stream (Stream, sTempoMV)

parseEspTempo :: [Datum] -> Maybe (Tempo -> Tempo)
parseEspTempo :: [Datum] -> Maybe (Tempo -> Tempo)
parseEspTempo d :: [Datum]
d = do
  Integer
on :: Integer <- Datum -> Maybe Integer
forall i. Integral i => Datum -> Maybe i
datum_integral ([Datum]
d[Datum] -> Int -> Datum
forall a. [a] -> Int -> a
!!0)
  Time
bpm <- Datum -> Maybe Time
forall n. Floating n => Datum -> Maybe n
datum_floating ([Datum]
d[Datum] -> Int -> Datum
forall a. [a] -> Int -> a
!!1)
  Integer
t1 :: Integer <- Datum -> Maybe Integer
forall i. Integral i => Datum -> Maybe i
datum_integral ([Datum]
d[Datum] -> Int -> Datum
forall a. [a] -> Int -> a
!!2)
  Integer
t2 <- Datum -> Maybe Integer
forall i. Integral i => Datum -> Maybe i
datum_integral ([Datum]
d[Datum] -> Int -> Datum
forall a. [a] -> Int -> a
!!3)
  Integer
n :: Integer <- Datum -> Maybe Integer
forall i. Integral i => Datum -> Maybe i
datum_integral ([Datum]
d[Datum] -> Int -> Datum
forall a. [a] -> Int -> a
!!4)
  let nanos :: Integer
nanos = (Integer
t1Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*1000000000) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
t2
  (Tempo -> Tempo) -> Maybe (Tempo -> Tempo)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Tempo -> Tempo) -> Maybe (Tempo -> Tempo))
-> (Tempo -> Tempo) -> Maybe (Tempo -> Tempo)
forall a b. (a -> b) -> a -> b
$ \t :: Tempo
t -> Tempo
t {
    atTime :: Time
atTime = Time -> Time
forall n. Num n => n -> n
ut_to_ntpr (Time -> Time) -> Time -> Time
forall a b. (a -> b) -> a -> b
$ Integer -> Time
forall a b. (Real a, Fractional b) => a -> b
realToFrac Integer
nanos Time -> Time -> Time
forall a. Fractional a => a -> a -> a
/ 1000000000,
    atCycle :: Rational
atCycle = Integer -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n,
    cps :: Time
cps = Time
bpmTime -> Time -> Time
forall a. Fractional a => a -> a -> a
/60,
    paused :: Bool
paused = Integer
on Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0
    }

changeTempo :: MVar Tempo -> Packet -> IO ()
changeTempo :: MVar Tempo -> Packet -> IO ()
changeTempo t :: MVar Tempo
t (Packet_Message msg :: Message
msg) =
  case [Datum] -> Maybe (Tempo -> Tempo)
parseEspTempo (Message -> [Datum]
messageDatum Message
msg) of
    Just f :: Tempo -> Tempo
f -> MVar Tempo -> (Tempo -> IO Tempo) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVarMasked_ MVar Tempo
t ((Tempo -> IO Tempo) -> IO ()) -> (Tempo -> IO Tempo) -> IO ()
forall a b. (a -> b) -> a -> b
$ \t0 :: Tempo
t0 -> Tempo -> IO Tempo
forall (m :: * -> *) a. Monad m => a -> m a
return (Tempo -> Tempo
f Tempo
t0)
    Nothing -> String -> IO ()
putStrLn "Warning: Unable to parse message from EspGrid as Tempo"
changeTempo _ _ = String -> IO ()
putStrLn "Serious error: Can only process Packet_Message"

tidalEspGridLink :: MVar Tempo -> IO ()
tidalEspGridLink :: MVar Tempo -> IO ()
tidalEspGridLink _ = String -> IO ()
putStrLn "Function no longer supported, please use 'espgrid tidal' to connect to ESPgrid instead."

espgrid :: Stream -> IO ()
espgrid :: Stream -> IO ()
espgrid st :: Stream
st = do
  let t :: MVar Tempo
t = Stream -> MVar Tempo
sTempoMV Stream
st
  UDP
socket <- String -> Int -> IO UDP
openUDP "127.0.0.1" 5510
  ThreadId
_ <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    (do
      UDP -> Message -> IO ()
forall t. Transport t => t -> Message -> IO ()
sendMessage UDP
socket (Message -> IO ()) -> Message -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> [Datum] -> Message
Message "/esp/tempo/q" []
      Packet
response <- UDP -> String -> IO Packet
forall t. Transport t => t -> String -> IO Packet
waitAddress UDP
socket "/esp/tempo/r"
      MVar Tempo -> Packet -> IO ()
Sound.Tidal.EspGrid.changeTempo MVar Tempo
t Packet
response
      Int -> IO ()
threadDelay 200000)
      IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (\e :: SomeException
e -> String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ "exception caught in tidalEspGridLink: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ SomeException -> String
forall a. Show a => a -> String
show (SomeException
e :: SomeException))
  () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

cpsEsp :: Real t => t -> IO ()
cpsEsp :: t -> IO ()
cpsEsp t :: t
t = do
  UDP
socket <- String -> Int -> IO UDP
openUDP "127.0.0.1" 5510
  UDP -> Message -> IO ()
forall t. Transport t => t -> Message -> IO ()
sendMessage UDP
socket (Message -> IO ()) -> Message -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> [Datum] -> Message
Message "/esp/beat/tempo" [t -> Datum
forall n. Real n => n -> Datum
float (t
tt -> t -> t
forall a. Num a => a -> a -> a
*60)]