module Data.Conduit.Audio.Sndfile
( sourceSnd, sourceSndFrom
, sinkSnd
) where
import Data.Conduit.Audio
import qualified Data.Conduit as C
import qualified Data.Conduit.List as CL
import qualified Sound.File.Sndfile as Snd
import qualified Sound.File.Sndfile.Buffer.Vector as SndBuf
import Control.Monad.IO.Class
import Control.Monad (void)
import Control.Monad.Fix (fix)
import Control.Monad.Trans.Resource (MonadResource)
sourceSnd
:: (MonadResource m, Snd.Sample a)
=> FilePath
-> IO (AudioSource m a)
sourceSnd = sourceSndFrom $ Frames 0
sourceSndFrom
:: (MonadResource m, Snd.Sample a)
=> Duration
-> FilePath
-> IO (AudioSource m a)
sourceSndFrom (Seconds secs) fp = do
info <- Snd.getFileInfo fp
sourceSndFrom (Frames $ secondsToFrames secs $ fromIntegral $ Snd.samplerate info) fp
sourceSndFrom (Frames fms) fp = do
info <- Snd.getFileInfo fp
let r = fromIntegral $ Snd.samplerate info
c = Snd.channels info
src = C.bracketP
(Snd.openFile fp Snd.ReadMode Snd.defaultInfo)
Snd.hClose
$ \h -> do
liftIO $ void $ Snd.hSeek h Snd.AbsoluteSeek fms
fix $ \loop -> liftIO (Snd.hGetBuffer h chunkSize) >>= \mx -> case mx of
Nothing -> return ()
Just buf -> do
C.yield $ SndBuf.fromBuffer buf
loop
return $ AudioSource src r c $ Snd.frames info fms
sinkSnd :: (MonadResource m, Snd.Sample a) => FilePath -> Snd.Format -> AudioSource m a -> m ()
sinkSnd fp fmt (AudioSource s r c _) = s C.$$ C.bracketP
(Snd.openFile fp Snd.WriteMode $ Snd.defaultInfo
{ Snd.format = fmt
, Snd.samplerate = round r
, Snd.channels = c
})
Snd.hClose
(\h -> CL.mapM_ $ liftIO . void . Snd.hPutBuffer h . SndBuf.toBuffer)