-- | A module for various scale functions that we may need for the transformation of data in a wave -- file. module Sound.Wav.Scale ( bounds , scale , zeroStable ) where import Data.Ratio import Data.Bits -- Thu May 1 08:28:15 EST 2014 -- The scale function works correctly but it does not maintain the position of zero. I -- would expect zero to stay constant no matter how you transformed it. I think we might -- need a positive half of the transform and a negative half of the transform just to keep -- everything balanced. I am not yet sure how I will make that work for unsigned types. -- Unfortunately I am beginning to this that this is a correct implimentation of this -- function and that the movement of zero is just conversion noise. People will have to -- learn to deal with it. -- -- Fri May 2 08:03:34 EST 2014 -- I have realised that I want a scale function that works in the same way that an -- equivalence relation works. I want the following three rules to hold true: -- -- Where s_ab means: the scale function s that scales a to b -- -- Rule 1: s_ab 0 = 0 (Reflexive) -- Rule 2: s_ba . s_ab $ x = x (Symmetric) -- Rule 3: s_bc . s_ab $ x = s_ac x (Transitive) -- -- So I should be able to write test cases that ensure that this is the case. -- | Given a bounded type it returns a lower and upper bound result. bounds :: Bounded a => (a, a) bounds = (minBound, maxBound) -- | Given two bounds linearly scale something fro the first range into the second. This method will -- ensure that the endpoints of the bounds meet in the scale. scale :: (Bounded a, Bounded b, Integral a, Integral b) => (a, a) -> (b, b) -> a -> b scale (aLow, aHigh) (bLow, bHigh) start = fromIntegral endOffset where fi :: Integral d => d -> Integer fi = fromIntegral startOffset = toRatio $ fi start - fi aLow endOffset = round (startOffset * rat) - fi bLow rat = bRange % aRange aRange = fi aHigh - fi aLow bRange = fi bHigh - fi bLow toRatio :: Integral a => a -> Ratio a toRatio = flip (%) 1 -- | This is a scale function in which, given an example integer fro ma range it will scale a number -- a into that range. The most important part of this scale is that zeroStable x 0 = 0. zeroStable :: (Bits a, Bits b, Integral a, Integral b) => b -> a -> b zeroStable example x = fromIntegral $ shift (fromIntegral x :: Integer) (toBits - fromBits) where fromBits = bitSize x toBits = bitSize example