module Harmonic.Rules.Import.Transform (
buildCadences, buildCadencesPerPiece,
fundamentals,
) where
import Harmonic.Rules.Import.Types
import qualified Data.Vector as V
import qualified Data.List as L
import Data.List (sortOn)
import qualified Harmonic.Rules.Types.Harmony as H
import qualified Harmonic.Evaluation.Scoring.Dissonance as D
import qualified Harmonic.Rules.Constraints.Overtone as O
fundamentals :: V.Vector [Int] -> [Int]
fundamentals :: Vector [Int] -> [Int]
fundamentals Vector [Int]
v = Vector Int -> [Int]
forall a. Vector a -> [a]
V.toList (Vector Int -> [Int]) -> Vector Int -> [Int]
forall a b. (a -> b) -> a -> b
$ ([Int] -> Int) -> Vector [Int] -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map [Int] -> Int
fundamental Vector [Int]
v
where
fundamental :: [Int] -> Int
fundamental :: [Int] -> Int
fundamental [] = Int
0
fundamental [Int]
xs = [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Int]
xs
buildCadences :: [ChordSlice] -> [H.Cadence]
buildCadences :: [ChordSlice] -> [Cadence]
buildCadences [ChordSlice]
slices =
let triadOptions :: [[Chord]]
triadOptions = (ChordSlice -> [Chord]) -> [ChordSlice] -> [[Chord]]
forall a b. (a -> b) -> [a] -> [b]
map ChordSlice -> [Chord]
sliceTriads [ChordSlice]
slices
transitions :: [([Chord], [Chord])]
transitions = [[Chord]] -> [[Chord]] -> [([Chord], [Chord])]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Chord]]
triadOptions (Int -> [[Chord]] -> [[Chord]]
forall a. Int -> [a] -> [a]
drop Int
1 [[Chord]]
triadOptions)
in (([Chord], [Chord]) -> [Cadence])
-> [([Chord], [Chord])] -> [Cadence]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Chord], [Chord]) -> [Cadence]
expand [([Chord], [Chord])]
transitions
where
expand :: ([Chord], [Chord]) -> [Cadence]
expand ([Chord]
fromChoices, [Chord]
toChoices) =
[ (Chord, Chord) -> Cadence
H.toCadence (Chord
fromChord, Chord
toChord)
| Chord
fromChord <- [Chord]
fromChoices
, Chord
toChord <- [Chord]
toChoices
]
sliceTriads :: ChordSlice -> [Chord]
sliceTriads ChordSlice
slice =
let ranked :: [Chord]
ranked = ChordSlice -> [Chord]
rankedTriads ChordSlice
slice
in if [Chord] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Chord]
ranked
then [[Int] -> Chord
H.flatTriad (ChordSlice -> [Int]
slicePitches ChordSlice
slice)]
else [Chord]
ranked
rankedTriads :: ChordSlice -> [Chord]
rankedTriads ChordSlice
slice =
let fundamental :: Int
fundamental = ChordSlice -> Int
sliceFundamental ChordSlice
slice
uniquePcs :: [Int]
uniquePcs = [Int] -> [Int]
forall a. Eq a => [a] -> [a]
L.nub (ChordSlice -> [Int]
slicePitches ChordSlice
slice)
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)
weights :: [Int]
weights = [Int
3,Int
2,Int
1]
in [[Chord]] -> [Chord]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Chord]] -> [Chord]) -> [[Chord]] -> [Chord]
forall a b. (a -> b) -> a -> b
$ (Int -> Chord -> [Chord]) -> [Int] -> [Chord] -> [[Chord]]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Chord -> [Chord]
forall a. Int -> a -> [a]
replicate [Int]
weights (((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)
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
chord :: Chord
chord = [Int] -> Chord
H.flatTriad [Int]
pcs
(Integer
diss, [Int]
_) = [Int] -> (Integer, [Int])
D.dissonanceLevel [Int]
pcs
in (Integer
diss, Chord
chord)
buildCadencesPerPiece :: [[ChordSlice]] -> [H.Cadence]
buildCadencesPerPiece :: [[ChordSlice]] -> [Cadence]
buildCadencesPerPiece [[ChordSlice]]
pieces = ([ChordSlice] -> [Cadence]) -> [[ChordSlice]] -> [Cadence]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [ChordSlice] -> [Cadence]
buildCadences [[ChordSlice]]
pieces