]> gitweb @ CieloNegro.org - wavpack.git/blobdiff - Codec/Audio/WavPack/Unpack.hs
working on unpackSamples
[wavpack.git] / Codec / Audio / WavPack / Unpack.hs
index f816657e9924e8b105b7bf99c232fdf5fb40332f..33c51522df4ea463bf641c2de927795961af1a64 100644 (file)
@@ -1,40 +1,60 @@
 {-# LANGUAGE
-    BangPatterns
-  , UnboxedTuples
+    DoAndIfThenElse
+  , FlexibleContexts
+  , ScopedTypeVariables
   , UnicodeSyntax
   #-}
 module Codec.Audio.WavPack.Unpack
-    (
+    ( WavpackStream(..)
+    , unpackSamples
     )
     where
-import Codec.Audio.WavPack.Internal
-import Data.Bits
-import Data.Bitstream.Generic (Bitstream)
-import qualified Data.Bitstream.Generic as B
+import Codec.Audio.WavPack.Block
+import Control.Monad.ST
+import Data.Int
+import Data.STRef
+import qualified Data.Vector.Generic.Mutable as MV
 import Data.Word
 import Prelude.Unicode
 
--- Read a single unsigned value from the specified bitstream with a
--- value from 0 to maxCode. If there are exactly a power of two number
--- of possible codes then this will read a fixed number of bits;
--- otherwise it reads the minimum number of bits and then determines
--- whether another bit is needed to define the code.
-readCode ∷ Bitstream bs ⇒ bs → Word32 → (# Word32, bs #)
-{-# INLINEABLE readCode #-}
-readCode bs 0       = (# 0, bs #)
-readCode bs 1       = (# b2n (B.head bs), B.tail bs #)
-readCode bs maxCode
-    = let !bitCount = countBits maxCode
-          !extras   = bit bitCount - maxCode - 1
-          !code     = B.toBits (B.take (bitCount - 1) bs)
-          (# code', bitCount' #)
-                    = if code ≥ extras then
-                          (# (code `shiftL` 1)
-                             - extras
-                             + b2n (bs B.!! bitCount)
-                           , bitCount #)
-                      else
-                          (# code, bitCount - 1 #)
-          !bs'      = B.drop bitCount' bs
-      in
-        (# code', bs' #)
+-- | FIXME
+data WavpackStream s
+    = WavpackStream {
+        wpsHeader      ∷ !BlockHeader
+      , wpsMuteError   ∷ !(STRef s Bool)
+      , wpsSampleIndex ∷ !(STRef s Word32)
+      }
+
+-- |This monster actually unpacks the WavPack bitstream(s) into the
+-- specified buffer as 32-bit integers or floats (depending on orignal
+-- data). Lossy samples will be clipped to their original limits
+-- (i.e. 8-bit samples are clipped to -128/+127) but are still
+-- returned in longs. It is up to the caller to potentially reformat
+-- this for the final output including any multichannel distribution,
+-- block alignment or endian compensation.
+unpackSamples ∷ ∀v s. (MV.MVector v Int32)
+              ⇒ WavpackStream s
+              → Int    -- ^ Number of channels.
+              → Int    -- ^ Reduced number of channels (1 or 2).
+              → Word32 -- ^ Number of samples to get.
+              → ST s (v s Int32)
+{-# INLINEABLE unpackSamples #-}
+unpackSamples wps numChannels reducedChannels nSamples0
+    = do let hdr   = wpsHeader wps
+             flags = bhFlags hdr
+         nSamples ← do idx ← readSTRef (wpsSampleIndex wps)
+                       if idx + nSamples0 > bhBlockIndex hdr + bhBlockSamples hdr then
+                           return $ bhBlockIndex hdr + bhBlockSamples hdr - idx
+                       else
+                           return nSamples0
+
+         muteError ← readSTRef (wpsMuteError wps)
+         if muteError then
+             do v ← if reducedChannels ≡ 1 ∨ numChannels ≡ 1 ∨ bfMono flags then
+                        MV.replicate (fromIntegral nSamples) 0
+                    else
+                        MV.replicate (fromIntegral nSamples ⋅ 2) 0
+                modifySTRef (wpsSampleIndex wps) (+ nSamples)
+                return v
+         else
+             error "FIXME"