From: PHO Date: Sat, 6 Nov 2010 06:20:30 +0000 (+0900) Subject: Sound.EsounD.Player X-Git-Tag: RELEASE-0.1~17 X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=EsounD.git;a=commitdiff_plain;h=d2396e7b6183bb033861069aaeb52be53a90bfdf Sound.EsounD.Player --- diff --git a/EsounD.cabal b/EsounD.cabal index cb7e8e1..d921824 100644 --- a/EsounD.cabal +++ b/EsounD.cabal @@ -34,6 +34,8 @@ Library Exposed-Modules: Sound.EsounD + Sound.EsounD.Player + Sound.EsounD.Types Other-Modules: Sound.EsounD.Internals diff --git a/Sound/EsounD.hs b/Sound/EsounD.hs index 82bd72a..e9276a0 100644 --- a/Sound/EsounD.hs +++ b/Sound/EsounD.hs @@ -1,98 +1,9 @@ -- | Type-safe bindings to EsounD with monadic regions. module Sound.EsounD - ( Frame - - , Channels - , Mono - , Stereo - - , Player - , openPlayer + ( module Sound.EsounD.Types + , module Sound.EsounD.Player ) where -import Bindings.EsounD -import Control.Monad.IO.Class -import Control.Monad.Trans.Region -import Control.Monad.Trans.Region.OnExit -import Control.Monad.Unicode -import Data.Bits -import Data.Int -import Foreign.C.String -import Network -import Prelude.Unicode -import Sound.EsounD.Internals -import System.IO -import System.IO.SaferFileHandles.Unsafe - -class Frame fr where - frameFmt ∷ fr → C'esd_format_t - -instance Frame Int8 where - frameFmt _ = c'ESD_BITS8 - -instance Frame Int16 where - frameFmt _ = c'ESD_BITS16 - -class Channels ch where - channelFmt ∷ ch → C'esd_format_t - -data Mono -instance Channels Mono where - channelFmt _ = c'ESD_MONO - -data Stereo -instance Channels Stereo where - channelFmt _ = c'ESD_STEREO - - --- ^ An ESD handle for playing a stream. -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. - , plHandle ∷ !Handle - , plCloseH ∷ !(CloseHandle r) - } - -instance Dup (Player fr ch) where - dup pl = do ch' ← dup (plCloseH pl) - return pl { plCloseH = ch' } - --- | 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). - → RegionT s pr (Player fr ch (RegionT s pr)) -openPlayer rate host name - = do h ← liftIO openSocket - ch ← onExit $ sanitizeIOError $ closeSocket h - return Player { - plRate = rate - , plHandle = h - , plCloseH = ch - } - where - fmt :: C'esd_format_t - fmt = frameFmt ((⊥) ∷ fr) .&. - channelFmt ((⊥) ∷ ch) .&. - c'ESD_STREAM .&. - c'ESD_PLAY - - openSocket :: IO Handle - openSocket = withCString host $ \hostPtr → - withCStrOrNull name $ \namePtr → - c'esd_play_stream - fmt - (fromIntegral rate) - hostPtr - namePtr - ≫= wrapSocket "esd_play_stream() returned an error" +import Sound.EsounD.Types +import Sound.EsounD.Player diff --git a/Sound/EsounD/Internals.hs b/Sound/EsounD/Internals.hs index 987dd1e..f75f99a 100644 --- a/Sound/EsounD/Internals.hs +++ b/Sound/EsounD/Internals.hs @@ -1,11 +1,18 @@ module Sound.EsounD.Internals - ( wrapSocket + ( Frame(..) + + , Channels(..) + , Mono + , Stereo + + , wrapSocket , closeSocket , withCStrOrNull ) where import Bindings.EsounD +import Data.Int import Foreign.C.String import Foreign.C.Types import Foreign.Ptr @@ -13,6 +20,27 @@ import System.IO import System.Posix.IO import System.Posix.Types +class Frame fr where + frameFmt ∷ fr → C'esd_format_t + +instance Frame Int8 where + frameFmt _ = c'ESD_BITS8 + +instance Frame Int16 where + frameFmt _ = c'ESD_BITS16 + +class Channels ch where + channelFmt ∷ ch → C'esd_format_t + +data Mono +instance Channels Mono where + channelFmt _ = c'ESD_MONO + +data Stereo +instance Channels Stereo where + channelFmt _ = c'ESD_STEREO + + wrapSocket :: String -> CInt → IO Handle wrapSocket e (-1) = fail e wrapSocket _ fd = fdToHandle (Fd fd) diff --git a/Sound/EsounD/Player.hs b/Sound/EsounD/Player.hs new file mode 100644 index 0000000..0d2b209 --- /dev/null +++ b/Sound/EsounD/Player.hs @@ -0,0 +1,71 @@ +-- | EsounD player streams. +module Sound.EsounD.Player + ( Player + , openPlayer + ) + where + +import Bindings.EsounD +import Control.Monad.IO.Class +import Control.Monad.Trans.Region +import Control.Monad.Trans.Region.OnExit +import Control.Monad.Unicode +import Data.Bits +import Foreign.C.String +import Network +import Prelude.Unicode +import Sound.EsounD.Internals +import System.IO +import System.IO.SaferFileHandles.Unsafe + + +-- ^ An opaque ESD handle for playing a stream. +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. + , plHandle ∷ !Handle + , plCloseH ∷ !(CloseHandle r) + } + +instance Dup (Player fr ch) where + dup pl = do ch' ← dup (plCloseH pl) + return pl { plCloseH = ch' } + +-- | 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). + → RegionT s pr (Player fr ch (RegionT s pr)) +openPlayer rate host name + = do h ← liftIO openSocket + ch ← onExit $ sanitizeIOError $ closeSocket h + return Player { + plRate = rate + , plHandle = h + , plCloseH = ch + } + where + fmt :: C'esd_format_t + fmt = frameFmt ((⊥) ∷ fr) .&. + channelFmt ((⊥) ∷ ch) .&. + c'ESD_STREAM .&. + c'ESD_PLAY + + openSocket :: IO Handle + openSocket = withCString host $ \hostPtr → + withCStrOrNull name $ \namePtr → + c'esd_play_stream + fmt + (fromIntegral rate) + hostPtr + namePtr + ≫= wrapSocket "esd_play_stream() returned an error" diff --git a/Sound/EsounD/Types.hs b/Sound/EsounD/Types.hs new file mode 100644 index 0000000..2525f46 --- /dev/null +++ b/Sound/EsounD/Types.hs @@ -0,0 +1,10 @@ +module Sound.EsounD.Types + ( Frame + + , Channels + , Mono + , Stereo + ) + where + +import Sound.EsounD.Internals