-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDurCalc.hs
More file actions
98 lines (82 loc) · 3.14 KB
/
DurCalc.hs
File metadata and controls
98 lines (82 loc) · 3.14 KB
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
-- This file is part of KSQuant2.
-- Copyright (c) 2010 - 2011, Kilian Sprotte. All rights reserved.
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
module DurCalc (notableDur
, notableDurL
, divToRatio
, dotFactor
, exp2
, isExp2)
where
import Data.Ratio ( numerator, denominator, (%) )
-- | Compute @2^n@ for any integer @n@.
exp2 :: Integer -> Rational
exp2 n | n >= 0 = 2^n
| otherwise = 1 / (2^abs n)
isExp2 :: Rational -> Bool
isExp2 r | r == 1 = True
| r > 1 && denominator r == 1 = isPowerOfTwo (numerator r)
| r < 1 && numerator r == 1 = isPowerOfTwo (denominator r)
| otherwise = False
isPowerOfTwo :: Integer -> Bool
isPowerOfTwo 1 = True
isPowerOfTwo x | x > 1 = even x && isPowerOfTwo (x `div` 2)
isPowerOfTwo _ = error "isPowerOfTwo"
lowerPowerOfTwo :: Integer -> Integer
lowerPowerOfTwo 1 = 1
lowerPowerOfTwo x | x > 1 = if isPowerOfTwo x then
x
else
lowerPowerOfTwo (x-1)
lowerPowerOfTwo _ = error "lowerPowerOfTwo"
-- e.g. when we divide by 9 the tuplet ratio will be 8 % 9
divToRatio :: Integer -> Rational
divToRatio d = lowerPowerOfTwo d % d
-- notableDur' :: Rational -> Bool
-- notableDur' x = h (numerator x) (denominator x)
-- where h 1 d = isPowerOfTwo d
-- h 3 d = isPowerOfTwo d && d >= 2
-- h 7 d = isPowerOfTwo d && d >= 4
-- -- 15 = 1 + 2 + 4 + 8
-- h 15 d = isPowerOfTwo d && d >= 8
-- h _ _ = False
notableDur' :: Integer -> Rational -> Bool
notableDur' maxDots r | maxDots == 0 = isExp2 r
| maxDots > 0 = notableDur' (maxDots - 1) r ||
notableDur' 0 (r / dotFactor maxDots)
| otherwise = error "notableDur' maxDots < 0"
notableDur :: Integer -> Rational -> Bool
notableDur maxDots x = notableDur' maxDots (abs x)
notableDurL :: Rational -> Rational -> Bool
notableDurL l x | abs x <= abs l = notableDur 3 x
| otherwise = False
-- | Compute a factor for a given number of augmentation dots.
--
-- The duration of a dotted note with duration @a@ and @n@ dots can be
-- obtained by @a * 'dotFactor' n@.
--
--
-- Examples:
--
-- >>> dotFactor 0
-- 1
--
-- >>> dotFactor 1
-- 3 % 2
--
-- >>> dotFactor 2
-- 7 % 4
--
dotFactor :: Integer -- ^ number of augmentation dots
-> Rational -- ^ factor
dotFactor n | n >= 0 = 2 - (1 % (2^n))
| otherwise = error "dotFactor not defined on negative n"