1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module Trivmix.Types
( Level
, toFloat
, Adjustment(..)
, doAdjustment
, module Data.Default
) where
import Data.Fixed
import Data.CaseInsensitive ( CI )
import qualified Data.CaseInsensitive as CI
import Data.Default
import Data.Function (on)
data Level = Lin Float | DB Float
instance Num Level where
(+) = asFloat (+)
(-) = asFloat (-)
(*) = asFloat (*)
abs = Lin . abs . toFloat
signum = Lin . signum . toFloat
fromInteger = Lin . fromInteger
asFloat :: (Float -> Float -> Float) -> Level -> Level -> Level
asFloat f (Lin x) (Lin y) = Lin $ f x y
asFloat f x y = DB $ (f `on` toFloat) x y
toFloat :: Level -> Float
toFloat (Lin x) = x
toFloat (DB x) = x
withPrec :: (Num a, RealFrac a, HasResolution b) => a -> Fixed b
withPrec x = withResolution $ \p' -> MkFixed $ toInteger $ round $ x * (fromInteger p')
withType :: (p a -> f a) -> f a
withType f = f undefined
withResolution :: (HasResolution a) => (Integer -> f a) -> f a
withResolution f = withType (f . resolution)
linToDb :: Float -> Float
linToDb x = 20 * (logBase 10 x)
dBToLin :: Float -> Float
dBToLin x = 10 ** (0.05 * x)
instance Show Level where
show (Lin x) = show x
show (DB x) = (show $ (withPrec x' :: Milli)) ++ "dB"
where
x' = linToDb x
instance Read Level where
readsPrec i = map toL . readsPrec i
where
toL :: (Float, String) -> (Level, String)
toL (f, str)
| ((==) `on` CI.mk) prec unit = (DB $ dBToLin f, rest)
| otherwise = (Lin f, str)
where
prec = take lU str
rest = drop lU str
unit = "dB"
lU = length unit
instance Eq Level where
(Lin a) == (Lin b) = a == b
(Lin a) == (DB b) = a == b
(DB a) == (Lin b) = a == b
(DB a) == (DB b) = a == b
instance Default Level where
def = Lin 0
data Adjustment a = Set a
| Add a
| Sub a
deriving (Show, Eq)
class Adjustable a where
add :: a -> a -> a
sub :: a -> a -> a
-- instance Num a => Adjustable a where
-- add = (+)
-- sub = (-)
instance Adjustable Level where
add (DB x) (DB y) = DB $ dBToLin $ ((+) `on` linToDb) x y
add x y = x + y
sub (DB x) (DB y) = DB $ dBToLin $ ((-) `on` linToDb) x y
sub x y = x - y
doAdjustment :: Adjustable a => a -> Adjustment a -> a
doAdjustment _ (Set y) = y
doAdjustment x (Add y) = add x y
doAdjustment x (Sub y) = sub x y
|