5 , MultiParamTypeClasses
9 -- | EsounD player streams.
10 module Sound.EsounD.Player
15 import Bindings.EsounD
16 import Control.Monad.IO.Class
17 import Control.Monad.Trans.Region
18 import Control.Monad.Trans.Region.OnExit
19 import Control.Monad.Unicode
21 import Data.StorableVector.Lazy as L
22 import Foreign.C.String
24 import Prelude.Unicode
25 import Sound.EsounD.Streams
26 import Sound.EsounD.Internals
28 import System.IO.SaferFileHandles.Unsafe
31 -- ^ An opaque ESD handle for playing a stream.
32 data Player fr ch (r ∷ ★ → ★)
35 -- THINKME: We really want to use RegionalFileHandle but we
36 -- can't, because safer-file-handles currently provides no ways
37 -- to wrap ordinary handles into safer handles.
39 , plCloseH ∷ !(FinalizerHandle r)
42 instance Dup (Player fr ch) where
43 dup pl = do ch' ← dup (plCloseH pl)
44 return pl { plCloseH = ch' }
46 instance Frame fr ⇒ Writable (Player fr Mono) (L.Vector fr) where
48 = liftIO $ sanitizeIOError $ L.hPut (plHandle pl) v
50 instance Frame fr ⇒ Writable (Player fr Stereo) (L.Vector fr, L.Vector fr) where
52 = liftIO $ sanitizeIOError $ L.hPut (plHandle pl) (interleave l r)
54 -- | Open an ESD handle for playing a stream.
55 openPlayer ∷ ∀fr ch s pr.
60 ⇒ Int -- ^ sample rate for the stream.
61 → HostName -- ^ host to connect to.
62 → Maybe String -- ^ name used to identify this stream to
64 → RegionT s pr (Player fr ch (RegionT s pr))
65 openPlayer rate host name
66 = do h ← liftIO openSocket
67 ch ← onExit $ sanitizeIOError $ closeSocket h
75 fmt = frameFmt ((⊥) ∷ fr) .&.
76 channelFmt ((⊥) ∷ ch) .&.
80 openSocket :: IO Handle
81 openSocket = withCString host $ \hostPtr →
82 withCStrOrNull name $ \namePtr →
88 ≫= wrapSocket "esd_play_stream() returned an error"