module Sound.Pulse.Simple
(simpleNew
,simpleFree
,simpleGetLatency
,simpleRead
,simpleReadRaw
,simpleWrite
,simpleWriteRaw
,simpleDrain
,simpleFlush
,Simple
,SampleSpec(..)
,SampleFormat(..)
,Compression(..)
,Endian(..)
,Direction(..)
,ChannelPosition(..)
,ChannelPan(..)
,BufferAttr(..))
where
import Control.Monad
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BS
import Foreign.C
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable
foreign import ccall "pa_simple_new" pasNew
:: CString -> CString -> CInt -> CString -> CString -> Ptr SampleSpec -> Ptr ChannelMap
-> Ptr BufferAttr -> Ptr CInt -> IO (Ptr PASimple)
foreign import ccall "pa_simple_free" pasFree :: Ptr PASimple -> IO ()
foreign import ccall "pa_simple_write" pasWrite :: Ptr PASimple -> Ptr CUChar -> CInt -> Ptr CInt -> IO CInt
foreign import ccall "pa_simple_read" pasRead :: Ptr PASimple -> Ptr CUChar -> CInt -> Ptr CInt -> IO CInt
foreign import ccall "pa_simple_drain" pasDrain :: Ptr PASimple -> Ptr CInt -> IO CInt
foreign import ccall "pa_simple_get_latency" pasGetLatency :: Ptr PASimple -> Ptr CInt -> IO CUInt
foreign import ccall "pa_simple_flush" pasFlush :: Ptr PASimple -> IO CInt
newtype Simple=Simple (Ptr PASimple)
data Direction=Play|Record
data SampleSpec=SampleSpec SampleFormat Int Int
data SampleFormat
=U8 Compression
|S16 Endian
|S24 Endian
|S2432 Endian
|S32 Endian
|F32 Endian
data Compression=Raw|ALaw|MuLaw
data Endian=BigEndian|LittleEndian
newtype ChannelMap=ChannelMap [ChannelPosition]
data ChannelPosition
=ChannelMono
|ChannelNormal ChannelPan
|ChannelFront ChannelPan
|ChannelRear ChannelPan
|ChannelTopRear ChannelPan
|ChannelTopFront ChannelPan
|ChannelLFE
|ChannelSubwoofer
|ChannelFrontCenterLeft
|ChannelFrontCenterRight
|ChannelSideLeft
|ChannelSideRight
|ChannelTopCenter
|ChannelAux Int
data ChannelPan=PanLeft|PanRight|PanCenter
data BufferAttr=BufferAttr (Maybe Int) (Maybe Int) (Maybe Int) (Maybe Int) (Maybe Int)
data PASimple=PASimple
instance Enum Direction where
toEnum=undefined
fromEnum Play=1
fromEnum Record=2
instance Storable SampleSpec where
alignment _= 4
sizeOf _= (12)
poke ptr (SampleSpec fmt rate nch)=do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr $ fromEnum fmt
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr rate
(\hsc_ptr -> pokeByteOff hsc_ptr 8) ptr nch
instance Enum SampleFormat where
toEnum=undefined
fromEnum (U8 Raw)=0
fromEnum (U8 ALaw)=1
fromEnum (U8 MuLaw)=2
fromEnum x=case x of
S16 e -> 3+f e
F32 e -> 5+f e
S32 e -> 7+f e
S24 e -> 9+f e
S2432 e -> 11+f e
where f LittleEndian=0; f BigEndian=1
instance Storable ChannelMap where
alignment _= 4
sizeOf _= 4
poke ptr (ChannelMap ps)=withArray (map fromEnum ps) $ \_ps -> do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr $ length ps
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr _ps
instance Enum ChannelPosition where
toEnum=undefined
fromEnum x=case x of
ChannelMono -> 0
ChannelNormal p -> 1+f p
ChannelFront p -> 1+f p
ChannelRear p -> 4+f p
ChannelLFE -> 7
ChannelSubwoofer -> 7
ChannelFrontCenterLeft -> 8
ChannelFrontCenterRight -> 9
ChannelSideLeft -> 10
ChannelSideRight -> 11
ChannelAux n -> 12+n
ChannelTopCenter -> 44
ChannelTopFront p -> 45+f p
ChannelTopRear p -> 48+f p
where f PanLeft=0; f PanRight=1; f PanCenter=2
instance Storable BufferAttr where
alignment _= 4
sizeOf _= 4
poke ptr (BufferAttr ml tl pb mr fs)=do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) ptr $ f ml
(\hsc_ptr -> pokeByteOff hsc_ptr 4) ptr $ f tl
(\hsc_ptr -> pokeByteOff hsc_ptr 8) ptr $ f pb
(\hsc_ptr -> pokeByteOff hsc_ptr 12) ptr $ f mr
(\hsc_ptr -> pokeByteOff hsc_ptr 16) ptr $ f fs
where f=maybe 0xffffffff id
simpleNew
:: Maybe String
-> String
-> Direction
-> Maybe String
-> String
-> SampleSpec
-> Maybe [ChannelPosition]
-> Maybe BufferAttr
-> IO Simple
simpleNew server client dir dev desc spec chmap attr=liftM Simple $
withMaybeCString server $ \_server->
withCString client $ \_client ->
withMaybeCString dev $ \_dev ->
withCString desc $ \_desc ->
withStorable spec $ \_spec ->
withMaybeStorable (liftM ChannelMap chmap) $ \_chmap ->
withMaybeStorable attr $ \_attr ->
pasNew _server _client (fromIntegral $ fromEnum dir) _dev _desc _spec _chmap _attr nullPtr
simpleReadRaw :: Simple -> Int -> IO BS.ByteString
simpleReadRaw (Simple x) size=
BS.create size $ \ptr->pasRead x (castPtr ptr) (fromIntegral size) nullPtr >> return ()
simpleWriteRaw :: Simple -> BS.ByteString -> IO ()
simpleWriteRaw (Simple x) (BS.PS ptr ofs size)=do
withForeignPtr ptr $ \p->pasWrite x (castPtr p) (fromIntegral size) nullPtr
return ()
simpleRead :: Storable a => Simple -> Int -> IO [a]
simpleRead s n=simpleReadHack undefined s n
simpleReadHack :: Storable a => a -> Simple -> Int -> IO [a]
simpleReadHack dummy (Simple x) n=do
let size=fromIntegral $ n*sizeOf dummy
rs<-allocaArray n $ \ptr->pasRead x (castPtr ptr) size nullPtr >> peekArray n ptr
return rs
simpleWrite :: Storable a => Simple -> [a] -> IO ()
simpleWrite (Simple x) xs=do
let n=length xs
size=fromIntegral $ n*sizeOf (head xs)
allocaArray n $ \ptr->pokeArray ptr xs >> pasWrite x (castPtr ptr) size nullPtr
return ()
simpleFlush :: Simple -> IO ()
simpleFlush (Simple x)=pasFlush x >> return ()
simpleDrain :: Simple -> IO ()
simpleDrain (Simple x)=pasDrain x nullPtr >> return ()
simpleFree :: Simple -> IO ()
simpleFree (Simple x)=pasFree x
simpleGetLatency :: Simple -> IO Integer
simpleGetLatency (Simple x)=liftM fromIntegral $ pasGetLatency x nullPtr
withMaybeStorable :: Storable a => Maybe a -> (Ptr a -> IO b) -> IO b
withMaybeStorable Nothing f=f nullPtr
withMaybeStorable (Just x) f=withStorable x f
withStorable :: Storable a => a -> (Ptr a -> IO b) -> IO b
withStorable x f=alloca (\ptr->poke ptr x>> f ptr)
withMaybeCString :: Maybe String -> (CString -> IO a) -> IO a
withMaybeCString Nothing f=f nullPtr
withMaybeCString (Just s) f=withCString s f