diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2018-05-15 12:50:42 +0200 | 
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2018-05-15 12:50:42 +0200 | 
| commit | 86ce943d5a49982246ab83e4acc72ffb7c22567c (patch) | |
| tree | 9a73ed3f112c302e5a1ed980c6505fa31fcf9287 /src/Trivmix | |
| parent | 31a88f4dd0800caeeb56d785b1876a9c2b88fb93 (diff) | |
| download | trivmix-86ce943d5a49982246ab83e4acc72ffb7c22567c.tar trivmix-86ce943d5a49982246ab83e4acc72ffb7c22567c.tar.gz trivmix-86ce943d5a49982246ab83e4acc72ffb7c22567c.tar.bz2 trivmix-86ce943d5a49982246ab83e4acc72ffb7c22567c.tar.xz trivmix-86ce943d5a49982246ab83e4acc72ffb7c22567c.zip  | |
Implement balance & refine types
Diffstat (limited to 'src/Trivmix')
| -rw-r--r-- | src/Trivmix/Types.hs | 79 | 
1 files changed, 42 insertions, 37 deletions
diff --git a/src/Trivmix/Types.hs b/src/Trivmix/Types.hs index a6a41b9..f01e023 100644 --- a/src/Trivmix/Types.hs +++ b/src/Trivmix/Types.hs  | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | {-# LANGUAGE FlexibleInstances, UndecidableInstances #-} | 1 | {-# LANGUAGE FlexibleInstances, UndecidableInstances, ViewPatterns, TemplateHaskell, PatternGuards #-} | 
| 2 | 2 | ||
| 3 | module Trivmix.Types | 3 | module Trivmix.Types | 
| 4 | ( Level | 4 | ( Level' | 
| 5 | , Level(Lin), toLin | ||
| 5 | , toFloat | 6 | , toFloat | 
| 6 | , asFloat | 7 | , asFloat | 
| 7 | , Adjustment(..) | 8 | , Adjustment(..) | 
| @@ -13,27 +14,37 @@ import Data.Fixed | |||
| 13 | import Data.CaseInsensitive ( CI ) | 14 | import Data.CaseInsensitive ( CI ) | 
| 14 | import qualified Data.CaseInsensitive as CI | 15 | import qualified Data.CaseInsensitive as CI | 
| 15 | 16 | ||
| 17 | import Text.ParserCombinators.ReadPrec | ||
| 18 | import Control.Applicative | ||
| 19 | import Control.Monad | ||
| 20 | |||
| 16 | import Data.Default | 21 | import Data.Default | 
| 17 | 22 | ||
| 18 | import Data.Function (on) | 23 | import Data.Function (on) | 
| 19 | 24 | ||
| 20 | data Level = Lin Float | DB Float | 25 | import Refined | 
| 21 | 26 | ||
| 22 | instance Num Level where | 27 | type Level' = Refined NonNegative Float | 
| 23 | (+) = asFloat (+) | 28 | data Level = Lin { toLin :: Level' } | DB { toLin :: Level' } | 
| 24 | (-) = asFloat (-) | ||
| 25 | (*) = asFloat (*) | ||
| 26 | abs = Lin . abs . toFloat | ||
| 27 | signum = Lin . signum . toFloat | ||
| 28 | fromInteger = Lin . fromInteger | ||
| 29 | 29 | ||
| 30 | asFloat :: (Float -> Float -> Float) -> Level -> Level -> Level | 30 | instance Num Level where | 
| 31 | asFloat f (Lin x) (Lin y) = Lin $ f x y | 31 | (+) = fmap (either error id) . asFloat (+) | 
| 32 | asFloat f x y = DB $ (f `on` toFloat) x y | 32 | (-) = fmap (either error id) . asFloat (-) | 
| 33 | (*) = fmap (either error id) . asFloat (*) | ||
| 34 | abs = Lin . toLin | ||
| 35 | signum = Lin . either error id . refine . signum . toFloat | ||
| 36 | fromInteger = Lin . either error id . refine . fromInteger | ||
| 37 | |||
| 38 | asFloat :: (Float -> Float -> Float) -> Level -> Level -> Either String Level | ||
| 39 | asFloat ((`on` toFloat) -> f) x y = toLvl <$> refine (f x y) | ||
| 40 | where | ||
| 41 | toLvl | ||
| 42 | | DB _ <- x = DB | ||
| 43 | | DB _ <- y = DB | ||
| 44 | | otherwise = Lin | ||
| 33 | 45 | ||
| 34 | toFloat :: Level -> Float | 46 | toFloat :: Level -> Float | 
| 35 | toFloat (Lin x) = x | 47 | toFloat = unrefine . toLin | 
| 36 | toFloat (DB x) = x | ||
| 37 | 48 | ||
| 38 | withPrec :: (Num a, RealFrac a, HasResolution b) => a -> Fixed b | 49 | withPrec :: (Num a, RealFrac a, HasResolution b) => a -> Fixed b | 
| 39 | withPrec x = withResolution $ \p' -> MkFixed $ toInteger $ round $ x * (fromInteger p') | 50 | withPrec x = withResolution $ \p' -> MkFixed $ toInteger $ round $ x * (fromInteger p') | 
| @@ -44,39 +55,33 @@ withType f = f undefined | |||
| 44 | withResolution :: (HasResolution a) => (Integer -> f a) -> f a | 55 | withResolution :: (HasResolution a) => (Integer -> f a) -> f a | 
| 45 | withResolution f = withType (f . resolution) | 56 | withResolution f = withType (f . resolution) | 
| 46 | 57 | ||
| 47 | linToDb :: Float -> Float | 58 | linToDb :: Level' -> Float | 
| 48 | linToDb x = 20 * (logBase 10 x) | 59 | linToDb (unrefine -> x) = 20 * (logBase 10 x) | 
| 49 | 60 | ||
| 50 | dBToLin :: Float -> Float | 61 | dBToLin :: Float -> Level' | 
| 51 | dBToLin x = 10 ** (0.05 * x) | 62 | dBToLin x = either error id . refine $ 10 ** (0.05 * x) | 
| 52 | 63 | ||
| 53 | instance Show Level where | 64 | instance Show Level where | 
| 54 | show (Lin x) = show x | 65 | show (Lin x) = show x | 
| 55 | show (DB x) = (show $ (withPrec x' :: Milli)) ++ "dB" | 66 | show (DB (linToDb -> x)) = (show $ (withPrec x :: Milli)) ++ "dB" | 
| 56 | where | ||
| 57 | x' = linToDb x | ||
| 58 | 67 | ||
| 59 | instance Read Level where | 68 | instance Read Level where | 
| 60 | readsPrec i = map toL . readsPrec i | 69 | readsPrec = readPrec_to_S $ parseDb <|> parseLin | 
| 61 | where | 70 | where | 
| 62 | toL :: (Float, String) -> (Level, String) | 71 | parseDb = do | 
| 63 | toL (f, str) | 72 | db <- readS_to_Prec readsPrec | 
| 64 | | ((==) `on` CI.mk) prec unit = (DB $ dBToLin f, rest) | 73 | let | 
| 65 | | otherwise = (Lin f, str) | 74 | unit@(length -> lU) = "dB" | 
| 66 | where | 75 | unit' <- forM [1..lU] $ const get | 
| 67 | prec = take lU str | 76 | guard $ ((==) `on` CI.mk) unit unit' | 
| 68 | rest = drop lU str | 77 | return . DB $ dBToLin db | 
| 69 | unit = "dB" | 78 | parseLin = Lin <$> readS_to_Prec readsPrec | 
| 70 | lU = length unit | ||
| 71 | 79 | ||
| 72 | instance Eq Level where | 80 | instance Eq Level where | 
| 73 | (Lin a) == (Lin b) = a == b | 81 | (==) = (==) `on` toLin | 
| 74 | (Lin a) == (DB b) = a == b | ||
| 75 | (DB a) == (Lin b) = a == b | ||
| 76 | (DB a) == (DB b) = a == b | ||
| 77 | 82 | ||
| 78 | instance Default Level where | 83 | instance Default Level where | 
| 79 | def = Lin 0 | 84 | def = Lin $$(refineTH 0) | 
| 80 | 85 | ||
| 81 | data Adjustment a = Set a | 86 | data Adjustment a = Set a | 
| 82 | | Add a | 87 | | Add a | 
