{-# LANGUAGE DeriveGeneric #-}
module Harmonic.Evaluation.Scoring.Dissonance
(
dissonanceLevel
, dissonanceScore
, hindemithVector
, intervalVector
, intervalClass
, rootMotionVector
, rootMotionScore
, mostConsonant
, rankByConsonance
) where
import GHC.Generics (Generic)
import Data.Function (on)
import Data.List (sortBy, sort, nub)
import Harmonic.Rules.Types.Pitch (PitchClass(..), mkPitchClass, unPitchClass)
hindemithVector :: [Integer]
hindemithVector :: [Integer]
hindemithVector = [Integer
16, Integer
8, Integer
4, Integer
2, Integer
1, Integer
24]
{-# INLINE hindemithVector #-}
rootMotionVector :: [Integer]
rootMotionVector :: [Integer]
rootMotionVector = [Integer
3, Integer
3, Integer
4, Integer
4, Integer
1, Integer
6]
{-# INLINE rootMotionVector #-}
rootMotionScore :: Int -> Integer
rootMotionScore :: Int -> Integer
rootMotionScore Int
n
| Int
ic Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Integer
2
| Bool
otherwise = [Integer]
rootMotionVector [Integer] -> Int -> Integer
forall a. HasCallStack => [a] -> Int -> a
!! (Int
ic Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
where ic :: Int
ic = Int -> Int
intervalClass Int
n
{-# INLINE rootMotionScore #-}
intervalClass :: Int -> Int
intervalClass :: Int -> Int
intervalClass Int
n
| Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
6 = Int
m
| Bool
otherwise = Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
m
where m :: Int
m = Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
{-# INLINE intervalClass #-}
intervalVector :: [Int] -> [Integer]
intervalVector :: [Int] -> [Integer]
intervalVector [Int]
xs = [Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int -> Int
vectCounts Int
ic) | Int
ic <- [Int
1..Int
6]]
where
pitches :: [Int]
pitches = [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ [Int] -> [Int]
forall a. Eq a => [a] -> [a]
nub ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12) [Int]
xs
pairs :: [(Int, Int)]
pairs = [(Int
a, Int
b) | Int
a <- [Int]
pitches, Int
b <- [Int]
pitches, Int
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
b]
intervals :: [Int]
intervals = [Int -> Int
intervalClass (Int
b Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
a) | (Int
a, Int
b) <- [(Int, Int)]
pairs]
vectCounts :: Int -> Int
vectCounts Int
ic = [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
ic) [Int]
intervals
intervalVectorPC :: [PitchClass] -> [Integer]
intervalVectorPC :: [PitchClass] -> [Integer]
intervalVectorPC [PitchClass]
pcs = [Int] -> [Integer]
intervalVector ([Int] -> [Integer]) -> [Int] -> [Integer]
forall a b. (a -> b) -> a -> b
$ (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
unPitchClass [PitchClass]
pcs
dissonanceLevel :: [Int] -> (Integer, [Int])
dissonanceLevel :: [Int] -> (Integer, [Int])
dissonanceLevel [Int]
xs
| [Integer] -> Integer -> Int
forall a. Eq a => [a] -> a -> Int
countElem [Integer]
iVect Integer
0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
5 = (Integer
27, [Int]
xs)
| [Int] -> Bool
hasPerfectFifth [Int]
xs = (Integer
baseDiss Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1, [Int]
xs)
| Bool
otherwise = (Integer
baseDiss, [Int]
xs)
where
iVect :: [Integer]
iVect = [Int] -> [Integer]
intervalVector [Int]
xs
baseDiss :: Integer
baseDiss = [Integer] -> Integer
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Integer] -> Integer) -> [Integer] -> Integer
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer)
-> [Integer] -> [Integer] -> [Integer]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(*) [Integer]
hindemithVector [Integer]
iVect
dissonanceScore :: [Int] -> Integer
dissonanceScore :: [Int] -> Integer
dissonanceScore = (Integer, [Int]) -> Integer
forall a b. (a, b) -> a
fst ((Integer, [Int]) -> Integer)
-> ([Int] -> (Integer, [Int])) -> [Int] -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> (Integer, [Int])
dissonanceLevel
hasPerfectFifth :: [Int] -> Bool
hasPerfectFifth :: [Int] -> Bool
hasPerfectFifth [] = Bool
False
hasPerfectFifth (Int
root:[Int]
rest) =
let p5 :: Int
p5 = (Int
root Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
7) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
in (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Int
x -> Int
x Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
p5) [Int]
rest
countElem :: Eq a => [a] -> a -> Int
countElem :: forall a. Eq a => [a] -> a -> Int
countElem [a]
xs a
x = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([a] -> Int) -> [a] -> Int
forall a b. (a -> b) -> a -> b
$ (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x) [a]
xs
mostConsonant :: [[Int]] -> [Int]
mostConsonant :: [[Int]] -> [Int]
mostConsonant [] = [Int
0, Int
4, Int
7]
mostConsonant [[Int]]
xs = (Integer, [Int]) -> [Int]
forall a b. (a, b) -> b
snd ((Integer, [Int]) -> [Int])
-> ([(Integer, [Int])] -> (Integer, [Int]))
-> [(Integer, [Int])]
-> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Integer, [Int])] -> (Integer, [Int])
forall a. HasCallStack => [a] -> a
head ([(Integer, [Int])] -> (Integer, [Int]))
-> ([(Integer, [Int])] -> [(Integer, [Int])])
-> [(Integer, [Int])]
-> (Integer, [Int])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Integer, [Int])] -> [(Integer, [Int])]
forall {b}. [(Integer, b)] -> [(Integer, b)]
sortByFst ([(Integer, [Int])] -> [Int]) -> [(Integer, [Int])] -> [Int]
forall a b. (a -> b) -> a -> b
$ ([Int] -> (Integer, [Int])) -> [[Int]] -> [(Integer, [Int])]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> (Integer, [Int])
dissonanceLevel [[Int]]
xs
where
sortByFst :: [(Integer, b)] -> [(Integer, b)]
sortByFst = ((Integer, b) -> (Integer, b) -> Ordering)
-> [(Integer, b)] -> [(Integer, b)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Integer -> Integer -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Integer -> Integer -> Ordering)
-> ((Integer, b) -> Integer)
-> (Integer, b)
-> (Integer, b)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Integer, b) -> Integer
forall a b. (a, b) -> a
fst)
rankByConsonance :: [[Int]] -> [[Int]]
rankByConsonance :: [[Int]] -> [[Int]]
rankByConsonance [[Int]]
xs = ((Integer, [Int]) -> [Int]) -> [(Integer, [Int])] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map (Integer, [Int]) -> [Int]
forall a b. (a, b) -> b
snd ([(Integer, [Int])] -> [[Int]]) -> [(Integer, [Int])] -> [[Int]]
forall a b. (a -> b) -> a -> b
$ ((Integer, [Int]) -> (Integer, [Int]) -> Ordering)
-> [(Integer, [Int])] -> [(Integer, [Int])]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Integer -> Integer -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Integer -> Integer -> Ordering)
-> ((Integer, [Int]) -> Integer)
-> (Integer, [Int])
-> (Integer, [Int])
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Integer, [Int]) -> Integer
forall a b. (a, b) -> a
fst) ([(Integer, [Int])] -> [(Integer, [Int])])
-> [(Integer, [Int])] -> [(Integer, [Int])]
forall a b. (a -> b) -> a -> b
$ ([Int] -> (Integer, [Int])) -> [[Int]] -> [(Integer, [Int])]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> (Integer, [Int])
dissonanceLevel [[Int]]
xs
rankByConsonanceWithScores :: [[Int]] -> [(Integer, [Int])]
rankByConsonanceWithScores :: [[Int]] -> [(Integer, [Int])]
rankByConsonanceWithScores [[Int]]
xs = ((Integer, [Int]) -> (Integer, [Int]) -> Ordering)
-> [(Integer, [Int])] -> [(Integer, [Int])]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Integer -> Integer -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Integer -> Integer -> Ordering)
-> ((Integer, [Int]) -> Integer)
-> (Integer, [Int])
-> (Integer, [Int])
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Integer, [Int]) -> Integer
forall a b. (a, b) -> a
fst) ([(Integer, [Int])] -> [(Integer, [Int])])
-> [(Integer, [Int])] -> [(Integer, [Int])]
forall a b. (a -> b) -> a -> b
$ ([Int] -> (Integer, [Int])) -> [[Int]] -> [(Integer, [Int])]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> (Integer, [Int])
dissonanceLevel [[Int]]
xs