module Sound.Tidal.Carabiner where
import Network.Socket hiding (send, sendTo, recv, recvFrom)
import Network.Socket.ByteString (send, recv)
import qualified Data.ByteString.Char8 as B8
import Control.Concurrent (forkIO, threadDelay, takeMVar, putMVar)
import qualified Sound.Tidal.Stream as S
import Sound.Tidal.Tempo
import System.Clock
import Text.Read (readMaybe)
import Control.Monad (when, forever)
import Data.Maybe (isJust, fromJust)
import qualified Sound.OSC.FD as O
port :: Int
port = 17000
carabiner :: S.Stream -> Int -> Double -> IO Socket
carabiner tidal bpc latency = do sock <- client tidal bpc latency "127.0.0.1" 17000
sendMsg sock "status\n"
return sock
client :: S.Stream -> Int -> Double -> String -> Int -> IO Socket
client tidal bpc latency host port = withSocketsDo $
do addrInfo <- getAddrInfo Nothing (Just host) (Just $ show port)
let serverAddr = head addrInfo
sock <- socket (addrFamily serverAddr) Stream defaultProtocol
connect sock (addrAddress serverAddr)
_ <- forkIO $ listener tidal bpc latency sock
return sock
listener :: S.Stream -> Int -> Double -> Socket -> IO ()
listener tidal bpc latency sock =
forever $ do rMsg <- recv sock 1024
let msg = B8.unpack rMsg
(name:_:ws) = words msg
pairs = pairs' ws
pairs' (a:b:xs) = (a,b):(pairs' xs)
pairs' _ = []
act tidal bpc latency name pairs
act :: S.Stream -> Int -> Double -> String -> [(String, String)] -> IO ()
act tidal bpc latency "status" pairs
= do let start = (lookup ":start" pairs >>= readMaybe) :: Maybe Integer
bpm = (lookup ":bpm" pairs >>= readMaybe) :: Maybe Double
beat = (lookup ":beat" pairs >>= readMaybe) :: Maybe Double
when (and [isJust start, isJust bpm, isJust beat]) $ do
nowM <- getTime Monotonic
nowO <- O.time
let m = (fromIntegral $ sec nowM) + ((fromIntegral $ nsec nowM)/1000000000)
d = nowO - m
start' = ((fromIntegral $ fromJust start) / 1000000)
startO = start' + d
cyc = toRational $ (fromJust beat) / (fromIntegral bpc)
tempo <- takeMVar (S.sTempoMV tidal)
let tempo' = tempo {atTime = startO + latency,
atCycle = 0,
cps = ((fromJust bpm) / 60) / (fromIntegral bpc)
}
putMVar (S.sTempoMV tidal) $ tempo'
act _ _ _ name _ = putStr $ "Unhandled thingie " ++ name
sendMsg :: Socket -> String -> IO ()
sendMsg sock msg = do send sock $ B8.pack msg
return ()