module Sound.Iteratee.Codecs.Common (
stringRead4
,joinMaybe
,convFunc
)
where
import Sound.Iteratee.Base
import Data.Iteratee as I
import qualified Data.Vector.Storable as V
import Foreign
import Control.Applicative
import Control.Monad (replicateM, liftM)
import Control.Monad.CatchIO
import Data.Char (chr)
import Data.Int.Int24
import Data.Word.Word24
import Data.ListLike.Vector.Storable ()
be :: IO Bool
be = fmap (==1) $ with (1 :: Word16) (\p -> peekByteOff p 1 :: IO Word8)
stringRead4 :: MonadCatchIO m => Iteratee (V.Vector Word8) m String
stringRead4 = (liftM . map) (chr . fromIntegral) $ replicateM 4 I.head
unroll8 :: (MonadCatchIO m) => Iteratee (V.Vector Word8) m (V.Vector Word8)
unroll8 = I.getChunk
unroller :: (Storable a, MonadCatchIO m, Functor m) =>
Int
-> Iteratee (V.Vector Word8) m (V.Vector a)
unroller wSize = liftI step
where
step (I.Chunk buf)
| V.null buf = liftI step
| otherwise = do
let len = V.length buf
if len < wSize
then liftI $ step' buf
else if len `rem` wSize == 0
then do
let buf' = hostToLE buf
idone buf' (I.Chunk V.empty)
else let newLen = (len `div` wSize) * wSize
h = hostToLE $ V.take newLen buf
t = V.drop newLen buf
in idone h (I.Chunk t)
step stream = idone V.empty stream
step' i (I.Chunk buf)
| V.null buf = liftI (step' i)
| otherwise = do
let l = V.length buf
iLen = V.length i
newbuf = i V.++ buf
if l+iLen < wSize
then liftI (step' newbuf)
else step (I.Chunk newbuf)
step' _i stream = idone V.empty stream
hostToLE :: forall a. Storable a => V.Vector Word8 -> V.Vector a
hostToLE vec = let be' = unsafePerformIO be in if be'
then error "wrong endian-ness. Ask the maintainer to implement hostToLE"
else let (ptr, offset,len) = V.unsafeToForeignPtr vec
in V.unsafeFromForeignPtr (castForeignPtr ptr)
offset
(len `quot` sizeOf (undefined :: a))
w16 :: Word16
w16 = 0
w24 :: Word24
w24 = 0
w32 :: Word32
w32 = 0
convFunc :: (MonadCatchIO m, Functor m) =>
AudioFormat
-> Iteratee (V.Vector Word8) m (V.Vector Double)
convFunc (AudioFormat _nc _sr 8) =
V.map (normalize 8 . (fromIntegral :: Word8 -> Int8)) <$> unroll8
convFunc (AudioFormat _nc _sr 16) =
V.map (normalize 16 . (fromIntegral :: Word16 -> Int16))
<$> unroller (sizeOf w16)
convFunc (AudioFormat _nc _sr 24) =
V.map (normalize 24 . (fromIntegral :: Word24 -> Int24))
<$> unroller (sizeOf w24)
convFunc (AudioFormat _nc _sr 32) =
V.map (normalize 32 . (fromIntegral :: Word32 -> Int32))
<$> unroller (sizeOf w32)
convFunc _ = I.throwErr (I.iterStrExc "Invalid wave bit depth")
joinMaybe :: Maybe [a] -> [a]
joinMaybe Nothing = []
joinMaybe (Just a) = a
normalize :: Integral a => BitDepth -> a -> Double
normalize 8 = \a -> let m = 1 / 128 in m * (fromIntegral a 128)
normalize bd = \a -> if a > 0
then fromIntegral a * mPos
else fromIntegral a * mNeg
where
mPos = 1/ (fromIntegral (1 `shiftL` fromIntegral (bd 1) :: Integer) 1)
mNeg = 1/ fromIntegral (1 `shiftL` fromIntegral (bd 1) :: Integer)