X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=wavpack.git;a=blobdiff_plain;f=Codec%2FAudio%2FWavPack%2FMetadata.hs;h=d8c0df1e592d889c1b203acb5a2ef3dd99d790f5;hp=bc1d07c3bd2059f940546b9fc2ad4bb18a65f00a;hb=5bf7c1be1cfce7ef8764ca3fbc34e8ef9bcf5037;hpb=acfc910ebb15715da125f86d473ab907f7f95698 diff --git a/Codec/Audio/WavPack/Metadata.hs b/Codec/Audio/WavPack/Metadata.hs index bc1d07c..d8c0df1 100644 --- a/Codec/Audio/WavPack/Metadata.hs +++ b/Codec/Audio/WavPack/Metadata.hs @@ -9,6 +9,8 @@ module Codec.Audio.WavPack.Metadata , SubBlock , Dummy(..) + , DecorrTerms(..) + , DecorrWeights(..) , RIFFHeader(..) , RIFFTrailer(..) , Unknown(..) @@ -20,7 +22,9 @@ import Data.Binary.Get import Data.Binary.Put import Data.Bits import qualified Data.ByteString.Lazy as L +import Data.Int import Data.Typeable +import qualified Data.Vector.Unboxed as UV import Prelude.Unicode -- | Type class for every metadata sub-blocks. @@ -87,9 +91,11 @@ instance Binary SubBlock where return $ runGet (getSubBlock rawID) subb where getSubBlock ∷ Word8 → Get SubBlock - getSubBlock 0x00 = fmap SubBlock (get ∷ Get Dummy) - getSubBlock 0x21 = fmap SubBlock (get ∷ Get RIFFHeader) - getSubBlock 0x22 = fmap SubBlock (get ∷ Get RIFFTrailer) + getSubBlock 0x00 = fmap SubBlock (get ∷ Get Dummy ) + getSubBlock 0x02 = fmap SubBlock (get ∷ Get DecorrTerms ) + getSubBlock 0x03 = fmap SubBlock (get ∷ Get DecorrWeights) + getSubBlock 0x21 = fmap SubBlock (get ∷ Get RIFFHeader ) + getSubBlock 0x22 = fmap SubBlock (get ∷ Get RIFFTrailer ) getSubBlock unknownID = if unknownID .&. 0x20 ≡ 0 then fail ("Unknown WavPack metadata ID: " ⧺ show unknownID) @@ -121,6 +127,86 @@ instance Binary Dummy where put = putLazyByteString ∘ flip L.replicate 0x00 ∘ fromIntegral ∘ dumSize get = fmap (Dummy ∘ fromIntegral) remaining +-- | Decorrelation terms and deltas. +data DecorrTerms + = DecorrTerms { + -- | @[ (term, delta) ]@ + dectVec ∷ !(UV.Vector (Int8, Int8)) + } + deriving (Eq, Show, Typeable) + +instance Metadata DecorrTerms where + metaID _ = 0x02 + metaSize = fromIntegral ∘ UV.length ∘ dectVec + +instance Binary DecorrTerms where + put = UV.mapM_ (putWord8 ∘ packDT) ∘ dectVec + where + packDT ∷ (Int8, Int8) → Word8 + packDT (term, δ) + = fromIntegral ( (term + 5 .&. 0x1F) + .|. + ((δ `shiftL` 5) .&. 0xE0) + ) + get = do n ← remaining + vec ← UV.replicateM (fromIntegral n) $ fmap unpackDT getWord8 + -- THINKME: unpack.c(read_decorr_terms) reverses the + -- order only when they are decoding. I don't know why so + -- I leave it unreversed for now. + return $ DecorrTerms vec + where + unpackDT ∷ Word8 → (Int8, Int8) + unpackDT w + = let term = (fromIntegral $ w .&. 0x1F) - 5 + δ = fromIntegral $ (w `shiftR` 5) .&. 0x07 + in + (term, δ) + +-- | Decorrelation weights. +data DecorrWeights + = DecorrWeights { + -- | For mono blocks, this is a weight vector for the single + -- channel. For stereo blocks, it's interleaved as A, B, A, B, + -- ... + decwVec ∷ !(UV.Vector Int16) + } + deriving (Eq, Show, Typeable) + +instance Metadata DecorrWeights where + metaID _ = 0x03 + metaSize = fromIntegral ∘ UV.length ∘ decwVec + +instance Binary DecorrWeights where + put = UV.mapM_ (putWord8 ∘ packW) ∘ decwVec + where + packW ∷ Int16 → Word8 + packW w + = let w' | w > 1024 = 1024 + | w < -1024 = -1024 + | otherwise = w + w'' | w' > 0 = w' - ((w' + 64) `shiftR` 7) + | otherwise = w' + w''' = (w'' + 4) `shiftR` 3 + in + fromIntegral w''' + get = do n ← remaining + vec ← UV.replicateM (fromIntegral n) $ fmap unpackW getWord8 + -- THINKME: the same caution as DecorrTerms, but never + -- try to reverse the vector simply. Think about the + -- interleaving. + return $ DecorrWeights vec + where + unpackW ∷ Word8 → Int16 + unpackW w + = let w' ∷ Int8 + w' = fromIntegral w + w'' ∷ Int16 + w'' = (fromIntegral w') `shiftL` 3 + w''' | w'' > 0 = w'' + ((w'' + 64) `shiftR` 7) + | otherwise = w'' + in + w''' + -- | RIFF header for .wav files (before audio) data RIFFHeader = RIFFHeader { @@ -165,4 +251,4 @@ instance Metadata Unknown where instance Binary Unknown where put = putLazyByteString ∘ unkData - get = (⊥) + get = error "unsupported operation"