, blockMetadata = subs
}
-getSubBlocks ∷ Word32 → Get [SubBlock]
-getSubBlocks 0 = return []
+-- Be aware; the Get monad is like a strict State monad so the entire
+-- sub-blocks are parsed at once. This might not be what you want
+-- (like me).
+getSubBlocks ∷ Integral n ⇒ n → Get [SubBlock]
+getSubBlocks 0 = return $! []
getSubBlocks !blockSize
= do before ← bytesRead
meta ← get
rest ← getSubBlocks $ blockSize - fromIntegral (after - before)
return (meta : rest)
+-- The lazy version.
+getSubBlocksLazily ∷ Integral n
+ ⇒ L.ByteString
+ → n
+ → (# [SubBlock], L.ByteString #)
+getSubBlocksLazily src 0 = (# [], src #)
+getSubBlocksLazily src !blockSize
+ = let (sub, src', consumed)
+ = runGetState get src 0
+ (# subs, src'' #)
+ = getSubBlocksLazily src' $
+ blockSize - fromIntegral consumed
+ in
+ (# sub : subs, src'' #)
+
-- | The preamble to every block in both the .wv and .wvc files.
data BlockHeader
= BlockHeader {
-- header we can accept.
→ case runGet get header of
bh → if isGoodHeader bh then
- case runGetState (getSubBlocks $ bhSize bh) rest 0 of
- (subs, rest', _)
+ case getSubBlocksLazily rest $ bhSize bh of
+ (# subs, rest' #)
→ let !blk = Block {
blockHeader = bh
, blockMetadata = subs
, SubBlock
, Dummy(..)
+ , RIFFHeader(..)
+ , RIFFTrailer(..)
, Unknown(..)
)
where
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 unknownID
= if unknownID .&. 0x20 ≡ 0 then
fail ("Unknown WavPack metadata ID: " ⧺ show unknownID)
put = putLazyByteString ∘ flip L.replicate 0x00 ∘ fromIntegral ∘ dumSize
get = fmap (Dummy ∘ fromIntegral) remaining
+-- | RIFF header for .wav files (before audio)
+data RIFFHeader
+ = RIFFHeader {
+ riffHeader ∷ L.ByteString
+ }
+ deriving (Eq, Show, Typeable)
+
+instance Metadata RIFFHeader where
+ metaID _ = 0x21
+
+instance Binary RIFFHeader where
+ put = putLazyByteString ∘ riffHeader
+ get = fmap RIFFHeader getRemainingLazyByteString
+
+-- | RIFF trailer for .wav files (after audio)
+data RIFFTrailer
+ = RIFFTrailer {
+ riffTrailer ∷ L.ByteString
+ }
+ deriving (Eq, Show, Typeable)
+
+instance Metadata RIFFTrailer where
+ metaID _ = 0x22
+
+instance Binary RIFFTrailer where
+ put = putLazyByteString ∘ riffTrailer
+ get = fmap RIFFTrailer getRemainingLazyByteString
+
-- | Unknown but optional metadata found in the WavPack block.
data Unknown
= Unknown {
instance Metadata Unknown where
metaID = unkID
- metaSize = fromIntegral ∘ L.length ∘ unkData
instance Binary Unknown where
put = putLazyByteString ∘ unkData