]> gitweb @ CieloNegro.org - EsounD.git/commitdiff
Monitor
authorPHO <pho@cielonegro.org>
Sun, 2 Jan 2011 00:03:44 +0000 (09:03 +0900)
committerPHO <pho@cielonegro.org>
Sun, 2 Jan 2011 00:03:44 +0000 (09:03 +0900)
EsounD.cabal
Sound/EsounD.hs
Sound/EsounD/Internals.hs
Sound/EsounD/Monitor.hs [new file with mode: 0644]
Sound/EsounD/Player.hs
Sound/EsounD/Streams.hs
examples/EsdPlayerExample.hs

index 783ef4751b5141ecb0de3a11b7b5e8791650dfdd..769b4cf9dcc807ae0031c0235278f39e076735a9 100644 (file)
@@ -39,6 +39,7 @@ Library
 
     Exposed-Modules:
         Sound.EsounD
+        Sound.EsounD.Monitor
         Sound.EsounD.Player
         Sound.EsounD.Streams
         Sound.EsounD.Types
index c44e6dd9007dfe650560abedaf136779764a4a8a..98e7c5aa324813d91c52424ccbd4c318f95a030f 100644 (file)
@@ -3,9 +3,11 @@ module Sound.EsounD
     ( module Sound.EsounD.Types
     , module Sound.EsounD.Streams
     , module Sound.EsounD.Player
+    , module Sound.EsounD.Monitor
     )
     where
 
+import Sound.EsounD.Monitor
+import Sound.EsounD.Player
 import Sound.EsounD.Streams
 import Sound.EsounD.Types
-import Sound.EsounD.Player
index 8d28ed8e346bf2aefcaf54d4459e6ef085f7da9c..fcaff1e5e88d84d5c887bf0a45e3d34f93b1e865 100644 (file)
@@ -11,6 +11,7 @@ module Sound.EsounD.Internals
     , Mono
     , Stereo
     , interleave
+    , deinterleave
 
     , wrapSocket
     , closeSocket
