packages feed

pulse-simple (empty) → 0.1.11

raw patch · 4 files changed

+313/−0 lines, 4 filesdep +basedep +bytestringsetup-changed

Dependencies added: base, bytestring

Files

+ LICENSE view
@@ -0,0 +1,25 @@+Copyright (c) 2009 Daiki Handa+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. The name of the author may not be used to endorse or promote products+   derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple+main=defaultMain+
+ Sound/Pulse/Simple.hsc view
@@ -0,0 +1,263 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |+-- Maintainer:  xanxys@gmail.com+-- Stability:   experimental+-- Portability: non-portable+--+-- Binding to PulseAudio Simple API+--+-- example(output 440Hz sine wave for 10 seconds):+-- +-- @+--  main=do+--      s<-simpleNew Nothing \"example\" Play Nothing \"this is example application\"+--          (SampleSpec (F32 LittleEndian) 44100 1) Nothing Nothing+--      simpleWrite s [sin $ 2*pi*440*(t/44100)|t<-[1..44100*10]]+--      simpleDrain s+--      simpleFree s+-- @+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+++#include <pulse/simple.h>+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)+++++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 -- 64 bit dep.+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 -- ^ format, sampling rate, #channels++data SampleFormat+    =U8 Compression+    |S16 Endian+    |S24 Endian+    |S2432 Endian -- ^ 24 bit sample in 32 bit+    |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 -- ^ low frequency effects+    |ChannelSubwoofer+    |ChannelFrontCenterLeft -- ^ equivalent to PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER+    |ChannelFrontCenterRight+    |ChannelSideLeft+    |ChannelSideRight+    |ChannelTopCenter+    |ChannelAux Int -- 0-31+++data ChannelPan=PanLeft|PanRight|PanCenter+    +++data BufferAttr=BufferAttr (Maybe Int) (Maybe Int) (Maybe Int) (Maybe Int) (Maybe Int)+-- ^ max length, target length, prebuffer, minimum request, fragment size+++-- hidden struct+data PASimple=PASimple++++++++instance Enum Direction where+    toEnum=undefined+    fromEnum Play=1+    fromEnum Record=2++instance Storable SampleSpec where+    alignment _= #{alignment pa_sample_spec}+    sizeOf _= #{size pa_sample_spec}+    poke ptr (SampleSpec fmt rate nch)=do+        #{poke pa_sample_spec,format}   ptr $ fromEnum fmt+        #{poke pa_sample_spec,rate}     ptr rate+        #{poke pa_sample_spec,channels} 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 _= #{alignment pa_channel_map}+    sizeOf _= #{alignment pa_channel_map}+    poke ptr (ChannelMap ps)=withArray (map fromEnum ps) $ \_ps -> do+        #{poke pa_channel_map,channels} ptr $ length ps+        #{poke pa_channel_map,map} 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 _= #{alignment pa_buffer_attr}+    sizeOf _= #{alignment pa_buffer_attr}+    poke ptr (BufferAttr ml tl pb mr fs)=do+        #{poke pa_buffer_attr,maxlength} ptr $ f ml+        #{poke pa_buffer_attr,tlength}   ptr $ f tl+        #{poke pa_buffer_attr,prebuf}    ptr $ f pb+        #{poke pa_buffer_attr,minreq}    ptr $ f mr+        #{poke pa_buffer_attr,fragsize}  ptr $ f fs+        where f=maybe 0xffffffff id+++ +++-- | Establish connection to pulseaudio server. You usually don't need to specify optional fields.+simpleNew+    :: Maybe String -- ^ server name+    -> String -- ^ client name+    -> Direction -- ^ Play or Record+    -> Maybe String -- ^ name of sink or source+    -> String -- ^ description of client+    -> SampleSpec+    -> Maybe [ChannelPosition] -- ^ label channels+    -> Maybe BufferAttr -- ^ buffer size, etc+    -> 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+++-- | Read raw data from buffer.+simpleReadRaw :: Simple -> Int -> IO BS.ByteString+simpleReadRaw (Simple x) size=+    BS.create size $ \ptr->pasRead x (castPtr ptr) (fromIntegral size) nullPtr >> return ()++-- | Write raw data to buffer.+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 ()++-- | Read from buffer.+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+    +-- | Write to buffer.+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 ()++-- | Flush playback buffer+simpleFlush :: Simple -> IO ()+simpleFlush (Simple x)=pasFlush x >> return ()++-- | block until buffer is completely consumed+simpleDrain :: Simple -> IO ()+simpleDrain (Simple x)=pasDrain x nullPtr >> return ()++-- | Close the connection.+simpleFree :: Simple -> IO ()+simpleFree (Simple x)=pasFree x++-- | Get current latency in microseconds.+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+
+ pulse-simple.cabal view
@@ -0,0 +1,22 @@+Name:            pulse-simple+Cabal-Version:   >=1.2+Version:         0.1.11+Author:          Daiki Handa+Maintainer:      xanxys@gmail.com+Synopsis:        binding to Simple API of pulseaudio+Build-Type:      Simple+License:         BSD3+License-File:    LICENSE+Category:        Sound+Description:+  Binding to simple version of client API for the pulseaudio soundserver.+  Although it does not provide advanced features and some not-so-adavanced features like+  volume control, it should be enough for simple applications.+  Tested only on 64-bit linux with ghc-6.10.3.++Library+    Extensions: ForeignFunctionInterface+    Extra-Libraries: pulse-simple+    Build-depends:   base>=3 && <4, bytestring+    Exposed-Modules: Sound.Pulse.Simple+