{-# Language ScopedTypeVariables #-}
module Csound.Typed.Control.Osc(
OscRef, OscHost, OscPort, OscAddress, OscType,
initOsc, listenOsc, sendOsc,
OscVal, listenOscVal
) where
import Data.Boolean (ifB, (==*))
import Csound.Dynamic(Rate(..))
import Csound.Typed.Types
import Csound.Typed.GlobalState hiding (oscInit, oscListen, oscSend)
import qualified Csound.Typed.GlobalState as C(oscInit, oscListen, oscSend)
import Csound.Typed.Control.Ref
newtype OscRef = OscRef { unOscRef :: D }
type OscPort = Int
type OscAddress = String
type OscType = String
type OscHost = String
initOsc :: OscPort -> OscRef
initOsc port = OscRef $ fromGE $ getOscPortHandle port
listenOsc :: forall a . Tuple a => OscRef -> OscAddress -> OscType -> Evt a
listenOsc oscRef oscAddr oscType = Evt $ \bam -> do
resRef <- initOscRef oscType
cond <- listen resRef
when1 cond $ bam =<< readRef resRef
where
listen :: Tuple a => Ref a -> SE BoolSig
listen ref = fmap (==* 1) $ csdOscListen ref oscRef oscAddr oscType
csdOscListen :: Tuple a => Ref a -> OscRef -> OscAddress -> OscType -> SE Sig
csdOscListen (Ref refVars) oscHandle addr ty =
fmap fromGE $ fromDep $ hideGEinDep $ do
expOscHandle <- toGE $ unOscRef oscHandle
expAddr <- toGE $ text addr
expOscType <- toGE $ text ty
return $ C.oscListen expOscHandle expAddr expOscType refVars
initOscRef :: OscType -> SE (Ref a)
initOscRef typeStr = fmap Ref $ newLocalVars (fmap getOscRate typeStr) (fromTuple $ (defTuple :: a))
getOscRate :: Char -> Rate
getOscRate x = case x of
'a' -> Ar
's' -> Sr
'i' -> Kr
'f' -> Kr
_ -> Kr
sendOsc :: forall a . Tuple a => OscHost -> OscPort -> OscAddress -> OscType -> Evt a -> SE ()
sendOsc host port addr ty evts = do
flagRef <- newRef (0 :: Sig)
valRef <- newRef defTuple
runEvt evts $ \a -> do
flag <- readRef flagRef
writeRef flagRef (flag + 1)
writeRef valRef a
flag <- readRef flagRef
value <- readRef valRef
send flag value
where
send :: Tuple a => Sig -> a -> SE ()
send trig as = SE $ hideGEinDep $ do
args <- fromTuple as
expTrig <- toGE trig
expHost <- toGE $ text $ host
expPort <- toGE $ int $ port
expAddr <- toGE $ text $ addr
expTy <- toGE $ text $ ty
return $ C.oscSend $ expTrig : expHost : expPort : expAddr : expTy : args
class Tuple a => OscVal a where
getOscTypes :: a -> String
getOscRef :: a -> SE (Ref a)
instance OscVal Sig where
getOscTypes = const "f"
getOscRef = newCtrlRef
instance OscVal Str where
getOscTypes = const "s"
getOscRef = newRef
instance (OscVal a, OscVal b) => OscVal (a, b) where
getOscTypes (a, b) = getOscTypes a ++ getOscTypes b
getOscRef (a, b) = do
refA <- getOscRef a
refB <- getOscRef b
return $ concatRef refA refB
instance (OscVal a, OscVal b, OscVal c) => OscVal (a, b, c) where
getOscTypes (a, b, c) = getOscTypes a ++ getOscTypes b ++ getOscTypes c
getOscRef (a, b, c) = do
refA <- getOscRef a
refB <- getOscRef b
refC <- getOscRef c
return $ concatRef3 refA refB refC
instance (OscVal a, OscVal b, OscVal c, OscVal d) => OscVal (a, b, c, d) where
getOscTypes (a, b, c, d) = getOscTypes a ++ getOscTypes b ++ getOscTypes c ++ getOscTypes d
getOscRef (a, b, c, d) = do
refA <- getOscRef a
refB <- getOscRef b
refC <- getOscRef c
refD <- getOscRef d
return $ concatRef4 refA refB refC refD
instance (OscVal a, OscVal b, OscVal c, OscVal d, OscVal e) => OscVal (a, b, c, d, e) where
getOscTypes (a, b, c, d, e) = getOscTypes a ++ getOscTypes b ++ getOscTypes c ++ getOscTypes d ++ getOscTypes e
getOscRef (a, b, c, d, e) = do
refA <- getOscRef a
refB <- getOscRef b
refC <- getOscRef c
refD <- getOscRef d
refE <- getOscRef e
return $ concatRef5 refA refB refC refD refE
listenOscVal :: (Tuple a, OscVal a) => OscRef -> String -> a -> SE a
listenOscVal port path initVal = do
ref <- getOscRef initVal
runEvt (listenOsc port path (getOscTypes initVal)) $ \a -> writeRef ref a
readRef ref