]> gitweb @ CieloNegro.org - EsounD.git/blob - Sound/EsounD/Monitor.hs
7a06b80019820bd9c2c3c131103368268878a020
[EsounD.git] / Sound / EsounD / Monitor.hs
1 {-# LANGUAGE
2     FlexibleContexts
3   , FlexibleInstances
4   , KindSignatures
5   , MultiParamTypeClasses
6   , UnicodeSyntax
7   , ScopedTypeVariables
8   #-}
9 -- | EsounD monitoring streams.
10 module Sound.EsounD.Monitor
11     ( Monitor
12     , openMonitor
13     )
14     where
15 import Bindings.EsounD
16 import Control.Exception.Peel
17 import Control.Monad.IO.Class
18 import Control.Monad.IO.Peel
19 import Control.Monad.Trans.Region
20 import Control.Monad.Trans.Region.OnExit
21 import Control.Monad.Unicode
22 import Data.Bits
23 import Data.StorableVector      as S
24 import Data.StorableVector.Lazy as L
25 import Foreign.Storable
26 import Network
27 import Prelude.Unicode
28 import Sound.EsounD.Streams
29 import Sound.EsounD.Internals
30 import System.IO
31 import System.IO.SaferFileHandles.Unsafe
32 import Text.Printf
33
34 -- ^ An opaque ESD handle for monitoring the output from the ESD.
35 data Monitor fr ch (r ∷ ★ → ★)
36     = Monitor {
37         moRate   ∷ !Int
38       , moHandle ∷ !Handle
39       , moCloseH ∷ !(FinalizerHandle r)
40       }
41
42 instance Dup (Monitor fr ch) where
43     dup mo = do ch' ← dup (moCloseH mo)
44                 return mo { moCloseH = ch' }
45
46 instance Stream (Monitor fr ch) where
47     streamSampleRate = moRate
48
49 toLSV ∷ Storable α ⇒ S.Vector α → L.Vector α
50 toLSV v = L.fromChunks [v]
51
52 instance Frame fr ⇒ ReadableStream (Monitor fr Mono) (L.Vector fr) where
53     readFrames mo nFrames
54         = liftIO $
55           sanitizeIOError $
56           fmap toLSV $
57           S.hGet (moHandle mo) nFrames
58
59 instance Frame fr ⇒ ReadableStream (Monitor fr Stereo) (L.Vector fr, L.Vector fr) where
60     readFrames mo nFrames
61         = liftIO $
62           sanitizeIOError $
63           fmap (deinterleave ∘ toLSV) $
64           S.hGet (moHandle mo) nFrames
65
66 -- | Open an ESD handle for monitoring the output from the ESD.
67 openMonitor ∷ ∀fr ch s pr.
68                ( Frame fr
69                , Channels ch
70                , MonadPeelIO pr
71                )
72             ⇒ Int            -- ^ sample rate for the stream.
73             → Maybe HostName -- ^ host to connect to.
74             → Maybe String   -- ^ name used to identify this stream
75                               --   to ESD (if any).
76             → RegionT s pr (Monitor fr ch (RegionT s pr))
77 openMonitor rate host name
78     = block $
79       do h  ← liftIO openSocket
80          ch ← onExit $ sanitizeIOError $ closeSocket h
81          return Monitor {
82                       moRate   = rate
83                     , moHandle = h
84                     , moCloseH = ch
85                     }
86     where
87       fmt ∷ C'esd_format_t
88       fmt = frameFmt   ((⊥) ∷ fr) .|.
89             channelFmt ((⊥) ∷ ch) .|.
90             c'ESD_STREAM            .|.
91             c'ESD_MONITOR
92
93       openSocket ∷ IO Handle
94       openSocket = withCStrOrNull host $ \hostPtr →
95                    withCStrOrNull name $ \namePtr →
96                        c'esd_monitor_stream
97                        fmt
98                        (fromIntegral rate)
99                        hostPtr
100                        namePtr
101                        ≫= wrapSocket
102                                ( printf "esd_monitor_stream(%s, %s, %s, %s) returned an error"
103                                         (show fmt )
104                                         (show rate)
105                                         (show host)
106                                         (show name)
107                                )