packages feed

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 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 ("))"); \+    }