4 , MultiParamTypeClasses
8 -- | EsounD player streams.
9 module Sound.EsounD.Player
14 import Bindings.EsounD
15 import Control.Monad.IO.Class
16 import Control.Monad.Trans.Region
17 import Control.Monad.Trans.Region.OnExit
18 import Control.Monad.Unicode
20 import Data.StorableVector.Lazy as Lazy
21 import Foreign.C.String
23 import Prelude.Unicode
24 import Sound.EsounD.Streams
25 import Sound.EsounD.Internals
27 import System.IO.SaferFileHandles.Unsafe
30 -- ^ An opaque ESD handle for playing a stream.
31 data Player fr ch (r ∷ ★ → ★)
34 -- THINKME: We really want to use RegionalFileHandle but we
35 -- can't, because safer-file-handles currently provides no ways
36 -- to wrap ordinary handles into safer handles.
38 , plCloseH ∷ !(FinalizerHandle r)
41 instance Dup (Player fr ch) where
42 dup pl = do ch' ← dup (plCloseH pl)
43 return pl { plCloseH = ch' }
45 instance Frame fr ⇒ Writable (Player fr Mono) (Lazy.Vector fr) where
47 = liftIO $ sanitizeIOError $ Lazy.hPut (plHandle pl) v
49 -- | Open an ESD handle for playing a stream.
50 openPlayer ∷ ∀fr ch s pr.
55 ⇒ Int -- ^ sample rate for the stream.
56 → HostName -- ^ host to connect to.
57 → Maybe String -- ^ name used to identify this stream to
59 → RegionT s pr (Player fr ch (RegionT s pr))
60 openPlayer rate host name
61 = do h ← liftIO openSocket
62 ch ← onExit $ sanitizeIOError $ closeSocket h
70 fmt = frameFmt ((⊥) ∷ fr) .&.
71 channelFmt ((⊥) ∷ ch) .&.
75 openSocket :: IO Handle
76 openSocket = withCString host $ \hostPtr →
77 withCStrOrNull name $ \namePtr →
83 ≫= wrapSocket "esd_play_stream() returned an error"