soxlib (empty) → 0.0
raw patch · 6 files changed
+642/−0 lines, 6 filesdep +basedep +containersdep +explicit-exceptionsetup-changed
Dependencies added: base, containers, explicit-exception, extensible-exceptions, sample-frame, storablevector, transformers, utility-ht
Files
- LICENSE +31/−0
- Setup.lhs +3/−0
- soxlib.cabal +54/−0
- src/Sound/SoxLib.hs +174/−0
- src/Sound/SoxLib/FFI.hsc +342/−0
- src/Sound/SoxLib/Template.h +38/−0
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2012, Henning Thielemann++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * 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.++ * The names of contributors may not be used to endorse or promote+ products derived from this software without specific prior+ written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER OR CONTRIBUTORS 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.lhs view
@@ -0,0 +1,3 @@+#! /usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ soxlib.cabal view
@@ -0,0 +1,54 @@+Name: soxlib+Version: 0.0+License: BSD3+License-File: LICENSE+Author: Henning Thielemann <haskell@henning-thielemann.de>+Maintainer: Henning Thielemann <haskell@henning-thielemann.de>+Homepage: http://www.haskell.org/haskellwiki/Sox+Category: Sound+Synopsis: Write, read, convert audio signals using libsox+Description:+ This is an FFI binding to @libsox@ of the Sox (Sound Exchanger) project+ <http://sox.sourceforge.net/>.+ It lets write, read and convert audio signals+ in various formats, resolutions, and numbers of channels.+ .+ The package @sox@ has similar functionality+ but calls the @sox@ shell command.+Tested-With: GHC==6.12.3, GHC==7.4.1+Cabal-Version: >=1.6+Build-Type: Simple+Extra-Source-Files:+ src/Sound/SoxLib/Template.h++Source-Repository this+ Tag: 0.0+ Type: darcs+ Location: http://code.haskell.org/~thielema/soxlib/++Source-Repository head+ Type: darcs+ Location: http://code.haskell.org/~thielema/soxlib/++Library+ Build-Depends:+ sample-frame >=0.0.1 && <0.1,+ storablevector >=0.2.7 && <0.3,+ explicit-exception >=0.1.3 && < 0.2,+ -- that's the way to get compatibility between GHC 6.10 and 6.12+ extensible-exceptions >=0.1.1 && <0.2,+ transformers >=0.2 && <0.4,+ containers >=0.1 && <0.5,+ utility-ht >=0.0.5 && <0.1,+ base >=4 && <5++ GHC-Options: -Wall+ Hs-Source-Dirs: src+ Include-Dirs: src++ Exposed-Modules:+ Sound.SoxLib+ Other-Modules:+ Sound.SoxLib.FFI++ PkgConfig-Depends: sox >=14.3 && <14.4
+ src/Sound/SoxLib.hs view
@@ -0,0 +1,174 @@+module Sound.SoxLib (+ with, formatWith,+ withRead, readStorableVector, readStorableVectorLazy,+ withWrite, writeStorableVector, writeStorableVectorLazy,+ seek,+ FFI.Mode(..), FFI.ReadMode, FFI.WriteMode,+ ReaderInfo(..), defaultReaderInfo,+ WriterInfo(..), defaultWriterInfo,++ FFI.Rate,+ FFI.FileType(..),+ FFI.Format(..),+ FFI.SignalInfo(..),+ FFI.EncodingInfo(..),+ FFI.defaultSignalInfo,+ ) where++import qualified Sound.SoxLib.FFI as FFI++import qualified Foreign.Marshal.Utils as U+import qualified Foreign.C.String as CStr+import Foreign.Storable (Storable, peek, )+import Foreign.Ptr (Ptr, nullFunPtr, nullPtr, )++import Control.Exception (bracket_, bracket, )+import System.IO.Error (mkIOError, doesNotExistErrorType, )++import qualified Data.StorableVector.Base as SVB+import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector as SV++import qualified Control.Monad.Trans.Cont as MC+import Control.Monad (when, )++import System.IO.Unsafe (unsafeInterleaveIO, )++import Data.Int (Int32, )+++with :: IO a -> IO a+with = bracket_ FFI.init FFI.quit++formatWith :: IO a -> IO a+formatWith = bracket_ FFI.formatInit FFI.formatQuit+++withMaybe ::+ Storable b =>+ (a -> (Ptr b -> IO c) -> IO c) ->+ Maybe a -> MC.ContT c IO (Ptr b)+withMaybe _ Nothing = return nullPtr+withMaybe f (Just a) = MC.ContT $ f a+++data ReaderInfo =+ ReaderInfo {+ readerSignalInfo :: Maybe FFI.SignalInfo,+ readerEncodingInfo :: Maybe FFI.EncodingInfo,+ readerFileType :: Maybe FFI.FileType+ }++defaultReaderInfo :: ReaderInfo+defaultReaderInfo = ReaderInfo Nothing Nothing Nothing++withRead ::+ ReaderInfo -> FilePath ->+ (Ptr (FFI.Format FFI.ReadMode) -> IO a) -> IO a+withRead info path =+ MC.runContT $ do+ si <- withMaybe U.with $ readerSignalInfo info+ enc <- withMaybe U.with $ readerEncodingInfo info+ cft <- withMaybe CStr.withCString $+ fmap FFI.unFileType $ readerFileType info+ cpath <- MC.ContT $ CStr.withCString path+ MC.ContT $+ bracket+ (do fmt <- FFI.openRead cpath si enc cft+ if fmt==nullPtr+ then throwDoesNotExist "SoxLib.withRead" path+ else return fmt)+ FFI.close+++data WriterInfo =+ WriterInfo {+ writerSignalInfo :: Maybe FFI.SignalInfo,+ writerEncodingInfo :: Maybe FFI.EncodingInfo,+ writerFileType :: Maybe FFI.FileType+ }++defaultWriterInfo :: WriterInfo+defaultWriterInfo = WriterInfo Nothing Nothing Nothing++withWrite ::+ WriterInfo -> FilePath ->+ (Ptr (FFI.Format FFI.WriteMode) -> IO a) -> IO a+withWrite info path =+ MC.runContT $ do+ si <- withMaybe U.with $ writerSignalInfo info+ enc <- withMaybe U.with $ writerEncodingInfo info+ cft <- withMaybe CStr.withCString $+ fmap FFI.unFileType $ writerFileType info+ cpath <- MC.ContT $ CStr.withCString path+ MC.ContT $+ bracket+ (do fmt <- FFI.openWrite cpath si enc cft nullPtr nullFunPtr+ if fmt==nullPtr+ then throwDoesNotExist "SoxLib.withWrite" path+ else return fmt)+ FFI.close+++throwDoesNotExist :: String -> FilePath -> IO a+throwDoesNotExist name path =+ ioError $+ mkIOError doesNotExistErrorType+ name Nothing (Just path)++{- |+Multi-channel data is interleaved.+@size@ must be divisible by the number of channels.+-}+readStorableVector ::+ Ptr (FFI.Format FFI.ReadMode) -> Int -> IO (SV.Vector Int32)+readStorableVector fmt size =+ SVB.createAndTrim size $ \ptr ->+ fmap fromIntegral $ FFI.read fmt ptr (fromIntegral size)++{- |+Multi-channel data is interleaved.+@size@ must be divisible by the number of channels.+-}+writeStorableVector ::+ Ptr (FFI.Format FFI.WriteMode) -> SV.Vector Int32 -> IO ()+writeStorableVector fmt chunk =+ SVB.withStartPtr chunk $ \ptr len -> do+ written <- FFI.write fmt ptr (fromIntegral len)+ when (written < fromIntegral len) $ do+ f <- peek fmt+ ioError $ userError $ FFI.soxErrStr f+++{- |+Read complete file lazily into chunky storable vector.+The chunkSize must be divisible by the number of channels.+-}+readStorableVectorLazy ::+ Ptr (FFI.Format FFI.ReadMode) -> SVL.ChunkSize -> IO (SVL.Vector Int32)+readStorableVectorLazy fmt (SVL.ChunkSize size) =+ let go =+ unsafeInterleaveIO $ do+ chunk <- readStorableVector fmt size+ if SV.length chunk >= size+ then fmap (chunk:) go+ else if SV.length chunk == 0+ then return []+ else return [chunk]+ in fmap SVL.fromChunks go++{- |+The chunkSize must be divisible by the number of channels.+-}+writeStorableVectorLazy ::+ Ptr (FFI.Format FFI.WriteMode) -> SVL.Vector Int32 -> IO ()+writeStorableVectorLazy fmt =+ mapM_ (writeStorableVector fmt) . SVL.chunks+++seek :: (FFI.Mode mode) => Ptr (FFI.Format mode) -> Int -> IO ()+seek fmt pos = do+ res <- FFI.seek fmt (fromIntegral pos) 0+ when (res /= 0) $ do+ f <- peek fmt+ ioError $ userError $ FFI.soxErrStr f
+ src/Sound/SoxLib/FFI.hsc view
@@ -0,0 +1,342 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Sound.SoxLib.FFI where++#include <sox.h>+#include <Sound/SoxLib/Template.h>++import qualified Foreign.C.String as CStr+import qualified Foreign.C.Types as C+import qualified Foreign.C.Error as E+import Foreign.Storable (Storable, sizeOf, alignment, peek, peekByteOff, poke, pokeByteOff, )+import Foreign.Ptr (FunPtr, Ptr, nullPtr, plusPtr, )++import Control.Applicative (pure, (<*>), )++import Data.Maybe.HT (toMaybe, )+import Data.Maybe (fromMaybe, )++import qualified Data.Word as Word+-- import qualified Data.Int as Int+-- we must import it unqualified, because Hsc calls it that way+import Data.Word+import Data.Int++import qualified Prelude as P+import Prelude hiding (Bool, init, length, )++++newtype IOType = IOType #{type lsx_io_type}+ deriving (Storable)++#{enum IOType, IOType+ , ioFile = lsx_io_file+ , ioPipe = lsx_io_pipe+ , ioURL = lsx_io_url+ }++data Format mode =+ Format {+ filename :: FilePath,+ signalInfo :: SignalInfo,+ encodingInfo :: EncodingInfo,+ filetype :: FileType,+ -- oob :: OOB,+ seekable :: P.Bool,+ olength :: Int,+ clips :: Int,+ soxErrno :: E.Errno,+ soxErrStr :: String,+ fp :: Ptr C.CFile,+ ioType :: IOType,+ tellOff :: C.CLong,+ dataStart :: C.CLong,+ -- handler :: FormatHandler,+ priv :: Ptr ()+ }++instance Mode mode => Storable (Format mode) where+ sizeOf _ = #{size sox_format_t}+ alignment _ = #{alignment sox_format_t}+ peek p =+ pure Format+ <*> (peekEmptyCString =<< #{peek sox_format_t, filename} p)+ <*> #{peek sox_format_t, signal} p+ <*> #{peek sox_format_t, encoding} p+ <*> (fmap FileType . peekEmptyCString =<<+ #{peek sox_format_t, filetype} p)+ -- <*> #{peek sox_format_t, oob} p+ <*> peekBool (#{ptr sox_format_t, seekable} p)+ <*> (#{peek_int sox_format_t, olength} p)+ <*> (#{peek_int sox_format_t, clips} p)+ <*> fmap E.Errno (#{peek sox_format_t, sox_errno} p)+ <*> (CStr.peekCStringLen (#{ptr sox_format_t, sox_errstr} p, 256))+ <*> #{peek sox_format_t, fp} p+ <*> #{peek sox_format_t, io_type} p+ <*> #{peek sox_format_t, tell_off} p+ <*> #{peek sox_format_t, data_start} p+ -- <*> #{peek sox_format_t, handler} p+ <*> #{peek sox_format_t, priv} p+ poke = error "SoxLib.Format.poke cannot be implemented because it requires temporary memory"+++peekEmptyCString :: CStr.CString -> IO String+peekEmptyCString ptr =+ if ptr == nullPtr+ then return ""+ else CStr.peekCString ptr+++class Mode mode where+ getModeChar :: Format mode -> C.CChar++data ReadMode = ReadMode+data WriteMode = WriteMode++instance Mode ReadMode where+ getModeChar _ = CStr.castCharToCChar 'r'++instance Mode WriteMode where+ getModeChar _ = CStr.castCharToCChar 'w'+++type Rate = Double++ignoreLength :: Int+ignoreLength = -1++data SignalInfo =+ SignalInfo {+ rate :: Maybe Rate,+ channels :: Maybe Int,+ precision :: Maybe Int,+ length :: Maybe Int,+ mult :: Maybe Double+ }+ deriving (Show)++defaultSignalInfo :: SignalInfo+defaultSignalInfo =+ SignalInfo Nothing Nothing Nothing Nothing Nothing++readSINumber :: (Num a, Eq a) => a -> Maybe a+readSINumber n =+ toMaybe (n /= #{const SOX_UNSPEC}) n++writeSINumber :: (Num a, Eq a) => Maybe a -> a+writeSINumber =+ fromMaybe (#{const SOX_UNSPEC})+++instance Storable SignalInfo where+ sizeOf _ = #{size sox_signalinfo_t}+ alignment _ = #{alignment sox_signalinfo_t}+ peek p =+ pure SignalInfo+ <*> (fmap readSINumber $ peekDouble (#{ptr sox_signalinfo_t, rate} p))+ <*> (fmap readSINumber $ #{peek_int sox_signalinfo_t, channels} p)+ <*> (fmap readSINumber $ #{peek_int sox_signalinfo_t, precision} p)+ <*> (fmap readSINumber $ #{peek_int sox_signalinfo_t, length} p)+ <*> (do pd <- #{peek sox_signalinfo_t, mult} p+ if pd == nullPtr+ then return Nothing+ else fmap Just $ peekDouble pd)+ poke p v =+ pokeDouble (#{ptr sox_signalinfo_t, rate} p) (writeSINumber $ rate v) >>+ #{poke sox_signalinfo_t, channels } p (writeSINumber $ channels v) >>+ #{poke sox_signalinfo_t, precision} p (writeSINumber $ precision v) >>+ #{poke sox_signalinfo_t, length } p (writeSINumber $ length v) >>+ case mult v of+ Nothing -> #{poke sox_signalinfo_t, mult} p nullPtr+ Just _ ->+ error "SoxLib.SignalInfo.poke: Just-mult cannot simply be poked because it requires temporary memory"+++newtype Option = Option #{type sox_option_t}+ deriving (Storable)++#{enum Option, Option+ , optionNo = SOX_OPTION_NO+ , optionYes = SOX_OPTION_YES+ , optionDefault = SOX_OPTION_DEFAULT+ }++instance Show Option where+ show (Option #{const SOX_OPTION_NO }) = "optionNo"+ show (Option #{const SOX_OPTION_YES }) = "optionYes"+ show (Option #{const SOX_OPTION_DEFAULT}) = "optionDefault"+ show (Option n) = error $ "SoxLib.Option.show :invalid number " ++ show n+++data EncodingInfo =+ EncodingInfo {+ encoding :: Encoding,+ bitsPerSample :: Int,+ compression :: Double,++ reverseBytes, reverseNibbles, reverseBits :: Option,+ oppositeEndian :: P.Bool+ }+ deriving (Show)++instance Storable EncodingInfo where+ sizeOf _ = #{size sox_encodinginfo_t}+ alignment _ = #{alignment sox_encodinginfo_t}+ peek p =+ pure EncodingInfo+ <*> (#{peek sox_encodinginfo_t, encoding} p)+ <*> (#{peek_int sox_encodinginfo_t, bits_per_sample} p)+ <*> (peekDouble $ #{ptr sox_encodinginfo_t, compression} p)+ <*> (#{peek sox_encodinginfo_t, reverse_bytes} p)+ <*> (#{peek sox_encodinginfo_t, reverse_nibbles} p)+ <*> (#{peek sox_encodinginfo_t, reverse_bits} p)+ <*> (peekBool $ #{ptr sox_encodinginfo_t, opposite_endian} p)+ poke p v =+ #{poke sox_encodinginfo_t, encoding } p (encoding v) >>+ #{poke_int sox_encodinginfo_t, bits_per_sample} p (bitsPerSample v) >>+ pokeDouble (#{ptr sox_encodinginfo_t, compression} p) (compression v) >>+ #{poke sox_encodinginfo_t, reverse_bytes } p (reverseBytes v) >>+ #{poke sox_encodinginfo_t, reverse_nibbles} p (reverseNibbles v) >>+ #{poke sox_encodinginfo_t, reverse_bits } p (reverseBits v) >>+ pokeBool (#{ptr sox_encodinginfo_t, opposite_endian} p) (oppositeEndian v)+++newtype Bool = Bool #{inttype sox_bool}+ deriving (Show, Eq, Storable)++#{enum Bool, Bool+ , false = sox_false+ , true = sox_true+ }++packBool :: P.Bool -> Bool+packBool False = false+packBool True = true++unpackBool :: Bool -> P.Bool+unpackBool x = x/=false+++peekBool :: Ptr Bool -> IO P.Bool+peekBool p = fmap unpackBool $ peek p++pokeBool :: Ptr Bool -> P.Bool -> IO ()+pokeBool p b = poke p $ packBool b+++peekDouble :: Ptr C.CDouble -> IO Double+peekDouble p = fmap realToFrac $ peek p++pokeDouble :: Ptr C.CDouble -> Double -> IO ()+pokeDouble p x = poke p $ realToFrac x+++newtype Encoding = Encoding #{inttype sox_encoding_t}+ deriving (Storable)++instance Bounded Encoding where+ minBound = Encoding #{const SOX_ENCODING_UNKNOWN}+ maxBound = Encoding $ pred #{const SOX_ENCODINGS}++#{enum Encoding, Encoding+ , encodingUnknown = SOX_ENCODING_UNKNOWN+ , encodingSign2 = SOX_ENCODING_SIGN2+ , encodingUnsigned = SOX_ENCODING_UNSIGNED+ , encodingFloat = SOX_ENCODING_FLOAT+ , encodingFloatText = SOX_ENCODING_FLOAT_TEXT+ , encodingFlac = SOX_ENCODING_FLAC+ , encodingHcom = SOX_ENCODING_HCOM+ , encodingWavpack = SOX_ENCODING_WAVPACK+ , encodingWavpackf = SOX_ENCODING_WAVPACKF+ , encodingUlaw = SOX_ENCODING_ULAW+ , encodingAlaw = SOX_ENCODING_ALAW+ , encodingG721 = SOX_ENCODING_G721+ , encodingG723 = SOX_ENCODING_G723+ , encodingClADPCM = SOX_ENCODING_CL_ADPCM+ , encodingClADPCM16 = SOX_ENCODING_CL_ADPCM16+ , encodingMsADPCM = SOX_ENCODING_MS_ADPCM+ , encodingImaADPCM = SOX_ENCODING_IMA_ADPCM+ , encodingOkiADPCM = SOX_ENCODING_OKI_ADPCM+ , encodingDPCM = SOX_ENCODING_DPCM+ , encodingDWVW = SOX_ENCODING_DWVW+ , encodingDWVWN = SOX_ENCODING_DWVWN+ , encodingGSM = SOX_ENCODING_GSM+ , encodingMP3 = SOX_ENCODING_MP3+ , encodingVorbis = SOX_ENCODING_VORBIS+ , encodingAmrWB = SOX_ENCODING_AMR_WB+ , encodingAmrNB = SOX_ENCODING_AMR_NB+ , encodingCVSD = SOX_ENCODING_CVSD+ , encodingLPC10 = SOX_ENCODING_LPC10+}++instance Show Encoding where+ show (Encoding #{const SOX_ENCODING_UNKNOWN }) = "encodingUnknown"+ show (Encoding #{const SOX_ENCODING_SIGN2 }) = "encodingSign2"+ show (Encoding #{const SOX_ENCODING_UNSIGNED }) = "encodingUnsigned"+ show (Encoding #{const SOX_ENCODING_FLOAT }) = "encodingFloat"+ show (Encoding #{const SOX_ENCODING_FLOAT_TEXT}) = "encodingFloatText"+ show (Encoding #{const SOX_ENCODING_FLAC }) = "encodingFlac"+ show (Encoding #{const SOX_ENCODING_HCOM }) = "encodingHcom"+ show (Encoding #{const SOX_ENCODING_WAVPACK }) = "encodingWavpack"+ show (Encoding #{const SOX_ENCODING_WAVPACKF }) = "encodingWavpackf"+ show (Encoding #{const SOX_ENCODING_ULAW }) = "encodingUlaw"+ show (Encoding #{const SOX_ENCODING_ALAW }) = "encodingAlaw"+ show (Encoding #{const SOX_ENCODING_G721 }) = "encodingG721"+ show (Encoding #{const SOX_ENCODING_G723 }) = "encodingG723"+ show (Encoding #{const SOX_ENCODING_CL_ADPCM }) = "encodingClADPCM"+ show (Encoding #{const SOX_ENCODING_CL_ADPCM16}) = "encodingClADPCM16"+ show (Encoding #{const SOX_ENCODING_MS_ADPCM }) = "encodingMsADPCM"+ show (Encoding #{const SOX_ENCODING_IMA_ADPCM }) = "encodingImaADPCM"+ show (Encoding #{const SOX_ENCODING_OKI_ADPCM }) = "encodingOkiADPCM"+ show (Encoding #{const SOX_ENCODING_DPCM }) = "encodingDPCM"+ show (Encoding #{const SOX_ENCODING_DWVW }) = "encodingDWVW"+ show (Encoding #{const SOX_ENCODING_DWVWN }) = "encodingDWVWN"+ show (Encoding #{const SOX_ENCODING_GSM }) = "encodingGSM"+ show (Encoding #{const SOX_ENCODING_MP3 }) = "encodingMP3"+ show (Encoding #{const SOX_ENCODING_VORBIS }) = "encodingVorbis"+ show (Encoding #{const SOX_ENCODING_AMR_WB }) = "encodingAmrWB"+ show (Encoding #{const SOX_ENCODING_AMR_NB }) = "encodingAmrNB"+ show (Encoding #{const SOX_ENCODING_CVSD }) = "encodingCVSD"+ show (Encoding #{const SOX_ENCODING_LPC10 }) = "encodingLPC10"+ show (Encoding n) = "(Encoding " ++ show n ++ ")"++++newtype FileType = FileType {unFileType :: String}+type CFileType = CStr.CString+type Sample = #{type sox_sample_t}+type OOB = ()+-- type FormatHandler = ()+type Whence = C.CInt+++foreign import ccall unsafe "sox.h sox_init"+ init :: IO C.CInt++foreign import ccall unsafe "sox.h sox_quit"+ quit :: IO C.CInt++foreign import ccall unsafe "sox.h sox_format_init"+ formatInit :: IO C.CInt++foreign import ccall unsafe "sox.h sox_format_quit"+ formatQuit :: IO ()++foreign import ccall unsafe "sox.h sox_open_read"+ openRead :: CStr.CString -> Ptr SignalInfo -> Ptr EncodingInfo -> CFileType -> IO (Ptr (Format ReadMode))++foreign import ccall safe "sox.h sox_open_write"+ openWrite :: CStr.CString -> Ptr SignalInfo -> Ptr EncodingInfo -> CFileType -> Ptr OOB -> FunPtr (CStr.CString -> IO Bool) -> IO (Ptr (Format WriteMode))++foreign import ccall unsafe "sox.h sox_read"+ read :: Ptr (Format ReadMode) -> Ptr Sample -> C.CSize -> IO C.CSize++foreign import ccall unsafe "sox.h sox_write"+ write :: Ptr (Format WriteMode) -> Ptr Sample -> C.CSize -> IO C.CSize++foreign import ccall unsafe "sox.h sox_close"+ close :: Ptr (Format mode) -> IO C.CInt++foreign import ccall unsafe "sox.h sox_seek"+ seek :: Ptr (Format mode) -> C.CSize -> Whence -> IO C.CInt
+ src/Sound/SoxLib/Template.h view
@@ -0,0 +1,38 @@+#include <stdio.h>++/* http://www.haskell.org/haskellwiki/FFICookBook#Working_with_structs */+#define hsc_alignment(t) \+ printf("(%ld)", (unsigned long)offsetof(struct {char x__; t (y__); }, y__));++#define hsc_inttype(t) \+ printf ("%s%lu", \+ (t)(-1) < (t)0 ? "Int.Int" : "Word.Word", \+ (unsigned long)sizeof (t) * 8); \++#define hsc_intfieldtype(t,f) \+ { \+ t x, y; \+ x.f = -1; \+ y.f = 0; \+ printf ("%s%lu", \+ x.f < y.f ? "Int.Int" : "Word.Word", \+ (unsigned long)sizeof (x.f) * 8); \+ }++#define hsc_peek_int(t, f) \+ { \+ t *x = 0; \+ printf ("(\\hsc_ptr -> fmap fromIntegral (peekByteOff hsc_ptr %ld :: IO ", \+ (long) &(x->f)); \+ hsc_intfieldtype (t, f) \+ printf ("))"); \+ }++#define hsc_poke_int(t, f) \+ { \+ t *x = 0; \+ printf ("(\\hsc_ptr hsc_x -> pokeByteOff hsc_ptr %ld (fromIntegral hsc_x :: ", \+ (long) &(x->f)); \+ hsc_intfieldtype (t, f) \+ printf ("))"); \+ }