module Sound.File.Sndfile.Buffer (
module Sound.File.Sndfile.Buffer.Sample
, Buffer(..)
, hGetBuffer
, hGetContents
, readFile
, hGetContentChunks
, readFileChunks
, hPutBuffer
, writeFile
) where
import Control.Exception (bracket)
import Foreign
import Prelude hiding (readFile, writeFile)
import Sound.File.Sndfile.Exception (throw)
import Sound.File.Sndfile.Interface
import Sound.File.Sndfile.Buffer.Sample (Sample(..))
import System.IO.Unsafe (unsafeInterleaveIO)
class Buffer a e where
fromForeignPtr :: ForeignPtr e -> Int -> Int -> IO (a e)
toForeignPtr :: a e -> IO (ForeignPtr e, Int, Int)
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
hGetContents :: (Sample e, Buffer a e) => Handle -> IO (Info, Maybe (a e))
hGetContents h = (,) info `fmap` hGetBuffer h (frames info)
where info = hInfo h
hGetContentChunks :: (Sample e, Buffer a e) => Count -> Handle -> IO (Info, [a e])
hGetContentChunks n h = (,) (hInfo h) `fmap` lazyread
where
lazyread = unsafeInterleaveIO loop
loop = do
r <- hGetBuffer h n
case r of
Just b -> do
bs <- lazyread
return (b:bs)
Nothing -> return []
readFile :: (Sample e, Buffer a e) => FilePath -> IO (Info, Maybe (a e))
readFile path = do
bracket
(openFile path ReadMode defaultInfo)
(hClose)
(hGetContents)
readFileChunks :: (Sample e, Buffer a e) => Count -> FilePath -> IO (Info, [a e])
readFileChunks n path = do
bracket
(openFile path ReadMode defaultInfo)
(hClose)
(hGetContentChunks n)
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
withForeignPtr fp $ \ptr -> do
let p = plusPtr ptr (sizeOf (undefined :: e) * i) :: Ptr e
hPutBuf h p (n `div` numChannels)
where
numChannels = channels $ hInfo h
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)