hsc3-server-0.1.0: Sound/SC3/Server/Monad.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Sound.SC3.Server.Monad (
-- *Server Monad
ServerT
, runServerT
, Server
, runServer
, lift
, liftIO
, rootNode
-- *Allocators
, BufferId
, BusId
, NodeId
, nodeId
, bufferId
, busId
, alloc
, allocMany
, free
, allocRange
, freeRange
-- *Synchronization
, fork
, async
, syncWith
, syncAddress
, sync
, unsafeSync
) where
import Control.Concurrent (ThreadId)
import Control.Concurrent.MVar.Strict
import Control.Monad.Reader (MonadReader, ReaderT(..), ask, asks, lift)
import Control.Monad.Trans (MonadIO, MonadTrans, liftIO)
import Data.Accessor
import Sound.SC3 (Rate(..))
import Sound.SC3.Server.Allocator (Id, IdAllocator, RangeAllocator, Range)
import Sound.SC3.Server.Connection (Connection)
import qualified Sound.SC3.Server.Connection as C
-- import Sound.SC3.Server.Process.Options (ServerOptions, numberOfInputBusChannels, numberOfOutputBusChannels)
import Sound.SC3.Server.State (BufferId, BufferIdAllocator, BusId, BusIdAllocator, NodeId, NodeIdAllocator, State)
import qualified Sound.SC3.Server.State as State
import qualified Sound.SC3.Server.State.Concurrent as IOState
import Sound.OpenSoundControl (OSC)
newtype ServerT m a = ServerT (ReaderT Connection m a)
deriving (Functor, Monad, MonadReader Connection, MonadIO, MonadTrans)
type Server = ServerT IO
type Allocator a = Accessor State a
liftConn :: MonadIO m => (Connection -> IO a) -> ServerT m a
liftConn f = ask >>= \c -> liftIO (f c)
liftState :: MonadIO m => (State -> a) -> ServerT m a
liftState f = asks C.state >>= liftIO . readMVar >>= return . f
runServerT :: ServerT m a -> Connection -> m a
runServerT (ServerT r) = runReaderT r
runServer :: Server a -> Connection -> IO a
runServer = runServerT
rootNode :: MonadIO m => ServerT m NodeId
rootNode = liftState State.rootNode
nodeId :: Allocator NodeIdAllocator
nodeId = State.nodeId
bufferId :: Allocator BufferIdAllocator
bufferId = State.bufferId
busId :: Rate -> Allocator BusIdAllocator
busId AR = State.audioBusId
busId KR = State.controlBusId
busId r = error ("No bus allocator for rate " ++ show r)
alloc :: (IdAllocator a, MonadIO m) => Allocator a -> ServerT m (Id a)
alloc a = asks C.state >>= liftIO . IOState.alloc a
allocMany :: (IdAllocator a, MonadIO m) => Allocator a -> Int -> ServerT m [Id a]
allocMany a n = asks C.state >>= liftIO . flip (IOState.allocMany a) n
free :: (IdAllocator a, MonadIO m) => Allocator a -> Id a -> ServerT m ()
free a i = asks C.state >>= liftIO . flip (IOState.free a) i
allocRange :: (RangeAllocator a, MonadIO m) => Allocator a -> Int -> ServerT m (Range (Id a))
allocRange a n = asks C.state >>= liftIO . flip (IOState.allocRange a) n
freeRange :: (RangeAllocator a, MonadIO m) => Allocator a -> Range (Id a) -> ServerT m ()
freeRange a r = asks C.state >>= liftIO . flip (IOState.freeRange a) r
fork :: (MonadIO m) => ServerT IO () -> ServerT m ThreadId
fork = liftConn . flip C.fork . runServerT
async :: (MonadIO m) => OSC -> ServerT m ()
async = liftConn . C.async
syncWith :: (MonadIO m) => OSC -> (OSC -> Maybe a) -> ServerT m a
syncWith s = liftConn . C.syncWith s
syncAddress :: (MonadIO m) => OSC -> String -> ServerT m OSC
syncAddress s = liftConn . C.syncAddress s
sync :: (MonadIO m) => OSC -> ServerT m ()
sync = liftConn . C.sync
unsafeSync :: (MonadIO m) => ServerT m ()
unsafeSync = liftConn C.unsafeSync