5 , MultiParamTypeClasses
9 -- | EsounD player streams.
10 module Sound.EsounD.Player
15 import Bindings.EsounD
16 import Control.Exception.Control
17 import Control.Monad.IO.Class
18 import Control.Monad.IO.Control
19 import Control.Monad.Trans.Region
20 import Control.Monad.Trans.Region.OnExit
21 import Control.Monad.Unicode
23 import Data.StorableVector.Lazy as L
25 import Prelude.Unicode
26 import Sound.EsounD.Streams
27 import Sound.EsounD.Internals
29 import System.IO.SaferFileHandles.Unsafe
32 -- ^ An opaque ESD handle for playing a stream.
33 data Player fr ch (r ∷ ★ → ★)
36 -- THINKME: We really want to use RegionalFileHandle but we
37 -- can't, because safer-file-handles currently provides no ways
38 -- to wrap ordinary handles into safer handles.
40 , plCloseH ∷ !(FinalizerHandle r)
43 instance Dup (Player fr ch) where
44 dup pl = do ch' ← dup (plCloseH pl)
45 return pl { plCloseH = ch' }
47 instance Stream (Player fr ch) where
48 streamSampleRate = plRate
50 instance Frame fr ⇒ WritableStream (Player fr Mono) (L.Vector fr) where
54 do L.hPut (plHandle pl) v
57 instance Frame fr ⇒ WritableStream (Player fr Stereo) (L.Vector fr, L.Vector fr) where
61 do L.hPut (plHandle pl) (interleave l r)
64 -- | Open an ESD handle for playing a stream.
65 openPlayer ∷ ∀fr ch s pr.
70 ⇒ Int -- ^ sample rate for the stream.
71 → Maybe HostName -- ^ host to connect to.
72 → Maybe String -- ^ name used to identify this stream to
74 → RegionT s pr (Player fr ch (RegionT s pr))
75 openPlayer rate host name
77 do h ← liftIO openSocket
78 ch ← onExit $ sanitizeIOError $ closeSocket h
86 fmt = frameFmt ((⊥) ∷ fr) .|.
87 channelFmt ((⊥) ∷ ch) .|.
91 openSocket :: IO Handle
92 openSocket = withCStrOrNull host $ \hostPtr →
93 withCStrOrNull name $ \namePtr →
100 ( printf "esd_play_stream(%s, %s, %s, %s) returned an error"