X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=wavpack.git;a=blobdiff_plain;f=Codec%2FAudio%2FWavPack%2FMetadata.hs;h=77901f445aedf505ab7e4ce117ae026ebdd147c7;hp=0b8d3ebbb060f6bbdd9ea269fabf19fe401a1d61;hb=9128d47e1f753b82477535a1116b3a4f416243fc;hpb=ccc5bb864714f7f2ece125681e746c7e69938d93 diff --git a/Codec/Audio/WavPack/Metadata.hs b/Codec/Audio/WavPack/Metadata.hs index 0b8d3eb..77901f4 100644 --- a/Codec/Audio/WavPack/Metadata.hs +++ b/Codec/Audio/WavPack/Metadata.hs @@ -6,7 +6,7 @@ -- | WavPack metadata sub-blocks module Codec.Audio.WavPack.Metadata ( Metadata(..) - , SubBlock(..) + , SubBlock , Dummy(..) , Unknown(..) @@ -21,29 +21,48 @@ import qualified Data.ByteString.Lazy as L import Data.Typeable import Prelude.Unicode +-- | Type class for every metadata sub-blocks. class (Binary α, Eq α, Show α, Typeable α) ⇒ Metadata α where + -- | Get the metadata ID without odd-size bit nor large-block bit + -- (mandatory). metaID ∷ α → Word8 + -- | Get the size of metadata, excluding the metadata header + -- (optional). metaSize ∷ α → Word32 - metaSize = fromIntegral ∘ L.length ∘ runPut ∘ put + -- | Cast a 'SubBlock' to this type of metadata (optional). + fromSubBlock ∷ SubBlock → Maybe α + fromSubBlock (SubBlock a) = cast a + -- | Wrap the metadata into 'SubBlock' (optional). + toSubBlock ∷ α → SubBlock + toSubBlock = SubBlock +-- | An opaque sub-block container. data SubBlock = ∀α. Metadata α ⇒ SubBlock α + deriving Typeable + +instance Metadata SubBlock where + metaID (SubBlock a) = metaID a + metaSize (SubBlock a) = metaSize a + fromSubBlock = Just + toSubBlock = id instance Binary SubBlock where put (SubBlock a) = let size = metaSize a - oddBit = if odd size then 0x40 else 0 - largeBit = if size > 255 then 0x80 else 0 + size' = size + 1 + oddBit = if odd size then 0x40 else 0 + largeBit = if size > 0x1FE then 0x80 else 0 idWord = metaID a .|. oddBit .|. largeBit in do putWord8 idWord - if size > 255 then + if size > 0x1FE then -- Don't forget about the endianness. - do putWord8 $ fromIntegral $ (size `shiftR` 1) .&. 0xFF - putWord8 $ fromIntegral $ (size `shiftR` 9) .&. 0xFF - putWord8 $ fromIntegral $ (size `shiftR` 17) .&. 0xFF + do putWord8 $ fromIntegral $ (size' `shiftR` 1) .&. 0xFF + putWord8 $ fromIntegral $ (size' `shiftR` 9) .&. 0xFF + putWord8 $ fromIntegral $ (size' `shiftR` 17) .&. 0xFF else - putWord8 $ fromIntegral $ (size `shiftR` 1) .&. 0xFF + putWord8 $ fromIntegral $ (size' `shiftR` 1) .&. 0xFF put a when (odd size) $ putWord8 0 @@ -52,17 +71,17 @@ instance Binary SubBlock where isLarge = idWord .&. 0x80 ≢ 0 rawID = idWord .&. (complement 0x40) .&. (complement 0x80) adj = if isOdd then -1 else 0 - size ← if isLarge then - do sz0 ← getWord8 - sz1 ← getWord8 - sz2 ← getWord8 - return $ ( (fromIntegral sz2 `shiftL` 17) .|. - (fromIntegral sz1 `shiftL` 9) .|. - (fromIntegral sz0 `shiftL` 1) - ) + adj - else - fmap ((+ adj) ∘ (`shiftL` 1) ∘ fromIntegral) getWord8 - subb ← getLazyByteString $ fromIntegral (size ∷ Word32) + size ← if isLarge then + do sz0 ← getWord8 + sz1 ← getWord8 + sz2 ← getWord8 + return $ ( (fromIntegral sz2 `shiftL` 17) .|. + (fromIntegral sz1 `shiftL` 9) .|. + (fromIntegral sz0 `shiftL` 1) + ) + adj + else + fmap ((+ adj) ∘ (`shiftL` 1) ∘ fromIntegral) getWord8 + subb ← getLazyByteString $ fromIntegral (size ∷ Word32) return $ runGet (getSubBlock rawID) subb where getSubBlock ∷ Word8 → Get SubBlock @@ -84,7 +103,9 @@ instance Show SubBlock where -- | Dummy metadata to pad WavPack blocks. data Dummy = Dummy { - dumSize ∷ !Word32 + -- | Must be less than 2^25 bytes long due to the limitation + -- of WavPack specification. + dumSize ∷ Word32 } deriving (Eq, Show, Typeable) @@ -99,7 +120,10 @@ instance Binary Dummy where -- | Unknown but optional metadata found in the WavPack block. data Unknown = Unknown { - unkID ∷ !Word8 + -- | The ID of this unknown metadata without odd-size bit nor + -- large-block bit. + unkID ∷ Word8 + -- | Raw data; must be less than 2^25 bytes long. , unkData ∷ L.ByteString } deriving (Eq, Show, Typeable)