module Music.Theory.Meter.Barlow_1987 where
import Data.List
import Data.Numbers.Primes
import Music.Theory.Math (R)
traceShow :: a -> b -> b
traceShow _ x = x
at :: (Integral n) => [a] -> n -> a
at x i = x `genericIndex` (i 1)
at' :: (Num a,Show a,Integral n,Show n,Show m) => m -> [a] -> n -> a
at' m x i =
let n = genericLength x
in if i == 0 || i == n + 1
then 1
else if i < 0 || i > n + 1
then error (show ("at'",m,x,i))
else x `genericIndex` (i 1)
mod' :: (Integral a,Show a) => a -> a -> a
mod' a b =
let r = mod a b
in if r < 0 || r >= b
then error (show ("mod'",a,b,r))
else r
to_r :: (Integral n,Show n) => n -> R
to_r = fromIntegral
div' :: (Integral a,Show a) => String -> a -> a -> a
div' m i j =
if i < 0 || j < 0
then error (show ("div'",m,i,j))
else truncate (to_r i / to_r j)
type Stratification t = [t]
indispensibilities :: (Integral n,Show n) => Stratification n -> [n]
indispensibilities x = map (lower_psi x (genericLength x)) [1 .. product x]
lower_psi :: (Integral a,Show a) => Stratification a -> a -> a -> a
lower_psi q z n =
let s8 r =
let s1 = product q
s2 = (n 2) `mod'` s1
s3 = let f k = at' "s3" q (z + 1 k)
in product (map f [0 .. r])
s4 = 1 + div' "s4" s2 s3
c = at' "c" q (z r)
s5 = s4 `mod'` c
s6 = upper_psi c (1 + s5)
s7 = let f = at' "s7" q
in product (map f [0 .. z r 1])
in traceShow ("lower_psi:s",s1,s2,s3,s4,s5,s6,s7) (s7 * s6)
in traceShow ("lower_psi",q,z,n) (sum (map s8 [0 .. z 1]))
reverse_primes :: (Integral n,Show n) => n -> [n]
reverse_primes n = reverse (genericTake n primes)
prime_stratification :: (Integral n,Show n) => n -> Stratification n
prime_stratification =
let go x k =
case x of
p:x' -> if k `rem` p == 0
then p : go x (div' "ps" k p)
else go x' k
[] -> []
in go (reverse_primes 14)
upper_psi :: (Integral a,Show a) => a -> a -> a
upper_psi p n =
if p `notElem` reverse_primes 14
then error (show ("upper_psi","not prime",p,n))
else if p == 2
then p n
else if n == p 1
then div' "upper_psi" p 4
else let n' = n div' "n'" n p
s = prime_stratification (p 1)
q = lower_psi s (genericLength s) n'
q' = to_r q
p' = to_r p
in truncate (q' + 2 * sqrt ((q' + 1) / p'))
thinning_table :: (Integral n,Show n) => Stratification n -> [[Bool]]
thinning_table s =
let x = indispensibilities s
n = genericLength x
true i = genericReplicate i True
false i = genericReplicate i False
f i = true (i + 1) ++ false (n i 1)
in transpose (map f x)
thinning_table_pp :: (Integral n,Show n) => Stratification n -> String
thinning_table_pp s =
let f x = if x then '*' else '.'
in unlines (map (map f) (thinning_table s))
relative_to_length :: (Real a, Fractional b) => [a] -> [b]
relative_to_length x =
let n = length x 1
in map ((/ fromIntegral n) . realToFrac) x
relative_indispensibilities :: (Integral n,Show n) => Stratification n -> [R]
relative_indispensibilities = relative_to_length . indispensibilities
align_meters :: (t -> [b]) -> t -> t -> [(b,b)]
align_meters f s1 s2 =
let i1 = f s1
i2 = f s2
n1 = length i1
n2 = length i2
n = lcm n1 n2
i1' = concat (replicate (n `div` n1) i1)
i2' = concat (replicate (n `div` n2) i2)
in zip i1' i2'
type S_MM t = ([t],t)
whole_div :: Integral a => a -> a -> a
whole_div i j =
case i `divMod` j of
(k,0) -> k
_ -> error "whole_div"
whole_quot :: Integral a => a -> a -> a
whole_quot i j =
case i `quotRem` j of
(k,0) -> k
_ -> error "whole_quot"
prolong_stratifications :: (Integral n,Show n) => S_MM n -> S_MM n -> ([n],[n])
prolong_stratifications (s1,v1) (s2,v2) =
let t1 = product s1 * v1
t2 = product s2 * v2
t = lcm t1 t2
s1' = s1 ++ prime_stratification (t `whole_div` t1)
s2' = s2 ++ prime_stratification (t `whole_div` t2)
in (s1',s2')
mean :: Fractional a => [a] -> a
mean x = sum x / fromIntegral (length x)
square :: Num a => a -> a
square n = n * n
align_s_mm :: (Integral n,Show n) => ([n] -> [t]) -> S_MM n -> S_MM n -> [(t,t)]
align_s_mm f (s1,v1) (s2,v2) =
let (s1',s2') = prolong_stratifications (s1,v1) (s2,v2)
in align_meters f s1' s2'
upper_psi' :: (Integral a,Show a) => a -> a -> a
upper_psi' h n =
if h > 3
then let omega x = if x == 0 then 0 else 1
h4 = div' "h4" h 4
n' = n 1 + omega (h n)
p = prime_stratification (h 1)
x0 = lower_psi p (genericLength p) n'
x1 = x0 + omega (div' "z" x0 h4)
x2 = omega (h n 1)
x3 = x2 + h4 * (1 x2)
in traceShow ("upper_psi'",h,n,n',x0,x1,x2,x3) (x1 * x3)
else (h + n 2) `mod'` h
mps_limit :: Floating a => a -> a
mps_limit n = sum [n ** 4 / 9
,n ** 3 / 3
,13 * (n ** 2 ) / 36
,n / 6
,1 / 36]
mean_square_product :: Fractional n => [(n,n)] -> n
mean_square_product x =
let f = square . uncurry (*)
n = fromIntegral (length x)
in sum (map f x) / square n
metrical_affinity :: (Integral n,Show n) => [n] -> n -> [n] -> n -> R
metrical_affinity s1 v1 s2 v2 =
let (s1',s2') = prolong_stratifications (s1,v1) (s2,v2)
i1 = relative_indispensibilities s1'
i2 = relative_indispensibilities s2'
v = lcm v1 v2
i1' = concat (genericReplicate (v `div` v1) i1)
i2' = concat (genericReplicate (v `div` v2) i2)
in mean_square_product (zip i1' i2')
metrical_affinity' :: (Integral t,Show t) => [t] -> t -> [t] -> t -> R
metrical_affinity' s1 v1 s2 v2 =
let (s1',s2') = prolong_stratifications (s1,v1) (s2,v2)
ix :: (Integer -> x) -> Integer -> x
ix f i = case i of
1 -> f 1
2 -> f 2
_ -> error (show ("ix",i))
s = ix (at [s1,s2])
v = ix (at [v1,v2])
u = ix (genericLength . s)
s' = ix (at [s1',s2'])
z = ix (genericLength . s')
q i j = s i `at` j
omega_u i = product (map (q i) [1::Int .. u i])
omega_z _ = lcm (v 1 * omega_u 1) (v 2 * omega_u 2)
omega_0 = lcm (product (s' 1)) (product (s' 2))
x0 n i = lower_psi (s' i) (z i) (1 + ((n 1) `mod'` omega_z i))
x1 n = square (product (map (x0 n) [1,2]))
x2 = sum (map x1 [1 .. omega_0])
x3 = 18 * x2 2
x4 i = square (omega_z i 1)
x5 = product (map x4 [1::Integer,2])
x6 = 7 * omega_0 * x5
x7 = to_r x3 / to_r x6
x8 = 2 * log x7
x9 = negate (recip x8)
in traceShow (omega_z,omega_0,x2,x3,x5,x6,x7,x8,x9) x9