( module Sound.EsounD.Types
, module Sound.EsounD.Streams
, module Sound.EsounD.Player
+ , module Sound.EsounD.Recorder
, module Sound.EsounD.Monitor
)
where
import Sound.EsounD.Monitor
import Sound.EsounD.Player
+import Sound.EsounD.Recorder
import Sound.EsounD.Streams
import Sound.EsounD.Types
, interleave
, deinterleave
+ , toLSV
+
, wrapSocket
, closeSocket
, withCStrOrNull
where
import Bindings.EsounD
import Data.Int
+import Data.StorableVector as S
import Data.StorableVector.Lazy as L
import Foreign.C.String
import Foreign.C.Types
(L.cons lFr l', L.cons rFr r')
-- Utility functions
+toLSV ∷ Storable α ⇒ S.Vector α → L.Vector α
+toLSV v = L.fromChunks [v]
+
wrapSocket ∷ String → CInt → IO Handle
wrapSocket e (-1) = fail e
wrapSocket _ fd = fdToHandle (Fd fd)
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
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 $
--- /dev/null
+{-# LANGUAGE
+ FlexibleContexts
+ , FlexibleInstances
+ , KindSignatures
+ , MultiParamTypeClasses
+ , UnicodeSyntax
+ , ScopedTypeVariables
+ #-}
+-- | EsounD recording streams.
+module Sound.EsounD.Recorder
+ ( Recorder
+ , openRecorder
+ )
+ 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 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 recording data from the soundcard via ESD.
+data Recorder fr ch (r ∷ ★ → ★)
+ = Recorder {
+ reRate ∷ !Int
+ , reHandle ∷ !Handle
+ , reCloseH ∷ !(FinalizerHandle r)
+ }
+
+instance Dup (Recorder fr ch) where
+ dup re = do ch' ← dup (reCloseH re)
+ return re { reCloseH = ch' }
+
+instance Stream (Recorder fr ch) where
+ streamSampleRate = reRate
+
+instance Frame fr ⇒ ReadableStream (Recorder fr Mono) (L.Vector fr) where
+ readFrames re nFrames
+ = liftIO $
+ sanitizeIOError $
+ fmap toLSV $
+ S.hGet (reHandle re) nFrames
+
+instance Frame fr ⇒ ReadableStream (Recorder fr Stereo) (L.Vector fr, L.Vector fr) where
+ readFrames re nFrames
+ = liftIO $
+ sanitizeIOError $
+ fmap (deinterleave ∘ toLSV) $
+ S.hGet (reHandle re) nFrames
+
+-- | Open an ESD handle for recording data from the soundcard via ESD.
+openRecorder ∷ ∀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 (Recorder fr ch (RegionT s pr))
+openRecorder rate host name
+ = block $
+ do h ← liftIO openSocket
+ ch ← onExit $ sanitizeIOError $ closeSocket h
+ return Recorder {
+ reRate = rate
+ , reHandle = h
+ , reCloseH = ch
+ }
+ where
+ fmt ∷ C'esd_format_t
+ fmt = frameFmt ((⊥) ∷ fr) .|.
+ channelFmt ((⊥) ∷ ch) .|.
+ c'ESD_STREAM .|.
+ c'ESD_RECORD
+
+ openSocket ∷ IO Handle
+ openSocket = withCStrOrNull host $ \hostPtr →
+ withCStrOrNull name $ \namePtr →
+ c'esd_record_stream
+ fmt
+ (fromIntegral rate)
+ hostPtr
+ namePtr
+ ≫= wrapSocket
+ ( printf "esd_record_stream(%s, %s, %s, %s) returned an error"
+ (show fmt )
+ (show rate)
+ (show host)
+ (show name)
+ )