-- | @sclang@ math functions. module Sound.SC3.Lang.Math where import Data.Bits -- * Binary -- | @0@ is false, @1@ is True, else error. -- -- > map bitChar "01" == [False,True] bitChar :: Char -> Bool bitChar c = case c of '0' -> False '1' -> True _ -> error "bitChar" -- | Parse a sequence of 0 and 1 characters as a BE bit sequence -- -- > parseBits "101" == 5 -- > parseBits "00001111" == 15 parseBits :: (Num a,Bits a) => String -> a parseBits x = let x' = filter (id . bitChar . snd) (zip [0..] (reverse x)) in foldr ((.|.) . bit . fst) 0 x' -- * SimpleNumber -- | Variant of @SimpleNumber.exprand@ that shifts a linear (0,1) -- value to an exponential distribution. -- -- > map (floor . exprandrng 10 100) [0,0.5,1] == [10,31,100] exprandrng :: (Floating b) => b -> b -> b -> b exprandrng l r i = l * exp (log (r / l) * i) -- | Psuedo-inifite bounded value. -- -- > inf == maxBound inf :: Bounded a => a inf = maxBound -- | Predicate for 'inf'. -- -- > isInf inf == True isInf :: (Eq a,Bounded a) => a -> Bool isInf = (== inf) -- | @SimpleNumber.linexp@ shifts from linear to exponential ranges. -- -- > map (floor . linexp 1 2 10 100) [1,1.5,2] == [10,31,100] linexp :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a linexp l r l' r' n = if n <= l then l' else if n >= r then r' else ((r'/l') ** ((n-l)/(r-l))) * l' -- * Gain -- | Synonym for 'logBase' @10@. log10 :: Floating a => a -> a log10 = logBase 10 -- > map rmsToDb [1,0.75,0.5,0.25,0] rmsToDb :: Floating a => a -> a rmsToDb rms = log10 rms * 20 -- > map dbToRms [0,-3,-6,-9,-12] dbToRms :: Floating a => a -> a dbToRms db = 10 ** (db * 0.05) -- > map powToDb [1,0.75,0.5,0.25,0] powToDb :: Floating a => a -> a powToDb pow = 10 * log10 pow -- > map dbToPow [0,-3,-6,-9,-12] dbToPow :: Floating a => a -> a dbToPow db = 10 ** (db * 0.1)