hsndfile 0.3.3 → 0.4.0
raw patch · 11 files changed
+239/−343 lines, 11 filesdep −arraydep −carraydep ~basePVP ok
version bump matches the API change (PVP)
Dependencies removed: array, carray
Dependency ranges changed: base
API changes (from Hackage documentation)
- Sound.File.Sndfile: class (MArray a e m) => MBuffer a e m
- Sound.File.Sndfile: hGetFrames :: (MBuffer a e m) => Handle -> a Index e -> Count -> m Count
- Sound.File.Sndfile: hGetSamples :: (MBuffer a e m) => Handle -> a Index e -> Count -> m Count
- Sound.File.Sndfile: hPutFrames :: (MBuffer a e m) => Handle -> a Index e -> Count -> m Count
- Sound.File.Sndfile: hPutSamples :: (MBuffer a e m) => Handle -> a Index e -> Count -> m Count
- Sound.File.Sndfile: hReadFrames :: (MBuffer a e m, Num e) => Handle -> Count -> m (Maybe (a Index e))
- Sound.File.Sndfile: hReadSamples :: (MBuffer a e m, Num e) => Handle -> Count -> m (Maybe (a Index e))
- Sound.File.Sndfile: interact :: (MBuffer a e m) => (e -> e) -> a Index e -> Handle -> Handle -> m ()
+ Sound.File.Sndfile: class Buffer a e
+ Sound.File.Sndfile: class Storable e => Sample e
+ Sound.File.Sndfile: fromForeignPtr :: Buffer a e => ForeignPtr e -> Int -> Int -> IO (a e)
+ Sound.File.Sndfile: hGetBuf :: Sample e => Handle -> Ptr e -> Count -> IO Count
+ Sound.File.Sndfile: hGetBuffer :: (Sample e, Storable e, Buffer a e) => Handle -> Count -> IO (Maybe (a e))
+ Sound.File.Sndfile: hGetContentChunks :: (Sample e, Buffer a e) => Count -> Handle -> IO (Info, [a e])
+ Sound.File.Sndfile: hGetContents :: (Sample e, Buffer a e) => Handle -> IO (Info, Maybe (a e))
+ Sound.File.Sndfile: hPutBuf :: Sample e => Handle -> Ptr e -> Count -> IO Count
+ Sound.File.Sndfile: hPutBuffer :: (Sample e, Storable e, Buffer a e) => Handle -> a e -> IO Count
+ Sound.File.Sndfile: readFile :: (Sample e, Buffer a e) => FilePath -> IO (Info, Maybe (a e))
+ Sound.File.Sndfile: readFileChunks :: (Sample e, Buffer a e) => Count -> FilePath -> IO (Info, [a e])
+ Sound.File.Sndfile: toForeignPtr :: Buffer a e => a e -> IO (ForeignPtr e, Int, Int)
+ Sound.File.Sndfile: writeFile :: (Sample e, Buffer a e) => Info -> FilePath -> a e -> IO Count
+ Sound.File.Sndfile.Buffer: class Buffer a e
+ Sound.File.Sndfile.Buffer: class Storable e => Sample e
+ Sound.File.Sndfile.Buffer: fromForeignPtr :: Buffer a e => ForeignPtr e -> Int -> Int -> IO (a e)
+ Sound.File.Sndfile.Buffer: hGetBuf :: Sample e => Handle -> Ptr e -> Count -> IO Count
+ Sound.File.Sndfile.Buffer: hGetBuffer :: (Sample e, Storable e, Buffer a e) => Handle -> Count -> IO (Maybe (a e))
+ Sound.File.Sndfile.Buffer: hGetContentChunks :: (Sample e, Buffer a e) => Count -> Handle -> IO (Info, [a e])
+ Sound.File.Sndfile.Buffer: hGetContents :: (Sample e, Buffer a e) => Handle -> IO (Info, Maybe (a e))
+ Sound.File.Sndfile.Buffer: hPutBuf :: Sample e => Handle -> Ptr e -> Count -> IO Count
+ Sound.File.Sndfile.Buffer: hPutBuffer :: (Sample e, Storable e, Buffer a e) => Handle -> a e -> IO Count
+ Sound.File.Sndfile.Buffer: readFile :: (Sample e, Buffer a e) => FilePath -> IO (Info, Maybe (a e))
+ Sound.File.Sndfile.Buffer: readFileChunks :: (Sample e, Buffer a e) => Count -> FilePath -> IO (Info, [a e])
+ Sound.File.Sndfile.Buffer: toForeignPtr :: Buffer a e => a e -> IO (ForeignPtr e, Int, Int)
+ Sound.File.Sndfile.Buffer: writeFile :: (Sample e, Buffer a e) => Info -> FilePath -> a e -> IO Count
- Sound.File.Sndfile: catch :: IO a -> (Exception -> IO a) -> IO a
+ Sound.File.Sndfile: catch :: Exception e => IO a -> (e -> IO a) -> IO a
Files
- ChangeLog.md +5/−3
- README.md +11/−27
- Sound/File/Sndfile.hs +12/−16
- Sound/File/Sndfile/Buffer.hs +86/−136
- Sound/File/Sndfile/Buffer/IOCArray.hs +0/−36
- Sound/File/Sndfile/Buffer/Internal.hs +36/−0
- Sound/File/Sndfile/Buffer/Sample.hs +40/−0
- Sound/File/Sndfile/Buffer/Storable.hs +0/−36
- Sound/File/Sndfile/Exception.hs +5/−4
- Sound/File/Sndfile/Interface.chs +27/−65
- hsndfile.cabal +17/−20
ChangeLog.md view
@@ -1,7 +1,9 @@-# ChangeLog for hsndfile+### Version 0.4 -## Version 0.3.2+* [__USER__] Simplified Buffer API: A single type class, **Buffer**, is provided for **ForeignPtr** based I/O. Instances are provided in separate packages, e.g. [hsndfile-vector](http://hackage.haskell.org/package/hsndfile-vector). +### Version 0.3.2+ * [__USER__] **hsndfile** has been adapted to compile with GHC 6.10. The only visible change is in exception handling: * `Sound.File.Sndfile.Exception.Exception` is now an instance of@@ -9,7 +11,7 @@ * The new generalized functions from `Control.Exception.Exception` are used for throwing and handling exceptions -## Version 0.2.0+### Version 0.2.0 * [__BUGFIX__] Fix exception throwing Exceptions detected in library code are now actually raised. Exception has been factored into
README.md view
@@ -1,34 +1,18 @@-# HSndfile--HSndfile is a Haskell interface to Eric de Castro Lopo's [libsndfile][1].--# Build requirements--* ghc 6.X.X (tested with ghc-6.8.1)-* c2hs--# Build instructions--Build the library-- $ runhaskell Setup.hs configure- $ runhaskell Setup.hs build--Build the documentation-- $ runhaskell Setup.hs haddock+# hsndfile -# Installation+**hsndfile** is a Haskell interface to Eric de Castro Lopo's [libsndfile][]. For more detailed information please visit [**hsndfile**'s homepage][hsndfile]. - # runhaskell Setup.hs install+The easiest way to install **hsndfile** is by using [cabal-install][]: -# Usage+ cabal install hsndfile -The interface is very similar to [libsndfile's][1] C API, although some-changes were made in order to conform to Haskell naming conventions.+Yes, that's all! If you want to play with the code, you can download the [latest release from hackage][hackage] or get a copy of the darcs repository: -# TODO+ darcs get http://code.haskell.org/hsndfile/ -* TODO: sf_command interface+## Changes -[1]: http://www.mega-nerd.com/libsndfile/+[libsndfile]: http://www.mega-nerd.com/libsndfile/+[hsndfile]: http://haskell.org/haskellwiki/Hsndfile+[hackage]: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hsndfile+[cabal-install]: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/cabal-install
Sound/File/Sndfile.hs view
@@ -1,7 +1,5 @@--- | "Sound.File.Sndfile" provides a Haskell interface to the ubiquitous--- libsndfile library by Erik de Castro Lopo (visit the author's website at--- <http://www.mega-nerd.com/libsndfile/>).-+-- | "Sound.File.Sndfile" provides a Haskell interface to the libsndfile library by Erik de Castro Lopo (visit the libraries's website at <http://www.mega-nerd.com/libsndfile/>).+-- The API is modeled after the original /C/ API, but type and function identifiers follow Haskell naming conventions. module Sound.File.Sndfile ( -- *Types@@ -17,23 +15,21 @@ -- *Stream handle operations Handle, hInfo, hIsSeekable, IOMode(..), openFile, getFileInfo, hFlush, hClose,- SeekMode(..), hSeek, hSeekRead, hSeekWrite,+ SeekMode(..), hSeek, hSeekRead, hSeekWrite -- *I\/O functions- MBuffer(..),- hReadSamples, hReadFrames,- interact,- --IBuffer(..),+ , Sample(..)+ , Buffer(..)+ , hGetBuffer+ , hGetContents, readFile+ , hGetContentChunks, readFileChunks+ , hPutBuffer, writeFile -- *Exception handling- Exception(..), catch,+ , Exception(..), catch -- *Header string field access- StringType(..), getString, setString+ , StringType(..), getString, setString ) where -import Prelude hiding (catch, interact)+import Prelude hiding (catch, interact, readFile, writeFile) import Sound.File.Sndfile.Buffer-import Sound.File.Sndfile.Buffer.Storable ()-import Sound.File.Sndfile.Buffer.IOCArray () import Sound.File.Sndfile.Exception import Sound.File.Sndfile.Interface---- EOF
Sound/File/Sndfile/Buffer.hs view
@@ -1,150 +1,100 @@-module Sound.File.Sndfile.Buffer-(- MBuffer(..),- checkSampleBounds, checkFrameBounds,- hReadSamples, hReadFrames,- interact,- IOFunc,- sf_read_double, sf_readf_double,- sf_write_double, sf_writef_double,- sf_read_float, sf_readf_float,- sf_write_float, sf_writef_float+{-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables #-}+-- | This module provides the 'Buffer' type class that abstracts the array type that is being used for I\/O. For concrete instances see for example the /hsndfile-vector/ package <http://hackage.haskell.org/package/hsndfile-vector>.+module Sound.File.Sndfile.Buffer (+ module Sound.File.Sndfile.Buffer.Sample+ , Buffer(..)+ , hGetBuffer+ , hGetContents+ , readFile+ , hGetContentChunks+ , readFileChunks+ , hPutBuffer+ , writeFile ) where -import Control.Monad (liftM, when)-import Data.Array.Base (unsafeRead, unsafeWrite)-import Data.Array.MArray (Ix, MArray, getBounds, newArray_)-import Data.Ix (rangeSize)-import Foreign.Ptr (Ptr)-import Foreign.C.Types (CLLong)-import Prelude hiding (interact)+import Control.Exception (bracket)+import Foreign+import Prelude hiding (readFile, writeFile) import Sound.File.Sndfile.Exception (throw) import Sound.File.Sndfile.Interface--checkSampleBounds :: (Monad m) => Count -> Int -> Count -> m ()-checkSampleBounds size channels count- | (count `mod` channels) /= 0 = throw 0 ("invalid channel/count combination " ++ (show count))- | (count < 0) || (count > size) = throw 0 ("index out of bounds")- | otherwise = return ()--checkFrameBounds :: (Monad m) => Count -> Int -> Count -> m ()-checkFrameBounds size channels count- | (size `mod` channels) /= 0 = throw 0 ("invalid buffer size")- | (count < 0) || (count > (size `quot` channels)) = throw 0 ("index out of bounds")- | otherwise = return ()+import Sound.File.Sndfile.Buffer.Sample (Sample(..))+import System.IO.Unsafe (unsafeInterleaveIO) -type IOFunc a = HandlePtr -> Ptr a -> CLLong -> IO CLLong+-- | Buffer class for I\/O on soundfile handles.+class Buffer a e where+ -- | Construct a buffer from a 'ForeignPtr', a start index and the element count.+ fromForeignPtr :: ForeignPtr e -> Int -> Int -> IO (a e)+ -- | Retrieve from a buffer a 'ForeignPtr' pointing to its data, a start index and an element count.+ toForeignPtr :: a e -> IO (ForeignPtr e, Int, Int) -foreign import ccall unsafe "sf_read_double" sf_read_double :: IOFunc Double-foreign import ccall unsafe "sf_readf_double" sf_readf_double :: IOFunc Double-foreign import ccall unsafe "sf_write_double" sf_write_double :: IOFunc Double-foreign import ccall unsafe "sf_writef_double" sf_writef_double :: IOFunc Double+-- | Return an buffer with the requested number of frames of data.+-- The resulting buffer size is equal to the product of the number of frames `n' and the number of channels in the soundfile.+hGetBuffer :: forall a e . (Sample e, Storable e, Buffer a e) => Handle -> Count -> IO (Maybe (a e))+hGetBuffer h n = do+ p <- mallocBytes (sizeOf (undefined :: e) * numChannels * n)+ n' <- hGetBuf h p n+ if n' == 0+ then return Nothing+ else do+ fp <- newForeignPtr_ p+ Just `fmap` fromForeignPtr fp 0 (n * numChannels)+ where+ numChannels = (channels.hInfo) h -foreign import ccall unsafe "sf_read_float" sf_read_float :: IOFunc Float-foreign import ccall unsafe "sf_readf_float" sf_readf_float :: IOFunc Float-foreign import ccall unsafe "sf_write_float" sf_write_float :: IOFunc Float-foreign import ccall unsafe "sf_writef_float" sf_writef_float :: IOFunc Float+-- | Return the contents of a handle open for reading in a single buffer.+hGetContents :: (Sample e, Buffer a e) => Handle -> IO (Info, Maybe (a e))+hGetContents h = (,) info `fmap` hGetBuffer h (frames info)+ where info = hInfo h --- |The class MBuffer is used for polymorphic I\/O on a 'Handle', and is--- parameterized on the mutable array type, the element type and the monad--- results are returned in.------ It is important to note that the data type used by the calling program and--- the data format of the file do not need to be the same. For instance, it is--- possible to open a 16 bit PCM encoded WAV file and read the data in--- floating point format. The library seamlessly converts between the two--- formats on-the-fly; the Haskell interface only supports reading and writing--- 'Double' or 'Float' values.------ When converting between integer data and floating point data, the following--- rules apply: The default behaviour when reading floating point data--- ('hGetSamples' or 'hGetFrames') from a file with integer data is--- normalisation. Regardless of whether data in the file is 8, 16, 24 or 32--- bit wide, the data will be read as floating point data in the range--- [-1.0, 1.0]. Similarly, data in the range [-1.0, 1.0] will be written to an--- integer PCM file so that a data value of 1.0 will be the largest allowable--- integer for the given bit width. This normalisation can be turned on or off--- using the command interface [TODO: implementation missing in Haskell].------ 'hGetSamples' and 'hGetFrames' return the number of items read. Unless the--- end of the file was reached during the read, the return value should equal--- the number of items requested. Attempts to read beyond the end of the file--- will not result in an error but will cause the read functions to return--- less than the number of items requested or 0 if already at the end of the--- file.-class (MArray a e m) => MBuffer a e m where- -- |Fill the destination array with the requested number of items. The 'count'- -- parameter must be an integer product of the number of channels or an error- -- will occur.- hGetSamples :: Handle -> a Index e -> Count -> m Count- -- |Fill the destination array with the requested number of frames of data.- -- The array must be large enough to hold the product of frames and the number- -- of channels or an error will occur.- hGetFrames :: Handle -> a Index e -> Count -> m Count- -- |Write 'count' samples from the source array to the stream. The 'count'- -- parameter must be an integer product of the number of channels or an error- -- will occur.- --- -- 'hPutSamples' returns the number of items written (which should be the same- -- as the 'count' parameter).- hPutSamples :: Handle -> a Index e -> Count -> m Count- -- |Write 'count' frames from the source array to the stream.- -- The array must be large enough to hold the product of frames and the number- -- of channels or an error will occur.- --- -- 'hPutFrames' returns the number of frames written (which should be the same- -- as the 'count' parameter).- hPutFrames :: Handle -> a Index e -> Count -> m Count+-- | Return the contents of a handle open for reading as a lazy list of buffers.+hGetContentChunks :: (Sample e, Buffer a e) => Count -> Handle -> IO (Info, [a e])+hGetContentChunks n h = (,) (hInfo h) `fmap` lazyread+ where+ {-# NOINLINE lazyread #-}+ lazyread = unsafeInterleaveIO loop+ loop = do+ r <- hGetBuffer h n+ case r of+ Just b -> do+ bs <- lazyread+ return (b:bs)+ Nothing -> return [] --- TODO: Optimize unsafeWriteRange-unsafeWriteRange :: (MArray a e m) => a Int e -> (Int, Int) -> e -> m ()-unsafeWriteRange _ (i0, i) _ | i0 > i = return ()-unsafeWriteRange a (i0, i) e = unsafeWrite a i0 e >> unsafeWriteRange a (i0+1,i) e+-- | Return the contents of a file in a single buffer.+readFile :: (Sample e, Buffer a e) => FilePath -> IO (Info, Maybe (a e))+readFile path = do+ bracket+ (openFile path ReadMode defaultInfo)+ (hClose)+ (hGetContents) --- |Return an array with the requested number of items. The 'count' parameter--- must be an integer product of the number of channels or an error will--- occur.-hReadSamples :: (MBuffer a e m, Num e) => Handle -> Count -> m (Maybe (a Index e))-hReadSamples h n = do- b <- newArray_ (0, n-1)- n' <- hGetSamples h b n- if n' == 0- then return Nothing- else do- when (n' < n) (unsafeWriteRange b (n',n-1) 0)- return (Just b)+-- | Return the contents of a file as a lazy list of buffers.+readFileChunks :: (Sample e, Buffer a e) => Count -> FilePath -> IO (Info, [a e])+readFileChunks n path = do+ bracket+ (openFile path ReadMode defaultInfo)+ (hClose)+ (hGetContentChunks n) --- |Return an array with the requested number of frames of data.--- The resulting array size is equal to the product of the number of frames--- `n' and the number of channels in the soundfile.-hReadFrames :: (MBuffer a e m, Num e) => Handle -> Count -> m (Maybe (a Index e))-hReadFrames h n = do- b <- newArray_ (0, si)- n' <- hGetFrames h b n- if n' == 0- then return Nothing+-- | Write the contents of a buffer to a handle open for writing.+-- Return the number of frames written.+hPutBuffer :: forall a e . (Sample e, Storable e, Buffer a e) => Handle -> a e -> IO Count+hPutBuffer h buffer = do+ (fp, i, n) <- toForeignPtr buffer+ if n `mod` numChannels /= 0+ then throw 0 "hPutBuffer: invalid buffer size (not a multiple of channel count)" else do- when (n' < n) (unsafeWriteRange b (f2s n', si) 0)- return (Just b)+ withForeignPtr fp $ \ptr -> do+ let p = plusPtr ptr (sizeOf (undefined :: e) * i) :: Ptr e+ hPutBuf h p (n `div` numChannels) where- f2s = (* channels (hInfo h))- si = (f2s n) - 1--modifyArray :: (MArray a e m, Ix i) => (e -> e) -> a i e -> Int -> Int -> m ()-modifyArray f a i n- | i >= n = return ()- | otherwise = do- e <- unsafeRead a i- unsafeWrite a i (f e)- modifyArray f a (i+1) n--interact :: (MBuffer a e m) => (e -> e) -> a Index e -> Handle -> Handle -> m ()-interact f buffer hIn hOut = do- s <- liftM rangeSize $ getBounds buffer- n <- hGetSamples hIn buffer s- when (n > 0) $ do- modifyArray f buffer 0 n- hPutSamples hOut buffer n- interact f buffer hIn hOut+ numChannels = channels $ hInfo h --- EOF+-- | Write the contents of a buffer to a file.+-- Return the number of frames written.+writeFile :: (Sample e, Buffer a e) => Info -> FilePath -> a e -> IO Count+writeFile info path buffer = do+ bracket+ (openFile path WriteMode info)+ (hClose)+ (flip hPutBuffer buffer)
− Sound/File/Sndfile/Buffer/IOCArray.hs
@@ -1,36 +0,0 @@-module Sound.File.Sndfile.Buffer.IOCArray where--import C2HS-import Data.Array.IOCArray-import Sound.File.Sndfile.Buffer-import Sound.File.Sndfile.Interface--{-# INLINE hIO #-}-hIO :: (Storable a) =>- (Count -> Int -> Count -> IO ())- -> IOFunc a- -> Handle -> (IOCArray Index a) -> Count- -> IO Count-hIO checkBounds ioFunc (Handle info handle) buffer count = do- size <- rangeSize `fmap` getBounds buffer- checkBounds size (channels info) count- result <- withIOCArray buffer $- \ptr -> fromIntegral `fmap` ioFunc handle ptr (fromIntegral count)- :: IO Count- checkHandle handle- touchIOCArray buffer- return $ fromIntegral result--instance MBuffer IOCArray Double IO where- hGetSamples = hIO checkSampleBounds sf_read_double- hGetFrames = hIO checkFrameBounds sf_readf_double- hPutSamples = hIO checkSampleBounds sf_write_double- hPutFrames = hIO checkFrameBounds sf_writef_double--instance MBuffer IOCArray Float IO where- hGetSamples = hIO checkSampleBounds sf_read_float- hGetFrames = hIO checkFrameBounds sf_readf_float- hPutSamples = hIO checkSampleBounds sf_write_float- hPutFrames = hIO checkFrameBounds sf_writef_float---- EOF
+ Sound/File/Sndfile/Buffer/Internal.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Sound.File.Sndfile.Buffer.Internal+(+ IOFunc+ , hBufIO+ , sf_readf_word16+ , sf_writef_word16+ , sf_readf_word32+ , sf_writef_word32+ , sf_readf_float+ , sf_writef_float+ , sf_readf_double+ , sf_writef_double+) where++import Data.Word (Word16, Word32)+import Foreign.Ptr (Ptr)+import Foreign.C.Types (CLLong)+import Sound.File.Sndfile.Interface (Count, Handle(..), HandlePtr)++type IOFunc a = HandlePtr -> Ptr a -> CLLong -> IO CLLong++hBufIO :: IOFunc a -> Handle -> Ptr a -> Count -> IO Count+hBufIO f h ptr = fmap fromIntegral . f (hPtr h) ptr . fromIntegral++foreign import ccall unsafe "sf_readf_short" sf_readf_word16 :: IOFunc Word16+foreign import ccall unsafe "sf_writef_short" sf_writef_word16 :: IOFunc Word16++foreign import ccall unsafe "sf_readf_int" sf_readf_word32 :: IOFunc Word32+foreign import ccall unsafe "sf_writef_int" sf_writef_word32 :: IOFunc Word32++foreign import ccall unsafe "sf_readf_float" sf_readf_float :: IOFunc Float+foreign import ccall unsafe "sf_writef_float" sf_writef_float :: IOFunc Float++foreign import ccall unsafe "sf_readf_double" sf_readf_double :: IOFunc Double+foreign import ccall unsafe "sf_writef_double" sf_writef_double :: IOFunc Double
+ Sound/File/Sndfile/Buffer/Sample.hs view
@@ -0,0 +1,40 @@+module Sound.File.Sndfile.Buffer.Sample (+ Sample(..)+) where++import Data.Word (Word16, Word32)+import Foreign.Ptr (Ptr)+import Foreign.Storable (Storable)+import Prelude hiding (interact)+import Sound.File.Sndfile.Buffer.Internal+import Sound.File.Sndfile.Interface++-- |The class Sample is used for polymorphic I\/O on a 'Handle', and is parameterized with the element type that is to be read from a file.+--+-- It is important to note that the data type used by the calling program and the data format of the file do not need to be the same. For instance, it is possible to open a 16 bit PCM encoded WAV file and read the data in floating point format. The library seamlessly converts between the two formats on-the-fly; the Haskell interface currently supports reading and writing 'Double' or 'Float' floating point values, as well as 'Word16' and 'Word32' integer values.+--+-- When converting between integer data and floating point data, the following rules apply: The default behaviour when reading floating point data from a file with integer data is normalisation. Regardless of whether data in the file is 8, 16, 24 or 32 bit wide, the data will be read as floating point data in the range [-1.0, 1.0]. Similarly, data in the range [-1.0, 1.0] will be written to an integer PCM file so that a data value of 1.0 will be the largest allowable integer for the given bit width. This normalisation can be turned on or off using the command interface (/implementation missing in Haskell/).+--+-- 'hGetSamples' and 'hGetFrames' return the number of items read. Unless the end of the file was reached during the read, the return value should equal the number of items requested. Attempts to read beyond the end of the file will not result in an error but will cause the read functions to return less than the number of items requested or 0 if already at the end of the file.++class Storable e => Sample e where+ -- | Read a buffer of frames.+ hGetBuf :: Handle -> Ptr e -> Count -> IO Count+ -- | Write a buffer of frames.+ hPutBuf :: Handle -> Ptr e -> Count -> IO Count++instance Sample Word16 where+ hGetBuf = hBufIO sf_readf_word16+ hPutBuf = hBufIO sf_writef_word16++instance Sample Word32 where+ hGetBuf = hBufIO sf_readf_word32+ hPutBuf = hBufIO sf_writef_word32++instance Sample Float where+ hGetBuf = hBufIO sf_readf_float+ hPutBuf = hBufIO sf_writef_float++instance Sample Double where+ hGetBuf = hBufIO sf_readf_double+ hPutBuf = hBufIO sf_writef_double
− Sound/File/Sndfile/Buffer/Storable.hs
@@ -1,36 +0,0 @@-module Sound.File.Sndfile.Buffer.Storable where--import C2HS-import Data.Array.Storable-import Sound.File.Sndfile.Buffer-import Sound.File.Sndfile.Interface--{-# INLINE hIO #-}-hIO :: (Storable a) =>- (Count -> Int -> Count -> IO ())- -> IOFunc a- -> Handle -> (StorableArray Index a) -> Count- -> IO Count-hIO checkBounds ioFunc (Handle info handle) buffer count = do- size <- rangeSize `fmap` getBounds buffer- checkBounds size (channels info) count- result <- withStorableArray buffer $- \ptr -> fromIntegral `fmap` ioFunc handle ptr (cIntConv count)- :: IO Count- checkHandle handle- touchStorableArray buffer- return $ cIntConv result--instance MBuffer StorableArray Double IO where- hGetSamples = hIO checkSampleBounds sf_read_double- hGetFrames = hIO checkFrameBounds sf_readf_double- hPutSamples = hIO checkSampleBounds sf_write_double- hPutFrames = hIO checkFrameBounds sf_writef_double--instance MBuffer StorableArray Float IO where- hGetSamples = hIO checkSampleBounds sf_read_float- hGetFrames = hIO checkFrameBounds sf_readf_float- hPutSamples = hIO checkSampleBounds sf_write_float- hPutFrames = hIO checkFrameBounds sf_writef_float---- EOF
Sound/File/Sndfile/Exception.hs view
@@ -1,9 +1,10 @@+{-# LANGUAGE DeriveDataTypeable #-} module Sound.File.Sndfile.Exception ( Exception(..),- catch, throw+ catch, try, throw ) where -import Control.Exception (fromException, toException, SomeException(..))+import Control.Exception (SomeException(..), catch, fromException, toException, try) import qualified Control.Exception as E import Data.Typeable (Typeable) import Prelude hiding (catch)@@ -32,8 +33,8 @@ fromErrorCode _ = Exception -- |Catch values of type 'Exception'.-catch :: IO a -> (Exception -> IO a) -> IO a-catch = E.catch+-- catch :: IO a -> (Exception -> IO a) -> IO a+-- catch = E.catch -- | Throw 'Exception' according to error code and string throw :: Int -> String -> a
Sound/File/Sndfile/Interface.chs view
@@ -1,10 +1,11 @@+{-# LANGUAGE ForeignFunctionInterface #-} module Sound.File.Sndfile.Interface where import C2HS-import Control.Monad (liftM, when)-import Data.Bits-import qualified Sound.File.Sndfile.Exception as E-import System.IO.Unsafe (unsafePerformIO)+import Control.Monad (liftM, when)+import Data.Bits ((.|.), (.&.))+import qualified Sound.File.Sndfile.Exception as E+import System.IO.Unsafe (unsafePerformIO) #include <sndfile.h> @@ -13,7 +14,6 @@ -- ==================================================================== -- Basic types - -- | Type for expressing sample counts. type Count = Int @@ -116,11 +116,9 @@ }; #endc --- |Stream format specification, consisting of header, sample and endianness--- formats.+-- |Stream format specification, consisting of header, sample and endianness formats. ----- Not all combinations of header, sample and endianness formats are valid;--- valid combinamtions can be checked with the 'checkFormat' function.+-- Not all combinations of header, sample and endianness formats are valid; valid combinamtions can be checked with the 'checkFormat' function. data Format = Format { headerFormat :: HeaderFormat, sampleFormat :: SampleFormat,@@ -151,8 +149,7 @@ -- ==================================================================== -- Info --- |The 'Info' structure is for passing data between the calling function and--- the library when opening a stream for reading or writing.+-- |The 'Info' structure is for passing data between the calling function and the library when opening a stream for reading or writing. data Info = Info { frames :: Count, -- ^Number of frames in file samplerate :: Int, -- ^Audio sample rate@@ -162,8 +159,7 @@ seekable :: Bool -- ^'True' when stream is seekable (e.g. local files) } deriving (Eq, Show) --- |Return soundfile duration in seconds computed via the 'Info' fields--- 'frames' and 'samplerate'.+-- |Return soundfile duration in seconds computed via the 'Info' fields 'frames' and 'samplerate'. duration :: Info -> Double duration info = (fromIntegral $ frames info) / (fromIntegral $ samplerate info) @@ -171,8 +167,7 @@ defaultInfo :: Info defaultInfo = Info 0 0 0 defaultFormat 0 False --- |This function allows the caller to check if a set of parameters in the--- 'Info' struct is valid before calling 'openFile' ('WriteMode').+-- |This function allows the caller to check if a set of parameters in the 'Info' struct is valid before calling 'openFile' ('WriteMode'). -- -- 'checkFormat' returns 'True' if the parameters are valid and 'False' otherwise. @@ -242,22 +237,13 @@ }; #endc --- |When opening a file for read ('ReadMode'), the format field should be set--- to 'defaultFormat' before calling 'openFile'. The only exception to this is--- the case of RAW files, where the caller has to set the samplerate, channels--- and format fields to valid values. All other fields of the structure are--- filled in by the library.+-- |When opening a file for read ('ReadMode'), the format field should be set to 'defaultFormat' before calling 'openFile'. The only exception to this is the case of RAW files, where the caller has to set the samplerate, channels and format fields to valid values. All other fields of the structure are filled in by the library. ----- When opening a file for write ('WriteMode'), the caller must fill in the--- structure members samplerate, channels, and format.+-- When opening a file for write ('WriteMode'), the caller must fill in the structure members samplerate, channels, and format. ----- Every call to 'openFile' should be matched with a call to 'hClose' to free--- up memory allocated during the call to 'openFile'.+-- Every call to 'openFile' should be matched with a call to 'hClose' to free up memory allocated during the call to 'openFile'. ----- On success, the 'openFile' function returns a 'Handle' which should be--- passed as the first parameter to all subsequent libsndfile calls dealing--- with that audio stream. On fail, the 'openFile' function signals an--- 'Exception'.+-- On success, the 'openFile' function returns a 'Handle' which should be passed as the first parameter to all subsequent libsndfile calls dealing with that audio stream. On fail, the 'openFile' function signals an 'Exception'. openFile :: FilePath -> IOMode -> Info -> IO Handle openFile filePath ioMode info = withCString filePath (\cFilePath ->@@ -268,17 +254,14 @@ newInfo <- peek cInfo return $ Handle newInfo cHandle)) --- |The 'hClose' function closes the stream, deallocates its internal buffers--- and returns () on success or signals an 'Exception' otherwise.+-- | The 'hClose' function closes the stream, deallocates its internal buffers and returns () on success or signals an 'Exception' otherwise. hClose :: Handle -> IO () hClose handle = do {#call unsafe sf_close#} $ hPtr handle checkHandle nullPtr return () --- |If the stream is opened with 'WriteMode' or 'ReadWriteMode', call the--- operating system\'s function to force the writing of all file cache buffers--- to disk. If the file is opened with 'ReadMode' no action is taken.+-- | If the stream is opened with 'WriteMode' or 'ReadWriteMode', call the operating system\'s function to force the writing of all file cache buffers to disk. If the file is opened with 'ReadMode' no action is taken. hFlush :: Handle -> IO () hFlush (Handle _ handle) = {#call unsafe sf_write_sync#} handle @@ -306,8 +289,7 @@ }; #endc --- Helper function for seeking, modifying either the read pointer, the write--- pointer, or both.+-- Helper function for seeking, modifying either the read pointer, the write pointer, or both. {-# INLINE hSeek' #-} hSeek' :: Maybe IOMode -> Handle -> SeekMode -> Count -> IO Count hSeek' ioMode (Handle _ handle) seekMode frames = do@@ -321,37 +303,21 @@ checkHandle handle return n --- |The file seek functions work much like 'System.IO.hseek' with the--- exception that the non-audio data is ignored and the seek only moves within--- the audio data section of the file. In addition, seeks are defined in--- number of (multichannel) frames. Therefore, a seek in a stereo file from--- the current position forward with an offset of 1 would skip forward by one--- sample of both channels.+-- |The file seek functions work much like 'System.IO.hseek' with the exception that the non-audio data is ignored and the seek only moves within the audio data section of the file. In addition, seeks are defined in number of (multichannel) frames. Therefore, a seek in a stereo file from the current position forward with an offset of 1 would skip forward by one sample of both channels. ----- like lseek(), the whence parameter can be any one of the following three--- values:+-- like lseek(), the whence parameter can be any one of the following three values: ----- * 'AbsoluteSeek' - The offset is set to the start of the audio data plus--- offset (multichannel) frames.+-- * 'AbsoluteSeek' - The offset is set to the start of the audio data plus offset (multichannel) frames. ----- * 'RelativeSeek' - The offset is set to its current location plus offset--- (multichannel) frames.+-- * 'RelativeSeek' - The offset is set to its current location plus offset (multichannel) frames. ----- * 'SeekFromEnd' - The offset is set to the end of the data plus offset--- (multichannel) frames.+-- * 'SeekFromEnd' - The offset is set to the end of the data plus offset (multichannel) frames. ----- Internally, libsndfile keeps track of the read and write locations using--- separate read and write pointers. If a file has been opened with a mode of--- 'ReadWriteMode', calling either 'hSeekRead' or 'hSeekWrite' allows the read--- and write pointers to be modified separately. 'hSeek' modifies both the--- read and the write pointer.+-- Internally, libsndfile keeps track of the read and write locations using separate read and write pointers. If a file has been opened with a mode of 'ReadWriteMode', calling either 'hSeekRead' or 'hSeekWrite' allows the read and write pointers to be modified separately. 'hSeek' modifies both the read and the write pointer. -- --- Note that the frames offset can be negative and in fact should be when--- SeekFromEnd is used for the whence parameter.+-- Note that the frames offset can be negative and in fact should be when SeekFromEnd is used for the whence parameter. -- --- 'hSeek' will return the offset in (multichannel) frames from the start of--- the audio data, or signal an error when an attempt is made to seek beyond--- the start or end of the file.+-- 'hSeek' will return the offset in (multichannel) frames from the start of the audio data, or signal an error when an attempt is made to seek beyond the start or end of the file. hSeek :: Handle -> SeekMode -> Count -> IO Count hSeek = hSeek' Nothing@@ -386,8 +352,7 @@ }; #endc --- |The 'getString' function returns the specificed string from the stream--- header in the 'Maybe' monad if it exists and 'Nothing' otherwise.+-- |The 'getString' function returns the specificed string from the stream header in the 'Maybe' monad if it exists and 'Nothing' otherwise. getString :: Handle -> StringType -> IO (Maybe String) getString (Handle _ handle) t = do ptr <- {#call unsafe sf_get_string#} handle (cFromEnum t)@@ -396,13 +361,10 @@ else liftM Just $ peekCString =<< (return ptr) --- |The 'setString' function sets the string data associated with the--- respective 'StringType'.+-- |The 'setString' function sets the string data associated with the respective 'StringType'. setString :: Handle -> StringType -> String -> IO () setString (Handle _ handle) t s = withCString s (\cs -> do {#call unsafe sf_set_string#} handle (cFromEnum t) cs checkHandle handle return ())---- EOF
hsndfile.cabal view
@@ -1,25 +1,20 @@ name: hsndfile-version: 0.3.3-category: Sound+version: 0.4.0+category: Data, Sound license: GPL license-file: COPYING-copyright: Stefan Kersten, 2007-2008+copyright: Stefan Kersten, 2007-2010 author: Stefan Kersten maintainer: Stefan Kersten <sk@k-hornz.de> stability: Experimental-homepage: http://darcs.k-hornz.de/cgi-bin/darcsweb.cgi?r=hsndfile;a=summary+homepage: http://haskell.org/haskellwiki/Hsndfile synopsis: Haskell bindings for libsndfile-description: Haskell bindings for libsndfile.- .- Libsndfile is a comprehensive C library for reading- and writing a large number of soundfile formats:- <http://www.mega-nerd.com/libsndfile/>.+description: Haskell bindings for /libsndfile/, a comprehensive C library for reading and writing a large number of soundfile formats by Erik de Castro Lopo (<http://www.mega-nerd.com/libsndfile/>). .- Changelog and source tarballs can be found at- <http://space.k-hornz.de/files/software/hsndfile>-tested-with: GHC+ For more information on /hsndfile/ visit its homepage at <http://haskell.org/haskellwiki/Hsndfile>.+tested-with: GHC==6.8.*, GHC==6.10.1, GHC==6.10.4 build-type: Simple-cabal-version: >= 1.2+cabal-version: >= 1.6 extra-source-files: ChangeLog.md@@ -27,19 +22,21 @@ libsndfile/sndfile.h library- build-depends: array, base >= 4.0.0.0, carray >= 0.1.2, haskell98+ build-depends: base >= 4 && < 5,+ haskell98 build-tools: c2hs >= 0.15- extensions: DeriveDataTypeable- ForeignFunctionInterface- MultiParamTypeClasses exposed-modules: Sound.File.Sndfile- other-modules: C2HS Sound.File.Sndfile.Buffer- Sound.File.Sndfile.Buffer.IOCArray- Sound.File.Sndfile.Buffer.Storable+ other-modules: C2HS+ Sound.File.Sndfile.Buffer.Internal+ Sound.File.Sndfile.Buffer.Sample Sound.File.Sndfile.Exception Sound.File.Sndfile.Interface ghc-options: -Wall -fno-warn-name-shadowing extra-libraries: sndfile if os(windows) include-dirs: libsndfile++source-repository head+ type: darcs+ location: http://code.haskell.org/hsndfile