hsndfile (empty) → 0.1.1
raw patch · 9 files changed
+1247/−0 lines, 9 filesdep +arraydep +basedep +carraysetup-changed
Dependencies added: array, base, carray, haskell98
Files
- C2HS.hs +220/−0
- COPYING +339/−0
- Setup.hs +4/−0
- Sound/File/Sndfile.hs +36/−0
- Sound/File/Sndfile/Buffer.hs +99/−0
- Sound/File/Sndfile/Buffer/IOCArray.hs +47/−0
- Sound/File/Sndfile/Buffer/Storable.hs +47/−0
- Sound/File/Sndfile/Interface.chs +428/−0
- hsndfile.cabal +27/−0
+ C2HS.hs view
@@ -0,0 +1,220 @@+-- C->Haskell Compiler: Marshalling library+--+-- Copyright (c) [1999...2005] Manuel M T Chakravarty+--+-- 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.+--+--- Description ---------------------------------------------------------------+--+-- Language: Haskell 98+--+-- This module provides the marshaling routines for Haskell files produced by +-- C->Haskell for binding to C library interfaces. It exports all of the+-- low-level FFI (language-independent plus the C-specific parts) together+-- with the C->HS-specific higher-level marshalling routines.+--++module C2HS (++ -- * Re-export the language-independent component of the FFI + module Foreign,++ -- * Re-export the C language component of the FFI+ module CForeign,++ -- * Composite marshalling functions+ withCStringLenIntConv, peekCStringLenIntConv, withIntConv, withFloatConv,+ peekIntConv, peekFloatConv, withBool, peekBool, withEnum, peekEnum,++ -- * Conditional results using 'Maybe'+ nothingIf, nothingIfNull,++ -- * Bit masks+ combineBitMasks, containsBitMask, extractBitMasks,++ -- * Conversion between C and Haskell types+ cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum+) where +++import Foreign+ hiding (Word)+ -- Should also hide the Foreign.Marshal.Pool exports in+ -- compilers that export them+import CForeign++import Monad (when, liftM)+++-- Composite marshalling functions+-- -------------------------------++-- Strings with explicit length+--+withCStringLenIntConv s f = withCStringLen s $ \(p, n) -> f (p, cIntConv n)+peekCStringLenIntConv (s, n) = peekCStringLen (s, cIntConv n)++-- Marshalling of numerals+--++withIntConv :: (Storable b, Integral a, Integral b) + => a -> (Ptr b -> IO c) -> IO c+withIntConv = with . cIntConv++withFloatConv :: (Storable b, RealFloat a, RealFloat b) + => a -> (Ptr b -> IO c) -> IO c+withFloatConv = with . cFloatConv++peekIntConv :: (Storable a, Integral a, Integral b) + => Ptr a -> IO b+peekIntConv = liftM cIntConv . peek++peekFloatConv :: (Storable a, RealFloat a, RealFloat b) + => Ptr a -> IO b+peekFloatConv = liftM cFloatConv . peek++-- Passing Booleans by reference+--++withBool :: (Integral a, Storable a) => Bool -> (Ptr a -> IO b) -> IO b+withBool = with . fromBool++peekBool :: (Integral a, Storable a) => Ptr a -> IO Bool+peekBool = liftM toBool . peek+++-- Passing enums by reference+--++withEnum :: (Enum a, Integral b, Storable b) => a -> (Ptr b -> IO c) -> IO c+withEnum = with . cFromEnum++peekEnum :: (Enum a, Integral b, Storable b) => Ptr b -> IO a+peekEnum = liftM cToEnum . peek+++-- Storing of 'Maybe' values+-- -------------------------++instance Storable a => Storable (Maybe a) where+ sizeOf _ = sizeOf (undefined :: Ptr ())+ alignment _ = alignment (undefined :: Ptr ())++ peek p = do+ ptr <- peek (castPtr p)+ if ptr == nullPtr+ then return Nothing+ else liftM Just $ peek ptr++ poke p v = do+ ptr <- case v of+ Nothing -> return nullPtr+ Just v' -> new v'+ poke (castPtr p) ptr+++-- Conditional results using 'Maybe'+-- ---------------------------------++-- Wrap the result into a 'Maybe' type.+--+-- * the predicate determines when the result is considered to be non-existing,+-- ie, it is represented by `Nothing'+--+-- * the second argument allows to map a result wrapped into `Just' to some+-- other domain+--+nothingIf :: (a -> Bool) -> (a -> b) -> a -> Maybe b+nothingIf p f x = if p x then Nothing else Just $ f x++-- |Instance for special casing null pointers.+--+nothingIfNull :: (Ptr a -> b) -> Ptr a -> Maybe b+nothingIfNull = nothingIf (== nullPtr)+++-- Support for bit masks+-- ---------------------++-- Given a list of enumeration values that represent bit masks, combine these+-- masks using bitwise disjunction.+--+combineBitMasks :: (Enum a, Bits b) => [a] -> b+combineBitMasks = foldl (.|.) 0 . map (fromIntegral . fromEnum)++-- Tests whether the given bit mask is contained in the given bit pattern+-- (i.e., all bits set in the mask are also set in the pattern).+--+containsBitMask :: (Bits a, Enum b) => a -> b -> Bool+bits `containsBitMask` bm = let bm' = fromIntegral . fromEnum $ bm+ in+ bm' .&. bits == bm'++-- |Given a bit pattern, yield all bit masks that it contains.+--+-- * This does *not* attempt to compute a minimal set of bit masks that when+-- combined yield the bit pattern, instead all contained bit masks are+-- produced.+--+extractBitMasks :: (Bits a, Enum b, Bounded b) => a -> [b]+extractBitMasks bits = + [bm | bm <- [minBound..maxBound], bits `containsBitMask` bm]+++-- Conversion routines+-- -------------------++-- |Integral conversion+--+cIntConv :: (Integral a, Integral b) => a -> b+cIntConv = fromIntegral++-- |Floating conversion+--+cFloatConv :: (RealFloat a, RealFloat b) => a -> b+cFloatConv = realToFrac+-- As this conversion by default goes via `Rational', it can be very slow...+{-# RULES + "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;+ "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x+ #-}++-- |Obtain C value from Haskell 'Bool'.+--+cFromBool :: Num a => Bool -> a+cFromBool = fromBool++-- |Obtain Haskell 'Bool' from C value.+--+cToBool :: Num a => a -> Bool+cToBool = toBool++-- |Convert a C enumeration to Haskell.+--+cToEnum :: (Integral i, Enum e) => i -> e+cToEnum = toEnum . cIntConv++-- |Convert a Haskell enumeration to C.+--+cFromEnum :: (Enum e, Integral i) => e -> i+cFromEnum = cIntConv . fromEnum
+ COPYING view
@@ -0,0 +1,339 @@+ GNU GENERAL PUBLIC LICENSE+ Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The licenses for most software are designed to take away your+freedom to share and change it. By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users. This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it. (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.) You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++ To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have. You must make sure that they, too, receive or can get the+source code. And you must show them these terms so they know their+rights.++ We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++ Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software. If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++ Finally, any free program is threatened constantly by software+patents. We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary. To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++ The precise terms and conditions for copying, distribution and+modification follow.++ GNU GENERAL PUBLIC LICENSE+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++ 0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License. The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language. (Hereinafter, translation is included without limitation in+the term "modification".) Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope. The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++ 1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++ 2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++ a) You must cause the modified files to carry prominent notices+ stating that you changed the files and the date of any change.++ b) You must cause any work that you distribute or publish, that in+ whole or in part contains or is derived from the Program or any+ part thereof, to be licensed as a whole at no charge to all third+ parties under the terms of this License.++ c) If the modified program normally reads commands interactively+ when run, you must cause it, when started running for such+ interactive use in the most ordinary way, to print or display an+ announcement including an appropriate copyright notice and a+ notice that there is no warranty (or else, saying that you provide+ a warranty) and that users may redistribute the program under+ these conditions, and telling the user how to view a copy of this+ License. (Exception: if the Program itself is interactive but+ does not normally print such an announcement, your work based on+ the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole. If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works. But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++ 3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++ a) Accompany it with the complete corresponding machine-readable+ source code, which must be distributed under the terms of Sections+ 1 and 2 above on a medium customarily used for software interchange; or,++ b) Accompany it with a written offer, valid for at least three+ years, to give any third party, for a charge no more than your+ cost of physically performing source distribution, a complete+ machine-readable copy of the corresponding source code, to be+ distributed under the terms of Sections 1 and 2 above on a medium+ customarily used for software interchange; or,++ c) Accompany it with the information you received as to the offer+ to distribute corresponding source code. (This alternative is+ allowed only for noncommercial distribution and only if you+ received the program in object code or executable form with such+ an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it. For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable. However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++ 4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License. Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++ 5. You are not required to accept this License, since you have not+signed it. However, nothing else grants you permission to modify or+distribute the Program or its derivative works. These actions are+prohibited by law if you do not accept this License. Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++ 6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions. You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++ 7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all. For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices. Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++ 8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded. In such case, this License incorporates+the limitation as if written in the body of this License.++ 9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number. If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation. If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++ 10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission. For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this. Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++ NO WARRANTY++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software; you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation; either version 2 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License along+ with this program; if not, write to the Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++ Gnomovision version 69, Copyright (C) year name of author+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary. Here is a sample; alter the names:++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program+ `Gnomovision' (which makes passes at compilers) written by James Hacker.++ <signature of Ty Coon>, 1 April 1989+ Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs. If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library. If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ Setup.hs view
@@ -0,0 +1,4 @@+#!/usr/bin/env runhaskell++import Distribution.Simple+main = defaultMain
+ Sound/File/Sndfile.hs view
@@ -0,0 +1,36 @@+-- | "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/>).++module Sound.File.Sndfile+(+ -- *Types+ Count, Index,+ -- *Stream format+ Format(..),+ HeaderFormat(..),+ SampleFormat(..),+ EndianFormat(..),+ defaultFormat,+ -- *Stream info+ Info(..), duration, defaultInfo, checkFormat,+ -- *Stream handle operations+ Handle, hInfo, hIsSeekable,+ IOMode(..), openFile, getFileInfo, hFlush, hClose,+ SeekMode(..), hSeek, hSeekRead, hSeekWrite,+ -- *I\/O functions+ MBuffer(..), interact,+ --IBuffer(..),+ -- *Exception handling+ Exception, errorString, catch,+ -- *Header string field access+ StringType(..), getString, setString+) where++import Prelude hiding (catch, interact)+import Sound.File.Sndfile.Buffer+import Sound.File.Sndfile.Buffer.Storable ()+import Sound.File.Sndfile.Buffer.IOCArray ()+import Sound.File.Sndfile.Interface++-- EOF
+ Sound/File/Sndfile/Buffer.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE MultiParamTypeClasses #-}++module Sound.File.Sndfile.Buffer+(+ MBuffer(..),+ checkSampleBounds, checkFrameBounds,+ interact+) 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.Ix (rangeSize)+import Prelude hiding (interact)+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")+ | 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")+ | otherwise = return ()++-- |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++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++-- EOF
+ Sound/File/Sndfile/Buffer/IOCArray.hs view
@@ -0,0 +1,47 @@+{-# 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 ())+ -> IOFunc a+ -> Handle -> (IOCArray Index a) -> Count+ -> IO Count+hIO checkBounds ioFunc (Handle info handle) buffer count = do+ size <- liftM rangeSize $ getBounds buffer+ checkBounds size (channels info) count+ result <- withIOCArray buffer $+ \ptr -> liftM fromIntegral $ ioFunc handle ptr (cIntConv 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++instance MBuffer IOCArray Double IO where+ hGetSamples = hIO checkSampleBounds sf_read_double+ hGetFrames = hIO checkFrameBounds sf_read_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++instance MBuffer IOCArray Float IO where+ hGetSamples = hIO checkSampleBounds sf_read_float+ hGetFrames = hIO checkFrameBounds sf_read_float+ hPutSamples = hIO checkSampleBounds sf_write_float+ hPutFrames = hIO checkFrameBounds sf_write_float++-- EOF
+ Sound/File/Sndfile/Buffer/Storable.hs view
@@ -0,0 +1,47 @@+{-# 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 ())+ -> IOFunc a+ -> Handle -> (StorableArray Index a) -> Count+ -> IO Count+hIO checkBounds ioFunc (Handle info handle) buffer count = do+ size <- liftM rangeSize $ getBounds buffer+ checkBounds size (channels info) count+ result <- withStorableArray buffer $+ \ptr -> liftM fromIntegral $ ioFunc handle ptr (cIntConv 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+ 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++instance MBuffer StorableArray Float IO where+ hGetSamples = hIO checkSampleBounds sf_read_float+ hGetFrames = hIO checkFrameBounds sf_read_float+ hPutSamples = hIO checkSampleBounds sf_write_float+ hPutFrames = hIO checkFrameBounds sf_write_float++-- EOF
+ Sound/File/Sndfile/Interface.chs view
@@ -0,0 +1,428 @@+{-# 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 System.IO.Unsafe (unsafePerformIO)++#include <sndfile.h>++{#context lib="libsndfile" prefix="sf"#}++-- ====================================================================+-- Basic types++type Count = Int -- ^ Type for expressing sample counts.+type Index = Int -- ^ Type for expressing sample indices.++-- ====================================================================+-- Format++-- | Header format.+{#enum HeaderFormat {underscoreToCase} deriving (Eq, Show)#}+#c+enum HeaderFormat+{+ HEADER_FORMAT_NONE = 0,++ HEADER_FORMAT_WAV = SF_FORMAT_WAV,+ HEADER_FORMAT_AIFF = SF_FORMAT_AIFF,+ HEADER_FORMAT_AU = SF_FORMAT_AU,+ HEADER_FORMAT_RAW = SF_FORMAT_RAW,+ HEADER_FORMAT_PAF = SF_FORMAT_PAF,+ HEADER_FORMAT_SVX = SF_FORMAT_SVX,+ HEADER_FORMAT_NIST = SF_FORMAT_NIST,+ HEADER_FORMAT_VOC = SF_FORMAT_VOC,+ HEADER_FORMAT_IRCAM = SF_FORMAT_IRCAM,+ HEADER_FORMAT_W64 = SF_FORMAT_W64,+ HEADER_FORMAT_MAT4 = SF_FORMAT_MAT4,+ HEADER_FORMAT_MAT5 = SF_FORMAT_MAT5,+ HEADER_FORMAT_PVF = SF_FORMAT_PVF,+ HEADER_FORMAT_XI = SF_FORMAT_XI,+ HEADER_FORMAT_HTK = SF_FORMAT_HTK,+ HEADER_FORMAT_SDS = SF_FORMAT_SDS,+ HEADER_FORMAT_AVR = SF_FORMAT_AVR,+ HEADER_FORMAT_WAVEX = SF_FORMAT_WAVEX,+ HEADER_FORMAT_SD2 = SF_FORMAT_SD2,+ HEADER_FORMAT_FLAC = SF_FORMAT_FLAC,+ HEADER_FORMAT_CAF = SF_FORMAT_CAF+};+#endc++-- | Sample format.+{#enum SampleFormat {underscoreToCase} deriving (Eq, Show)#}+#c+enum SampleFormat+{+ SAMPLE_FORMAT_NONE = 0,++ SAMPLE_FORMAT_PCM_S8 = SF_FORMAT_PCM_S8,+ SAMPLE_FORMAT_PCM_16 = SF_FORMAT_PCM_16,+ SAMPLE_FORMAT_PCM_24 = SF_FORMAT_PCM_24,+ SAMPLE_FORMAT_PCM_32 = SF_FORMAT_PCM_32,+ + SAMPLE_FORMAT_PCM_U8 = SF_FORMAT_PCM_U8,+ + SAMPLE_FORMAT_FLOAT = SF_FORMAT_FLOAT,+ SAMPLE_FORMAT_DOUBLE = SF_FORMAT_DOUBLE,+ + SAMPLE_FORMAT_ULAW = SF_FORMAT_ULAW,+ SAMPLE_FORMAT_ALAW = SF_FORMAT_ALAW,+ SAMPLE_FORMAT_IMA_ADPCM = SF_FORMAT_IMA_ADPCM,+ SAMPLE_FORMAT_MS_ADPCM = SF_FORMAT_MS_ADPCM,+ + SAMPLE_FORMAT_GSM610 = SF_FORMAT_GSM610,+ SAMPLE_FORMAT_VOX_ADPCM = SF_FORMAT_VOX_ADPCM,+ + SAMPLE_FORMAT_G721_32 = SF_FORMAT_G721_32,+ SAMPLE_FORMAT_G723_24 = SF_FORMAT_G723_24,+ SAMPLE_FORMAT_G723_40 = SF_FORMAT_G723_40,+ + SAMPLE_FORMAT_DWVW_12 = SF_FORMAT_DWVW_12,+ SAMPLE_FORMAT_DWVW_16 = SF_FORMAT_DWVW_16,+ SAMPLE_FORMAT_DWVW_24 = SF_FORMAT_DWVW_24,+ SAMPLE_FORMAT_DWVW_N = SF_FORMAT_DWVW_N,+ + SAMPLE_FORMAT_FORMAT_DPCM_8 = SF_FORMAT_DPCM_8,+ SAMPLE_FORMAT_FORMAT_DPCM_16 = SF_FORMAT_DPCM_16+};+#endc++-- | Endianness.+{#enum EndianFormat {underscoreToCase} deriving (Eq, Show)#}+#c+enum EndianFormat+{+ ENDIAN_FILE = SF_ENDIAN_FILE,+ ENDIAN_LITTLE = SF_ENDIAN_LITTLE,+ ENDIAN_BIG = SF_ENDIAN_BIG,+ ENDIAN_CPU = SF_ENDIAN_CPU+};+#endc++-- only used internally+{#enum FormatMask {underscoreToCase} deriving (Eq)#}+#c+enum FormatMask+{+ FORMAT_SUB_MASK = SF_FORMAT_SUBMASK,+ FORMAT_TYPE_MASK = SF_FORMAT_TYPEMASK,+ FORMAT_END_MASK = SF_FORMAT_ENDMASK+};+#endc++-- |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.+data Format = Format {+ headerFormat :: HeaderFormat,+ sampleFormat :: SampleFormat,+ endianFormat :: EndianFormat+} deriving (Eq, Show)++-- |Default \'empty\' format, useful when opening files for reading with 'ReadMode'.+defaultFormat :: Format+defaultFormat = Format HeaderFormatNone SampleFormatNone EndianFile++-- Convert CInt to Format+hsFormat :: CInt -> Format+hsFormat i =+ let hf = cToEnum (i .&. (cFromEnum FormatTypeMask) .&. complement (cFromEnum FormatEndMask))+ sf = cToEnum (i .&. (cFromEnum FormatSubMask))+ ef = cToEnum (i .&. (cFromEnum FormatEndMask))+ in+ Format {+ headerFormat = hf,+ sampleFormat = sf,+ endianFormat = ef+ }++-- Convert Format to CInt+cFormat :: Format -> CInt+cFormat (Format hf sf ef) = (cFromEnum hf) .|. (cFromEnum sf) .|. (cFromEnum ef)++-- ====================================================================+-- Info++-- |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+ channels :: Int, -- ^Number of channels+ format :: Format, -- ^Header and sample format+ sections :: Int, -- ^Number of sections+ 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'.+duration :: Info -> Double+duration info = (fromIntegral $ frames info) / (fromIntegral $ samplerate info)++-- |Default \'empty\' info, useful when opening files for reading with 'ReadMode'.+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').+--+-- 'checkFormat' returns 'True' if the parameters are valid and 'False' otherwise.++{-# NOINLINE checkFormat #-}+checkFormat :: Info -> Bool+checkFormat info =+ unsafePerformIO (with info (liftM cToBool . {#call unsafe sf_format_check#} . castPtr))++-- Storable instance for Info+instance Storable (Info) where+ alignment _ = alignment (undefined :: CInt) -- hmm+ sizeOf _ = {#sizeof INFO#}+ -- Unmarshall Info from C representation+ peek ptr = do+ frames <- liftM fromIntegral $ {#get SF_INFO.frames#} ptr+ samplerate <- liftM fromIntegral $ {#get SF_INFO.samplerate#} ptr+ channels <- liftM fromIntegral $ {#get SF_INFO.channels#} ptr+ format <- liftM hsFormat $ {#get SF_INFO.format#} ptr+ sections <- liftM fromIntegral $ {#get SF_INFO.sections#} ptr+ seekable <- liftM toBool $ {#get SF_INFO.seekable#} ptr+ return $ Info {+ frames = frames,+ samplerate = samplerate,+ channels = channels,+ format = format,+ sections = sections,+ seekable = seekable+ }+ -- Marshall Info to C representation+ poke ptr info =+ do+ {#set SF_INFO.frames#} ptr $ fromIntegral $ frames info+ {#set SF_INFO.samplerate#} ptr $ fromIntegral $ samplerate info+ {#set SF_INFO.channels#} ptr $ fromIntegral $ channels info+ {#set SF_INFO.format#} ptr $ cFormat $ format info+ {#set SF_INFO.sections#} ptr $ fromIntegral $ sections info+ {#set SF_INFO.seekable#} ptr $ fromBool $ seekable info++-- ====================================================================+-- 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)+ return handle++-- ====================================================================+-- Handle operations++-- | Abstract file handle.+data Handle = Handle {+ hInfo :: Info, -- ^Return the stream 'Info' associated with the 'Handle'.+ hPtr :: HandlePtr+}+type HandlePtr = Ptr ()++-- | I\/O mode.+{#enum IOMode {} deriving (Eq, Show)#}+#c+enum IOMode+{+ ReadMode = SFM_READ,+ WriteMode = SFM_WRITE,+ ReadWriteMode = SFM_RDWR+};+#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 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'.+--+-- 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 ->+ with info (\cInfo -> do+ cHandle <- {#call unsafe sf_open#}+ cFilePath (cFromEnum ioMode) (castPtr cInfo)+ >>= checkHandle+ 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.+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.+hFlush :: Handle -> IO ()+hFlush (Handle _ handle) = {#call unsafe sf_write_sync#} handle++-- |Get header format information associated with file.+getFileInfo :: FilePath -> IO Info+getFileInfo filePath = do+ h <- openFile filePath ReadMode defaultInfo+ let info = hInfo h+ hClose h+ return info++-- ====================================================================+-- seeking++hIsSeekable :: Handle -> IO Bool+hIsSeekable = return . seekable . hInfo++{#enum SeekMode {} deriving (Eq, Show)#}+#c+enum SeekMode+{+ AbsoluteSeek = SEEK_SET,+ RelativeSeek = SEEK_CUR,+ SeekFromEnd = SEEK_END+};+#endc++-- 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+ n <- liftM fromIntegral $+ {#call unsafe sf_seek#}+ handle+ (cIntConv frames)+ ((cFromEnum seekMode) .|. (case ioMode of+ Nothing -> 0+ Just m -> cFromEnum m))+ 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.+--+-- 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.+--+-- * '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.+--+-- 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.+-- +-- '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++--hSeek (Handle _ handle) seekMode frames = do+-- n <- liftM fromIntegral $ {#call unsafe sf_seek#} handle (cIntConv frames) (cFromEnum seekMode)+-- checkHandle handle+-- return n++-- |Like 'hSeek', but only the read pointer is modified.+hSeekRead :: Handle -> SeekMode -> Count -> IO Count+hSeekRead = hSeek' (Just ReadMode)++-- |Like 'hSeek', but only the write pointer is modified.+hSeekWrite :: Handle -> SeekMode -> Count -> IO Count+hSeekWrite = hSeek' (Just WriteMode)++-- ====================================================================+-- string access++-- |Header string field types.+{#enum StringType {underscoreToCase} deriving (Eq, Show)#}+#c+enum StringType+{+ STR_TITLE = SF_STR_TITLE,+ STR_COPYRIGHT = SF_STR_COPYRIGHT,+ STR_SOFTWARE = SF_STR_SOFTWARE,+ STR_ARTIST = SF_STR_ARTIST,+ STR_COMMENT = SF_STR_COMMENT,+ STR_DATE = SF_STR_DATE+};+#endc++-- |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)+ if ptr == (nullPtr :: Ptr CChar)+ then return Nothing+ else liftM Just $ peekCString =<< (return ptr)+++-- |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
@@ -0,0 +1,27 @@+Name: hsndfile+Version: 0.1.1+Category: Sound+License: GPL+License-File: COPYING+Copyright: Stefan Kersten, 2007-2008+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+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/>.+Tested-With: GHC+Build-Type: Simple+Build-Depends: array, base, carray, haskell98+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+Extra-Libraries: sndfile