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