]> gitweb @ CieloNegro.org - EsounD.git/blob - Sound/EsounD/Player.hs
save my changes from being lost
[EsounD.git] / Sound / EsounD / Player.hs
1 {-# LANGUAGE
2     FlexibleContexts
3   , FlexibleInstances
4   , KindSignatures
5   , MultiParamTypeClasses
6   , UnicodeSyntax
7   , ScopedTypeVariables
8   , TypeFamilies
9   #-}
10 -- | EsounD player streams.
11 module Sound.EsounD.Player
12     ( Player
13     , openPlayer
14     )
15     where
16 import Bindings.EsounD
17 import Control.Monad.IO.Class
18 import Control.Monad.Trans.Region
19 import Control.Monad.Trans.Region.OnExit
20 import Control.Monad.Unicode
21 import Data.Bits
22 import Data.StorableVector.Lazy as L
23 import Foreign.C.String
24 import Network
25 import Prelude.Unicode
26 import Sound.EsounD.Streams
27 import Sound.EsounD.Internals
28 import System.IO
29 import System.IO.SaferFileHandles.Unsafe
30
31
32 -- ^ An opaque ESD handle for playing a stream.
33 data Player fr ch (r ∷ ★ → ★)
34     = Player {
35         plRate   ∷ !Int
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.
39       , plHandle ∷ !Handle
40       , plCloseH ∷ !(FinalizerHandle r)
41       }
42
43 instance Dup (Player fr ch) where
44     dup pl = do ch' ← dup (plCloseH pl)
45                 return pl { plCloseH = ch' }
46
47 instance (Mux L.Vector fr ch, dvec ~ DemuxedVec L.Vector fr ch) ⇒ Writable (Player fr ch) dvec where
48       write pl dvec
49           = liftIO $ sanitizeIOError $ L.hPut (plHandle pl) (mux dvec)
50
51 -- | Open an ESD handle for playing a stream.
52 openPlayer ∷ ∀fr ch s pr.
53                ( Frame fr
54                , Channels ch
55                , MonadIO pr
56                )
57            ⇒ Int          -- ^ sample rate for the stream.
58            → HostName     -- ^ host to connect to.
59            → Maybe String -- ^ name used to identify this stream to
60                            --   ESD (if any).
61            → RegionT s pr (Player fr ch (RegionT s pr))
62 openPlayer rate host name
63     = do h  ← liftIO openSocket
64          ch ← onExit $ sanitizeIOError $ closeSocket h
65          return Player {
66                       plRate   = rate
67                     , plHandle = h
68                     , plCloseH = ch
69                     }
70     where
71       fmt :: C'esd_format_t
72       fmt = frameFmt   ((⊥) ∷ fr) .&.
73             channelFmt ((⊥) ∷ ch) .&.
74             c'ESD_STREAM            .&.
75             c'ESD_PLAY
76
77       openSocket :: IO Handle
78       openSocket = withCString    host $ \hostPtr →
79                    withCStrOrNull name $ \namePtr →
80                        c'esd_play_stream
81                        fmt
82                        (fromIntegral rate)
83                        hostPtr
84                        namePtr
85                        ≫= wrapSocket "esd_play_stream() returned an error"