@@ -53,7 +54,7 @@ instance Channels Stereo where
     channelFmt _ = c'ESD_STEREO
 
 {-# INLINE interleave #-}
-interleave ∷ Frame fr ⇒ L.Vector fr → L.Vector fr → L.Vector fr
+interleave ∷ Storable α ⇒ L.Vector α → L.Vector α → L.Vector α
 interleave l r
     -- THINKME: consider using storablevector-streamfusion
     = let Just (lFr, l') = L.viewL l
@@ -62,6 +63,21 @@ interleave l r
       in
         L.cons lFr (L.cons rFr lr')
 
+{-# INLINE deinterleave #-}
+deinterleave ∷ Storable α ⇒ L.Vector α → (L.Vector α, L.Vector α)
+deinterleave v
+    -- THINKME: consider using storablevector-streamfusion
+    = let (lr, v') = L.splitAt 2 v
+      in
+        if L.null lr then
+            (L.empty, L.empty)
+        else
+            let Just (lFr, r) = L.viewL lr
+                Just (rFr, _) = L.viewL r
+                (l', r') = deinterleave v'
+            in
+              (L.cons lFr l', L.cons rFr r')
+
 -- Utility functions
 wrapSocket ∷ String → CInt → IO Handle
 wrapSocket e (-1) = fail e
diff --git a/Sound/EsounD/Monitor.hs b/Sound/EsounD/Monitor.hs
new file mode 100644 (file)
index 0000000..7a06b80
--- /dev/null
@@ -0,0 +1,107 @@
+{-# LANGUAGE
+    FlexibleContexts
+  , FlexibleInstances
+  , KindSignatures
+  , MultiParamTypeClasses
+  , UnicodeSyntax
+  , ScopedTypeVariables
+  #-}
+-- | EsounD monitoring streams.
+module Sound.EsounD.Monitor
+    ( Monitor
+    , openMonitor
+    )
+    where
+import Bindings.EsounD
+import Control.Exception.Peel
+import Control.Monad.IO.Class
+import Control.Monad.IO.Peel
+import Control.Monad.Trans.Region
+import Control.Monad.Trans.Region.OnExit
+import Control.Monad.Unicode
+import Data.Bits
+import Data.StorableVector      as S
+import Data.StorableVector.Lazy as L
+import Foreign.Storable
+import Network
+import Prelude.Unicode
+import Sound.EsounD.Streams
+import Sound.EsounD.Internals
+import System.IO
+import System.IO.SaferFileHandles.Unsafe
+import Text.Printf
+
+-- ^ An opaque ESD handle for monitoring the output from the ESD.
+data Monitor fr ch (r ∷ ★ → ★)
+    = Monitor {
+        moRate   ∷ !Int
+      , moHandle ∷ !Handle
+      , moCloseH ∷ !(FinalizerHandle r)
+      }
+
+instance Dup (Monitor fr ch) where
+    dup mo = do ch' ← dup (moCloseH mo)
+                return mo { moCloseH = ch' }
+
+instance Stream (Monitor fr ch) where
+    streamSampleRate = moRate
+
+toLSV ∷ Storable α ⇒ S.Vector α → L.Vector α
+toLSV v = L.fromChunks [v]
+
+instance Frame fr ⇒ ReadableStream (Monitor fr Mono) (L.Vector fr) where
+    readFrames mo nFrames
+        = liftIO $
+          sanitizeIOError $
+          fmap toLSV $
+          S.hGet (moHandle mo) nFrames
+
+instance Frame fr ⇒ ReadableStream (Monitor fr Stereo) (L.Vector fr, L.Vector fr) where
+    readFrames mo nFrames
+        = liftIO $
+          sanitizeIOError $
+          fmap (deinterleave ∘ toLSV) $
+          S.hGet (moHandle mo) nFrames
+
+-- | Open an ESD handle for monitoring the output from the ESD.
+openMonitor ∷ ∀fr ch s pr.
+               ( Frame fr
+               , Channels ch
+               , MonadPeelIO pr
+               )
+            ⇒ Int            -- ^ sample rate for the stream.
+            → Maybe HostName -- ^ host to connect to.
+            → Maybe String   -- ^ name used to identify this stream
+                              --   to ESD (if any).
+            → RegionT s pr (Monitor fr ch (RegionT s pr))
+openMonitor rate host name
+    = block $
+      do h  ← liftIO openSocket
+         ch ← onExit $ sanitizeIOError $ closeSocket h
+         return Monitor {
+                      moRate   = rate
+                    , moHandle = h
+                    , moCloseH = ch
+                    }
+    where
+      fmt ∷ C'esd_format_t
+      fmt = frameFmt   ((⊥) ∷ fr) .|.
+            channelFmt ((⊥) ∷ ch) .|.
+            c'ESD_STREAM            .|.
+            c'ESD_MONITOR
+
+      openSocket ∷ IO Handle
+      openSocket = withCStrOrNull host $ \hostPtr →
+                   withCStrOrNull name $ \namePtr →
+                       c'esd_monitor_stream
+                       fmt
+                       (fromIntegral rate)
+                       hostPtr
+                       namePtr
+                       ≫= wrapSocket
+                               ( printf "esd_monitor_stream(%s, %s, %s, %s) returned an error"
+                                        (show fmt )
+                                        (show rate)
+                                        (show host)
+                                        (show name)
+                               )
index b48dfee9a849f15245ecfb3f702ebdd8ca32e5ec..49740fc4167a57872f74b0c9a784b71f0dbb3c6d 100644 (file)
@@ -27,7 +27,7 @@ import Sound.EsounD.Streams
 import Sound.EsounD.Internals
 import System.IO
 import System.IO.SaferFileHandles.Unsafe
-
+import Text.Printf
 
 -- ^ An opaque ESD handle for playing a stream.
 data Player fr ch (r ∷ ★ → ★)
@@ -44,20 +44,23 @@ instance Dup (Player fr ch) where
     dup pl = do ch' ← dup (plCloseH pl)
                 return pl { plCloseH = ch' }
 
-instance Frame fr ⇒ Writable (Player fr Mono) (L.Vector fr) where 
-    write pl v
+instance Stream (Player fr ch) where
+    streamSampleRate = plRate
+
+instance Frame fr ⇒ WritableStream (Player fr Mono) (L.Vector fr) where 
+    writeFrames pl v
         = liftIO $ sanitizeIOError $ L.hPut (plHandle pl) v
 
-instance Frame fr ⇒ Writable (Player fr Stereo) (L.Vector fr, L.Vector fr) where
-    write pl (l, r)
+instance Frame fr ⇒ WritableStream (Player fr Stereo) (L.Vector fr, L.Vector fr) where
+    writeFrames pl (l, r)
         = liftIO $ sanitizeIOError $ L.hPut (plHandle pl) (interleave l r)
 
 -- | Open an ESD handle for playing a stream.
 openPlayer ∷ ∀fr ch s pr.
-               ( Frame fr
-               , Channels ch
-               , MonadPeelIO pr
-               )
+              ( Frame fr
+              , Channels ch
+              , MonadPeelIO pr
+              )
            ⇒ Int            -- ^ sample rate for the stream.
            → Maybe HostName -- ^ host to connect to.
            → Maybe String   -- ^ name used to identify this stream to
@@ -88,13 +91,9 @@ openPlayer rate host name
                        hostPtr
                        namePtr
                        ≫= wrapSocket
-                               ( "esd_play_stream("
-                                 ⧺ show fmt
-                                 ⧺ ", "
-                                 ⧺ show rate
-                                 ⧺ ", "
-                                 ⧺ show host
-                                 ⧺ ", "
-                                 ⧺ show name
-                                 ⧺ ") returned an error"
+                               ( printf "esd_play_stream(%s, %s, %s, %s) returned an error"
+                                        (show fmt )
+                                        (show rate)
+                                        (show host)
+                                        (show name)
                                )
index 216fdafda4cf4b2f21284a5260fe5c7bc3e10a34..374b60240eb6b6d17971c72fd549ed43b42f4023 100644 (file)
@@ -4,14 +4,32 @@
   #-}
 -- | EsounD stream I/O
 module Sound.EsounD.Streams
-    ( Writable(..)
+    ( Stream(..)
+    , ReadableStream(..)
+    , WritableStream(..)
     )
     where
 import Control.Monad.IO.Class
 import Control.Monad.Trans.Region
 
-class Writable ws dvec where
-    write ∷ ( AncestorRegion pr cr
-             , MonadIO cr
-             )
-          ⇒ ws pr → dvec → cr ()
+-- | ESD streams.
+class Stream s where
+    streamSampleRate ∷ s pr → Int
+
+-- | ESD streams which behave as sources.
+class Stream rs ⇒ ReadableStream rs dvec where
+    readFrames ∷ ( AncestorRegion pr cr
+                  , MonadIO cr
+                  )
+               ⇒ rs pr
+               → Int     -- ^ number of frames to read
+               → cr dvec -- ^ frames in deinterleaved vectors
+
+-- | ESD streams which behave as sinks.
+class Stream ws ⇒ WritableStream ws dvec where
+    writeFrames ∷ ( AncestorRegion pr cr
+                   , MonadIO cr
+                   )
+                ⇒ ws pr
+                → dvec  -- ^ frames in deinterleaved vectors
+                → cr ()
index cddc9eb809a6a122baa61a3a6600a1d30795ac9e..e25b1bee9baf075763fe4a2e87e324de5390a947 100644 (file)
@@ -24,7 +24,7 @@ playMono16Sine ∷ ( AncestorRegion pr cr
                → Double
                → cr ()
 playMono16Sine pl sampleFreq sec noteFreq
-    = write pl buffer
+    = writeFrames pl buffer
     where
       buffer ∷ L.Vector Int16
       buffer = L.pack L.defaultChunkSize frames