]> gitweb @ CieloNegro.org - EsounD.git/blobdiff - Sound/EsounD/Player.hs
samples
[EsounD.git] / Sound / EsounD / Player.hs
index 0d2b209c32b20fb9ba2ae72a2e518cac83ec8bf7..56781da08f2753efc24178d2bcac28f9c0379af2 100644 (file)
@@ -1,52 +1,80 @@
+{-# LANGUAGE
+    FlexibleContexts
+  , FlexibleInstances
+  , KindSignatures
+  , MultiParamTypeClasses
+  , UnicodeSyntax
+  , ScopedTypeVariables
+  #-}
 -- | EsounD player streams.
 module Sound.EsounD.Player
     ( Player
     , openPlayer
     )
     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 Foreign.C.String
+import Data.StorableVector.Lazy as L
 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 playing a stream.
-data Player fr ch (r ∷ * → *)
+data Player fr ch (r ∷ ★ → ★)
     = Player {
         plRate   ∷ !Int
       -- THINKME: We really want to use RegionalFileHandle but we
       -- can't, because safer-file-handles currently provides no ways
-      -- to wrap ordinary handles.
+      -- to wrap ordinary handles into safer handles.
       , plHandle ∷ !Handle
-      , plCloseH ∷ !(CloseHandle r)
+      , plCloseH ∷ !(FinalizerHandle r)
       }
 
 instance Dup (Player fr ch) where
     dup pl = do ch' ← dup (plCloseH pl)
                 return pl { plCloseH = ch' }
 
+instance Stream (Player fr ch) where
+    streamSampleRate = plRate
+
+instance Frame fr ⇒ WritableStream (Player fr Mono) (L.Vector fr) where 
+    writeFrames pl v
+        = liftIO $
+          sanitizeIOError $
+          do L.hPut (plHandle pl) v
+             hFlush (plHandle pl)
+
+instance Frame fr ⇒ WritableStream (Player fr Stereo) (L.Vector fr, L.Vector fr) where
+    writeFrames pl (l, r)
+        = liftIO $
+          sanitizeIOError $
+          do L.hPut (plHandle pl) (interleave l r)
+             hFlush (plHandle pl)
+
 -- | Open an ESD handle for playing a stream.
 openPlayer ∷ ∀fr ch s pr.
-               ( Frame fr
-               , Channels ch
-               , MonadIO pr
-               )
-           ⇒ Int          -- ^ sample rate for the stream.
-           → HostName     -- ^ host to connect to.
-           → Maybe String -- ^ name used to identify this stream to
-                           --   ESD (if any).
+              ( 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 (Player fr ch (RegionT s pr))
 openPlayer rate host name
-    = do h  ← liftIO openSocket
+    = block $
+      do h  ← liftIO openSocket
          ch ← onExit $ sanitizeIOError $ closeSocket h
          return Player {
                       plRate   = rate
@@ -55,17 +83,23 @@ openPlayer rate host name
                     }
     where
       fmt :: C'esd_format_t
-      fmt = frameFmt   ((⊥) ∷ fr) .&.
-            channelFmt ((⊥) ∷ ch) .&.
-            c'ESD_STREAM            .&.
+      fmt = frameFmt   ((⊥) ∷ fr) .|.
+            channelFmt ((⊥) ∷ ch) .|.
+            c'ESD_STREAM            .|.
             c'ESD_PLAY
 
       openSocket :: IO Handle
-      openSocket = withCString    host $ \hostPtr →
+      openSocket = withCStrOrNull host $ \hostPtr →
                    withCStrOrNull name $ \namePtr →
                        c'esd_play_stream
                        fmt
                        (fromIntegral rate)
                        hostPtr
                        namePtr
-                       ≫= wrapSocket "esd_play_stream() returned an error"
+                       ≫= wrapSocket
+                               ( printf "esd_play_stream(%s, %s, %s, %s) returned an error"
+                                        (show fmt )
+                                        (show rate)
+                                        (show host)
+                                        (show name)
+                               )