hsndfile 0.1.1 → 0.2.0
raw patch · 7 files changed
+137/−78 lines, 7 filesdep ~carrayPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: carray
API changes (from Hackage documentation)
+ Sound.File.Sndfile: Exception :: String -> Exception
+ Sound.File.Sndfile: MalformedFile :: String -> Exception
+ Sound.File.Sndfile: SystemError :: String -> Exception
+ Sound.File.Sndfile: UnrecognisedFormat :: String -> Exception
+ Sound.File.Sndfile: UnsupportedEncoding :: String -> Exception
+ 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))
Files
- Sound/File/Sndfile.hs +5/−2
- Sound/File/Sndfile/Buffer.hs +62/−8
- Sound/File/Sndfile/Buffer/IOCArray.hs +8/−17
- Sound/File/Sndfile/Buffer/Storable.hs +7/−16
- Sound/File/Sndfile/Exception.hs +37/−0
- Sound/File/Sndfile/Interface.chs +3/−25
- hsndfile.cabal +15/−10
Sound/File/Sndfile.hs view
@@ -19,10 +19,12 @@ IOMode(..), openFile, getFileInfo, hFlush, hClose, SeekMode(..), hSeek, hSeekRead, hSeekWrite, -- *I\/O functions- MBuffer(..), interact,+ MBuffer(..),+ hReadSamples, hReadFrames,+ interact, --IBuffer(..), -- *Exception handling- Exception, errorString, catch,+ Exception(..), catch, -- *Header string field access StringType(..), getString, setString ) where@@ -31,6 +33,7 @@ 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,33 +1,53 @@+{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE MultiParamTypeClasses #-} module Sound.File.Sndfile.Buffer ( MBuffer(..), checkSampleBounds, checkFrameBounds,- interact+ 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 ) where -import C2HS import Control.Monad (liftM, when) import Data.Array.Base (unsafeRead, unsafeWrite)-import Data.Array.MArray (Ix, MArray, getBounds)---import Data.Array.IArray (IArray)+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 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 (Exception ("invalid channel/count combination " ++ (show count)))- | (count < 0) || (count > size) = throw (Exception "index out of bounds")+ | (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 (Exception "invalid buffer size")- | (count < 0) || (count > (size `quot` channels)) = throw (Exception "index out of bounds")+ | (size `mod` channels) /= 0 = throw 0 ("invalid buffer size")+ | (count < 0) || (count > (size `quot` channels)) = throw 0 ("index out of bounds") | otherwise = return () +type IOFunc a = HandlePtr -> Ptr a -> CLLong -> IO CLLong++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++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+ -- |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.@@ -78,6 +98,40 @@ -- 'hPutFrames' returns the number of frames written (which should be the same -- as the 'count' parameter). hPutFrames :: Handle -> a Index e -> Count -> m Count++-- 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 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 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+ else do+ when (n' < n) (unsafeWriteRange b (f2s n', si) 0)+ return (Just b)+ 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
Sound/File/Sndfile/Buffer/IOCArray.hs view
@@ -1,16 +1,12 @@-{-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fglasgow-exts #-} module Sound.File.Sndfile.Buffer.IOCArray where import C2HS-import Control.Monad (liftM) import Data.Array.IOCArray import Sound.File.Sndfile.Buffer import Sound.File.Sndfile.Interface -type IOFunc a = HandlePtr -> Ptr a -> CLLong -> IO CLLong- {-# INLINE hIO #-} hIO :: (Storable a) => (Count -> Int -> Count -> IO ())@@ -18,30 +14,25 @@ -> Handle -> (IOCArray Index a) -> Count -> IO Count hIO checkBounds ioFunc (Handle info handle) buffer count = do- size <- liftM rangeSize $ getBounds buffer+ size <- rangeSize `fmap` getBounds buffer checkBounds size (channels info) count result <- withIOCArray buffer $- \ptr -> liftM fromIntegral $ ioFunc handle ptr (cIntConv count)+ \ptr -> fromIntegral `fmap` ioFunc handle ptr (fromIntegral count)+ :: IO Count checkHandle handle touchIOCArray buffer- return $ cIntConv result--foreign import ccall unsafe "sf_read_double" sf_read_double :: IOFunc Double-foreign import ccall unsafe "sf_write_double" sf_write_double :: IOFunc Double+ return $ fromIntegral result instance MBuffer IOCArray Double IO where hGetSamples = hIO checkSampleBounds sf_read_double- hGetFrames = hIO checkFrameBounds sf_read_double+ hGetFrames = hIO checkFrameBounds sf_readf_double hPutSamples = hIO checkSampleBounds sf_write_double- hPutFrames = hIO checkFrameBounds sf_write_double--foreign import ccall unsafe "sf_read_float" sf_read_float :: IOFunc Float-foreign import ccall unsafe "sf_write_float" sf_write_float :: IOFunc Float+ hPutFrames = hIO checkFrameBounds sf_writef_double instance MBuffer IOCArray Float IO where hGetSamples = hIO checkSampleBounds sf_read_float- hGetFrames = hIO checkFrameBounds sf_read_float+ hGetFrames = hIO checkFrameBounds sf_readf_float hPutSamples = hIO checkSampleBounds sf_write_float- hPutFrames = hIO checkFrameBounds sf_write_float+ hPutFrames = hIO checkFrameBounds sf_writef_float -- EOF
Sound/File/Sndfile/Buffer/Storable.hs view
@@ -1,16 +1,12 @@-{-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fglasgow-exts #-} module Sound.File.Sndfile.Buffer.Storable where import C2HS-import Control.Monad (liftM) import Data.Array.Storable import Sound.File.Sndfile.Buffer import Sound.File.Sndfile.Interface -type IOFunc a = HandlePtr -> Ptr a -> CLLong -> IO CLLong- {-# INLINE hIO #-} hIO :: (Storable a) => (Count -> Int -> Count -> IO ())@@ -18,30 +14,25 @@ -> Handle -> (StorableArray Index a) -> Count -> IO Count hIO checkBounds ioFunc (Handle info handle) buffer count = do- size <- liftM rangeSize $ getBounds buffer+ size <- rangeSize `fmap` getBounds buffer checkBounds size (channels info) count result <- withStorableArray buffer $- \ptr -> liftM fromIntegral $ ioFunc handle ptr (cIntConv count)+ \ptr -> fromIntegral `fmap` ioFunc handle ptr (cIntConv count)+ :: IO Count checkHandle handle touchStorableArray buffer return $ cIntConv result -foreign import ccall unsafe "sf_read_double" sf_read_double :: IOFunc Double-foreign import ccall unsafe "sf_write_double" sf_write_double :: IOFunc Double- instance MBuffer StorableArray Double IO where hGetSamples = hIO checkSampleBounds sf_read_double- hGetFrames = hIO checkFrameBounds sf_read_double+ hGetFrames = hIO checkFrameBounds sf_readf_double hPutSamples = hIO checkSampleBounds sf_write_double- hPutFrames = hIO checkFrameBounds sf_write_double--foreign import ccall unsafe "sf_read_float" sf_read_float :: IOFunc Float-foreign import ccall unsafe "sf_write_float" sf_write_float :: IOFunc Float+ hPutFrames = hIO checkFrameBounds sf_writef_double instance MBuffer StorableArray Float IO where hGetSamples = hIO checkSampleBounds sf_read_float- hGetFrames = hIO checkFrameBounds sf_read_float+ hGetFrames = hIO checkFrameBounds sf_readf_float hPutSamples = hIO checkSampleBounds sf_write_float- hPutFrames = hIO checkFrameBounds sf_write_float+ hPutFrames = hIO checkFrameBounds sf_writef_float -- EOF
+ Sound/File/Sndfile/Exception.hs view
@@ -0,0 +1,37 @@+{-# OPTIONS_GHC -fglasgow-exts #-}++module Sound.File.Sndfile.Exception (+ Exception(..),+ catch, throw+) where++import Control.Exception (catchDyn, throwDyn)+import Data.Typeable (Typeable)+import Prelude hiding (catch)++-- |Values of type 'Exception' are thrown by the library when an error occurs.+--+-- Use 'catch' to catch only exceptions of this type.+data Exception =+ Exception { errorString :: String }+ | UnrecognisedFormat { errorString :: String }+ | SystemError { errorString :: String }+ | MalformedFile { errorString :: String }+ | UnsupportedEncoding { errorString :: String }+ deriving (Typeable, Show)++-- | Construct 'Exception' from error code and string.+fromErrorCode :: Int -> String -> Exception+fromErrorCode 1 = UnrecognisedFormat+fromErrorCode 2 = SystemError+fromErrorCode 3 = MalformedFile+fromErrorCode 4 = UnsupportedEncoding+fromErrorCode _ = Exception++-- |Catch values of type 'Exception'.+catch :: IO a -> (Exception -> IO a) -> IO a+catch = catchDyn++-- | Throw 'Exception' according to error code and string+throw :: Int -> String -> a+throw code str = throwDyn (fromErrorCode code str)
Sound/File/Sndfile/Interface.chs view
@@ -1,15 +1,11 @@ {-# LANGUAGE ForeignFunctionInterface #-}-{-# OPTIONS_GHC -fglasgow-exts #-} module Sound.File.Sndfile.Interface where import C2HS import Control.Monad (liftM, when)-import Control.Exception (catchDyn, throwDyn) import Data.Bits-import Data.Int (Int64)-import Data.Typeable (Typeable)-import Prelude hiding (catch)+import qualified Sound.File.Sndfile.Exception as E import System.IO.Unsafe (unsafePerformIO) #include <sndfile.h>@@ -216,29 +212,11 @@ -- ==================================================================== -- Exceptions --- |Values of type 'Exception' are thrown by the library when an error occurs.------ Use 'catch' to catch only exceptions of this type.-data Exception = Exception String deriving (Typeable, Show)---- |Return the error string associated with the 'Exception'.-errorString :: Exception -> String-errorString (Exception s) = s---- |Catch values of type 'Exception'.-catch :: IO a -> (Exception -> IO a) -> IO a-catch = catchDyn--throw :: Exception -> a-throw = throwDyn--raiseError :: Handle -> IO ()-raiseError handle = liftM (throw . Exception) $ (peekCString $ {#call pure sf_strerror#} (hPtr handle))- checkHandle :: HandlePtr -> IO HandlePtr checkHandle handle = do code <- liftM fromIntegral $ {#call unsafe sf_error#} handle- when (code /= 0) $ raiseError (Handle defaultInfo handle)+ when (code /= 0) $+ peekCString ({#call pure sf_strerror#} handle) >>= E.throw code return handle -- ====================================================================
hsndfile.cabal view
@@ -1,6 +1,6 @@ Name: hsndfile-Version: 0.1.1-Category: Sound+Version: 0.2.0+Category: Sound License: GPL License-File: COPYING Copyright: Stefan Kersten, 2007-2008@@ -14,14 +14,19 @@ Libsndfile is a comprehensive C library for reading and writing a large number of soundfile formats: <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-Build-Type: Simple-Build-Depends: array, base, carray, haskell98+Build-Type: Simple+Build-Depends: array, base, carray >= 0.1.2, haskell98+Build-Tools: c2hs >= 0.15 Exposed-Modules: Sound.File.Sndfile-Other-Modules: C2HS,- Sound.File.Sndfile.Buffer,- Sound.File.Sndfile.Buffer.IOCArray,- Sound.File.Sndfile.Buffer.Storable,- Sound.File.Sndfile.Interface-Ghc-Options: -Wall+Other-Modules: C2HS+ Sound.File.Sndfile.Buffer+ Sound.File.Sndfile.Buffer.IOCArray+ Sound.File.Sndfile.Buffer.Storable+ Sound.File.Sndfile.Exception+ Sound.File.Sndfile.Interface+Ghc-Options: -Wall -fno-warn-name-shadowing Extra-Libraries: sndfile