1 -- | Type-safe bindings to EsounD with monadic regions.
14 import Bindings.EsounD
15 import Control.Monad.IO.Class
16 import Control.Monad.Trans.Region as R
17 import Control.Monad.Trans.Region.OnExit
18 import Control.Monad.Unicode
21 import Foreign.C.String
22 import Foreign.C.Types
25 import Prelude.Unicode
27 import System.IO.SaferFileHandles.Unsafe
28 import System.Posix.IO
29 import System.Posix.Types
32 frameFmt ∷ fr → C'esd_format_t
34 instance Frame Int8 where
35 frameFmt _ = c'ESD_BITS8
37 instance Frame Int16 where
38 frameFmt _ = c'ESD_BITS16
40 class Channels ch where
41 channelFmt ∷ ch → C'esd_format_t
44 instance Channels Mono where
45 channelFmt _ = c'ESD_MONO
48 instance Channels Stereo where
49 channelFmt _ = c'ESD_STEREO
52 -- ^ An ESD handle for playing a stream.
53 data Player fr ch (r ∷ * → *)
56 -- THINKME: We really want to use RegionalFileHandle but we
57 -- can't, because safer-file-handles currently provides no ways
58 -- to wrap ordinary handles.
60 , plCloseH ∷ !(CloseHandle r)
63 instance Dup (Player fr ch) where
64 dup pl = do ch' ← R.dup (plCloseH pl)
65 return pl { plCloseH = ch' }
67 -- | Open an ESD handle for playing a stream.
68 openPlayer ∷ ∀fr ch s pr.
73 ⇒ Int -- ^ sample rate for the stream.
74 → HostName -- ^ host to connect to.
75 → Maybe String -- ^ name used to identify this stream to
77 → RegionT s pr (Player fr ch (RegionT s pr))
78 openPlayer rate host name
79 = do h ← liftIO openSocket
80 ch ← onExit $ sanitizeIOError $ closeSocket h
88 fmt = frameFmt ((⊥) ∷ fr) .&.
89 channelFmt ((⊥) ∷ ch) .&.
93 openSocket :: IO Handle
94 openSocket = withCString host $ \hostPtr →
95 withCStrOrNull name $ \namePtr →
101 ≫= wrapSocket "esd_play_stream() returned an error"
103 wrapSocket :: String -> CInt → IO Handle
104 wrapSocket e (-1) = fail e
105 wrapSocket _ fd = fdToHandle (Fd fd)
107 closeSocket :: Handle → IO ()
108 closeSocket h = do (Fd fd) ← handleToFd h
109 _ ← c'esd_close (fromIntegral fd)
112 withCStrOrNull :: Maybe String → (CString → IO a) → IO a
113 withCStrOrNull Nothing f = f nullPtr
114 withCStrOrNull (Just s) f = withCString s f