-- | FIXME
module Codec.Audio.WavPack.Entropy
( EntropyData(..)
+
+ , clearMedians
+
+ , getMedian0
+ , getMedian1
+ , getMedian2
+
+ , incMedian0
+ , decMedian0
+ , incMedian1
+ , decMedian1
+ , incMedian2
+ , decMedian2
)
where
+import Control.Monad.ST
+import Control.Monad.Unicode
+import Data.Bits
+import Data.STRef
import Data.Word
+import Prelude.Unicode
-- | FIXME
-data EntropyData
+data EntropyData s
= EntropyData {
-- | Median log2 values for a channel.
- edMedian ∷ !(Word32, Word32, Word32)
+ edMedian0 ∷ !(STRef s Word32)
+ , edMedian1 ∷ !(STRef s Word32)
+ , edMedian2 ∷ !(STRef s Word32)
-- | FIXME
- , edSlowLevel ∷ !Word32
+ , edSlowLevel ∷ !(STRef s Word32)
-- | FIXME
- , edErrorLimit ∷ !Word32
+ , edErrorLimit ∷ !(STRef s Word32)
}
- deriving (Eq, Show)
+
+clearMedians ∷ EntropyData s → ST s ()
+clearMedians e
+ = writeSTRef (edMedian0 e) 0 ≫
+ writeSTRef (edMedian1 e) 0 ≫
+ writeSTRef (edMedian2 e) 0
+
+-- | The time constant of the 3 median level breakpoints
+div0, div1, div2 ∷ Word32
+div0 = 128 -- 5/ 7 of samples
+div1 = 64 -- 10/ 49 of samples
+div2 = 32 -- 20/343 of samples
+
+-- | Retrieve the specified median breakpoint (without frac; min = 1)
+getMedian0, getMedian1, getMedian2 ∷ EntropyData s → ST s Word32
+getMedian0 = fmap ((`shiftR` 4) ∘ (+ 1)) ∘ readSTRef ∘ edMedian0
+getMedian1 = fmap ((`shiftR` 4) ∘ (+ 1)) ∘ readSTRef ∘ edMedian1
+getMedian2 = fmap ((`shiftR` 4) ∘ (+ 1)) ∘ readSTRef ∘ edMedian2
+
+-- | Update the specified median breakpoints. Note that the median is
+-- incremented when the sample is higher than the median, else
+-- decremented. They are designed so that the median will never drop
+-- below 1 and the value is essentially stationary if there are 2
+-- increments for every 5 decrements.
+incMedian0, decMedian0, incMedian1, decMedian1, incMedian2, decMedian2 ∷ EntropyData s → ST s ()
+incMedian0 = flip modifySTRef (\x → x + ((x + div0 ) `div` div0) ⋅ 5) ∘ edMedian0
+decMedian0 = flip modifySTRef (\x → x - ((x + (div0-2)) `div` div0) ⋅ 2) ∘ edMedian0
+incMedian1 = flip modifySTRef (\x → x + ((x + div1 ) `div` div1) ⋅ 5) ∘ edMedian1
+decMedian1 = flip modifySTRef (\x → x - ((x + (div1-2)) `div` div1) ⋅ 2) ∘ edMedian1
+incMedian2 = flip modifySTRef (\x → x + ((x + div2 ) `div` div2) ⋅ 5) ∘ edMedian2
+decMedian2 = flip modifySTRef (\x → x - ((x + (div2-2)) `div` div2) ⋅ 2) ∘ edMedian2