module Harmonic.Rules.Import.Transform (
buildTransitionCounts, buildTransitionCountsPerPiece,
sliceInterpretations,
) where
import Harmonic.Rules.Import.Types
import qualified Data.Map.Strict as Map
import qualified Data.List as L
import Data.List (sortOn)
import Harmonic.Evaluation.Analysis.Markov (TransitionCounts)
import qualified Harmonic.Rules.Types.Harmony as H
import qualified Harmonic.Evaluation.Scoring.Dissonance as D
import qualified Harmonic.Rules.Constraints.Overtone as O
sliceInterpretations :: ChordSlice -> [(H.Chord, Double)]
sliceInterpretations :: ChordSlice -> [(Chord, Double)]
sliceInterpretations ChordSlice
slice =
let ranked :: [(Chord, Double)]
ranked = ChordSlice -> [(Chord, Double)]
forall {b}. Fractional b => ChordSlice -> [(Chord, b)]
rankedTriads ChordSlice
slice
in if [(Chord, Double)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Chord, Double)]
ranked
then [([Int] -> Chord
H.flatTriad (ChordSlice -> [Int]
slicePitches ChordSlice
slice), Double
1)]
else [(Chord, Double)]
ranked
where
rankedTriads :: ChordSlice -> [(Chord, b)]
rankedTriads ChordSlice
sl =
let fundamental :: Int
fundamental = ChordSlice -> Int
sliceFundamental ChordSlice
sl
uniquePcs :: [Int]
uniquePcs = [Int] -> [Int]
forall a. Eq a => [a] -> [a]
L.nub (ChordSlice -> [Int]
slicePitches ChordSlice
sl)
overtones :: [Int]
overtones = (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
fundamental) [Int]
uniquePcs
candidates :: [[Int]]
candidates = (Int, [Int]) -> [[Int]]
forall a. (Integral a, Num a) => (a, [a]) -> [[a]]
O.possibleTriads'' (Int
fundamental, [Int]
overtones)
scored :: [(Integer, Chord)]
scored = ([Int] -> (Integer, Chord)) -> [[Int]] -> [(Integer, Chord)]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> (Integer, Chord)
score [[Int]]
candidates
top :: [(Integer, Chord)]
top = Int -> [(Integer, Chord)] -> [(Integer, Chord)]
forall a. Int -> [a] -> [a]
take Int
3 (((Integer, Chord) -> Integer)
-> [(Integer, Chord)] -> [(Integer, Chord)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Integer, Chord) -> Integer
forall a b. (a, b) -> a
fst [(Integer, Chord)]
scored)
raw :: [(Chord, b)]
raw = [Chord] -> [b] -> [(Chord, b)]
forall a b. [a] -> [b] -> [(a, b)]
zip (((Integer, Chord) -> Chord) -> [(Integer, Chord)] -> [Chord]
forall a b. (a -> b) -> [a] -> [b]
map (Integer, Chord) -> Chord
forall a b. (a, b) -> b
snd [(Integer, Chord)]
top) [b
3, b
2, b
1]
total :: b
total = [b] -> b
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((Chord, b) -> b) -> [(Chord, b)] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map (Chord, b) -> b
forall a b. (a, b) -> b
snd [(Chord, b)]
raw)
in [ (Chord
chord, b
w b -> b -> b
forall a. Fractional a => a -> a -> a
/ b
total) | (Chord
chord, b
w) <- [(Chord, b)]
raw ]
score :: [Int] -> (Integer, Chord)
score [Int]
triad =
let pcs :: [Int]
pcs = (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]
triad
(Integer
diss, [Int]
_) = [Int] -> (Integer, [Int])
D.dissonanceLevel [Int]
pcs
in (Integer
diss, [Int] -> Chord
H.flatTriad [Int]
pcs)
buildTransitionCounts :: [ChordSlice] -> TransitionCounts
buildTransitionCounts :: [ChordSlice] -> TransitionCounts
buildTransitionCounts [ChordSlice]
slices =
let ts :: [[(Chord, Double)]]
ts = (ChordSlice -> [(Chord, Double)])
-> [ChordSlice] -> [[(Chord, Double)]]
forall a b. (a -> b) -> [a] -> [b]
map ChordSlice -> [(Chord, Double)]
sliceInterpretations [ChordSlice]
slices
triples :: [([(Chord, Double)], [(Chord, Double)], [(Chord, Double)])]
triples = [[(Chord, Double)]]
-> [[(Chord, Double)]]
-> [[(Chord, Double)]]
-> [([(Chord, Double)], [(Chord, Double)], [(Chord, Double)])]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [[(Chord, Double)]]
ts (Int -> [[(Chord, Double)]] -> [[(Chord, Double)]]
forall a. Int -> [a] -> [a]
drop Int
1 [[(Chord, Double)]]
ts) (Int -> [[(Chord, Double)]] -> [[(Chord, Double)]]
forall a. Int -> [a] -> [a]
drop Int
2 [[(Chord, Double)]]
ts)
in (Double -> Double -> Double)
-> [TransitionCounts] -> TransitionCounts
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
(a -> a -> a) -> f (Map k a) -> Map k a
Map.unionsWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(+)
[ (Double -> Double -> Double)
-> [(Edge, Double)] -> TransitionCounts
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(+)
[ ( ( Cadence -> Cadence
corpusNamed ((Chord, Chord) -> Cadence
H.toCadence (Chord
a, Chord
b))
, Cadence -> Cadence
corpusNamed ((Chord, Chord) -> Cadence
H.toCadence (Chord
b, Chord
c)) )
, Double
wa Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
wb Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
wc )
| (Chord
a, Double
wa) <- [(Chord, Double)]
t1, (Chord
b, Double
wb) <- [(Chord, Double)]
t2, (Chord
c, Double
wc) <- [(Chord, Double)]
t3
]
| ([(Chord, Double)]
t1, [(Chord, Double)]
t2, [(Chord, Double)]
t3) <- [([(Chord, Double)], [(Chord, Double)], [(Chord, Double)])]
triples
]
where
corpusNamed :: Cadence -> Cadence
corpusNamed Cadence
c =
Cadence
c { H.cadenceFunctionality = H.corpusFunctionality (H.cadenceIntervals c) }
buildTransitionCountsPerPiece :: [[ChordSlice]] -> TransitionCounts
buildTransitionCountsPerPiece :: [[ChordSlice]] -> TransitionCounts
buildTransitionCountsPerPiece = (Double -> Double -> Double)
-> [TransitionCounts] -> TransitionCounts
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
(a -> a -> a) -> f (Map k a) -> Map k a
Map.unionsWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(+) ([TransitionCounts] -> TransitionCounts)
-> ([[ChordSlice]] -> [TransitionCounts])
-> [[ChordSlice]]
-> TransitionCounts
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([ChordSlice] -> TransitionCounts)
-> [[ChordSlice]] -> [TransitionCounts]
forall a b. (a -> b) -> [a] -> [b]
map [ChordSlice] -> TransitionCounts
buildTransitionCounts