{-# LANGUAGE DeriveGeneric #-}
module Harmonic.Evaluation.Scoring.VoiceLeading
(
voiceLeadingCost
, alignVoices
, totalCost
, cyclicCost
, voiceMovement
, minimalMovement
, allVoicings
, pitchPlacements
, initialCompact
, solveRoot
, solveFlow
, liteVoicing
, bassVoicing
, normalizeByFirstRoot
) where
import Data.List (sort, nub, minimumBy)
import qualified Data.List as List
import Data.Function (on)
import Data.Maybe (catMaybes)
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import qualified Data.Set as Set
import qualified Data.Vector as V
import GHC.Generics (Generic)
import Harmonic.Rules.Types.Pitch (PitchClass(..), mkPitchClass, unPitchClass, transpose)
minPitch :: Int
minPitch :: Int
minPitch = Int
7
maxPitch :: Int
maxPitch :: Int
maxPitch = Int
41
targetOctaveMin :: Int
targetOctaveMin :: Int
targetOctaveMin = Int
12
targetFirstRootMin :: Int
targetFirstRootMin :: Int
targetFirstRootMin = -Int
12
voiceMovement :: Int -> Int -> Int
voiceMovement :: Int -> Int -> Int
voiceMovement Int
from Int
to = Int -> Int
forall a. Num a => a -> a
abs (Int
to Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
from)
{-# INLINE voiceMovement #-}
minimalMovement :: PitchClass -> PitchClass -> Int
minimalMovement :: PitchClass -> PitchClass -> Int
minimalMovement (P Int
from) (P Int
to) =
let up :: Int
up = (Int
to Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
from) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
down :: Int
down = (Int
from Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
to) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
in Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
up Int
down
{-# INLINE minimalMovement #-}
voiceLeadingCost :: [Int] -> [Int] -> Int
voiceLeadingCost :: [Int] -> [Int] -> Int
voiceLeadingCost [Int]
from [Int]
to
| [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
from Bool -> Bool -> Bool
|| [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
to = Int
0
| [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
from Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
to =
let ([Int]
from', [Int]
to') = [Int] -> [Int] -> ([Int], [Int])
alignVoices [Int]
from [Int]
to
in [Int] -> [Int] -> Int
voiceLeadingCost [Int]
from' [Int]
to'
| [Int]
from [Int] -> [Int] -> Bool
forall a. Eq a => a -> a -> Bool
== [Int]
to = Int
0
| Bool
otherwise =
Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int
baseCost Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
parallelPenalty Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
leapPenalty
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
registerExchangePenalty Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
contraryBonus Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
stepwiseBonus)
where
movements :: [Int]
movements = (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Int -> Int
voiceMovement [Int]
from [Int]
to
signedMoves :: [Int]
signedMoves = (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Int]
to [Int]
from
voiceData :: [(Int, Int, Int)]
voiceData = [Int] -> [Int] -> [Int] -> [(Int, Int, Int)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Int]
from [Int]
to [Int]
signedMoves
pairsAll :: [((Int, Int, Int), (Int, Int, Int))]
pairsAll = [ ((Int, Int, Int)
a, (Int, Int, Int)
b) | ((Int, Int, Int)
a : [(Int, Int, Int)]
rest) <- [(Int, Int, Int)] -> [[(Int, Int, Int)]]
forall a. [a] -> [[a]]
List.tails [(Int, Int, Int)]
voiceData, (Int, Int, Int)
b <- [(Int, Int, Int)]
rest ]
pairsAdj :: [((Int, Int, Int), (Int, Int, Int))]
pairsAdj = [(Int, Int, Int)]
-> [(Int, Int, Int)] -> [((Int, Int, Int), (Int, Int, Int))]
forall a b. [a] -> [b] -> [(a, b)]
zip [(Int, Int, Int)]
voiceData (Int -> [(Int, Int, Int)] -> [(Int, Int, Int)]
forall a. Int -> [a] -> [a]
drop Int
1 [(Int, Int, Int)]
voiceData)
baseCost :: Int
baseCost = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
movements
isPerfect :: a -> Bool
isPerfect a
ivl = a
ivl a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
7 Bool -> Bool -> Bool
|| a
ivl a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
isParallelPerfect :: ((a, a, a), (a, a, a)) -> Bool
isParallelPerfect ((a
f1, a
t1, a
s1), (a
f2, a
t2, a
s2)) =
let fromInt :: a
fromInt = (a
f2 a -> a -> a
forall a. Num a => a -> a -> a
- a
f1) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12
toInt :: a
toInt = (a
t2 a -> a -> a
forall a. Num a => a -> a -> a
- a
t1) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
12
in a -> Bool
forall {a}. (Eq a, Num a) => a -> Bool
isPerfect a
fromInt Bool -> Bool -> Bool
&& a
fromInt a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
toInt Bool -> Bool -> Bool
&& (a
s1 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0 Bool -> Bool -> Bool
|| a
s2 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0)
parallelPenalty :: Int
parallelPenalty = Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* [((Int, Int, Int), (Int, Int, Int))] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((((Int, Int, Int), (Int, Int, Int)) -> Bool)
-> [((Int, Int, Int), (Int, Int, Int))]
-> [((Int, Int, Int), (Int, Int, Int))]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int, Int, Int), (Int, Int, Int)) -> Bool
forall {a} {a} {a}.
(Integral a, Num a, Num a, Eq a, Eq a) =>
((a, a, a), (a, a, a)) -> Bool
isParallelPerfect [((Int, Int, Int), (Int, Int, Int))]
pairsAll)
leapPenalty :: Int
leapPenalty = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
4) [Int]
movements)
isExchange :: ((a, b, a), (a, b, a)) -> Bool
isExchange ((a
_, b
_, a
s1), (a
_, b
_, a
s2)) =
a
s1 a -> a -> a
forall a. Num a => a -> a -> a
* a
s2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
abs a
s1 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
5 Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
abs a
s2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
5
registerExchangePenalty :: Int
registerExchangePenalty = Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* [((Int, Int, Int), (Int, Int, Int))] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((((Int, Int, Int), (Int, Int, Int)) -> Bool)
-> [((Int, Int, Int), (Int, Int, Int))]
-> [((Int, Int, Int), (Int, Int, Int))]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int, Int, Int), (Int, Int, Int)) -> Bool
forall {a} {a} {b} {a} {b}.
(Ord a, Num a) =>
((a, b, a), (a, b, a)) -> Bool
isExchange [((Int, Int, Int), (Int, Int, Int))]
pairsAdj)
isContrary :: ((a, b, a), (a, b, a)) -> Bool
isContrary ((a
_, b
_, a
s1), (a
_, b
_, a
s2)) =
a
s1 a -> a -> a
forall a. Num a => a -> a -> a
* a
s2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
abs a
s1 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
4 Bool -> Bool -> Bool
&& a -> a
forall a. Num a => a -> a
abs a
s2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
4
contraryBonus :: Int
contraryBonus = (-Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* [((Int, Int, Int), (Int, Int, Int))] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((((Int, Int, Int), (Int, Int, Int)) -> Bool)
-> [((Int, Int, Int), (Int, Int, Int))]
-> [((Int, Int, Int), (Int, Int, Int))]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int, Int, Int), (Int, Int, Int)) -> Bool
forall {a} {a} {b} {a} {b}.
(Ord a, Num a) =>
((a, b, a), (a, b, a)) -> Bool
isContrary [((Int, Int, Int), (Int, Int, Int))]
pairsAll)
stepwiseBonus :: Int
stepwiseBonus =
let stepCount :: Int
stepCount = [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Int
m -> Int
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
|| Int
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2) [Int]
movements)
in if Int
stepCount Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 then -(Int
stepCount Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) else Int
0
alignVoices :: [Int] -> [Int] -> ([Int], [Int])
alignVoices :: [Int] -> [Int] -> ([Int], [Int])
alignVoices [Int]
from [Int]
to
| [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
from Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
to = ([Int]
from, [Int]
to)
| [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
from Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
to = ([Int] -> [Int] -> [Int]
forall {b}. (Num b, Ord b) => [b] -> [b] -> [b]
padTo [Int]
from [Int]
to, [Int]
to)
| Bool
otherwise = ([Int]
from, [Int] -> [Int] -> [Int]
forall {b}. (Num b, Ord b) => [b] -> [b] -> [b]
padTo [Int]
to [Int]
from)
where
padTo :: [b] -> [b] -> [b]
padTo [b]
small [b]
big =
let m :: Int
m = [b] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [b]
small
n :: Int
n = [b] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [b]
big
s :: Vector b
s = [b] -> Vector b
forall a. [a] -> Vector a
V.fromList [b]
small
b :: Vector b
b = [b] -> Vector b
forall a. [a] -> Vector a
V.fromList [b]
big
huge :: b
huge = b
10 b -> Int -> b
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
9 :: Int)
dist :: Int -> Int -> b
dist Int
j Int
i = b -> b
forall a. Num a => a -> a
abs (Vector b
b Vector b -> Int -> b
forall a. Vector a -> Int -> a
V.! Int
j b -> b -> b
forall a. Num a => a -> a -> a
- Vector b
s Vector b -> Int -> b
forall a. Vector a -> Int -> a
V.! Int
i)
row0 :: Vector (b, Int)
row0 = Int -> (Int -> (b, Int)) -> Vector (b, Int)
forall a. Int -> (Int -> a) -> Vector a
V.generate Int
m (\Int
i -> if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then (Int -> Int -> b
dist Int
0 Int
0, Int
0) else (b
huge, Int
i))
step :: Vector (b, b) -> Int -> Vector (b, Int)
step Vector (b, b)
prev Int
j = Int -> (Int -> (b, Int)) -> Vector (b, Int)
forall a. Int -> (Int -> a) -> Vector a
V.generate Int
m ((Int -> (b, Int)) -> Vector (b, Int))
-> (Int -> (b, Int)) -> Vector (b, Int)
forall a b. (a -> b) -> a -> b
$ \Int
i ->
let stayC :: b
stayC = (b, b) -> b
forall a b. (a, b) -> a
fst (Vector (b, b)
prev Vector (b, b) -> Int -> (b, b)
forall a. Vector a -> Int -> a
V.! Int
i)
diagC :: b
diagC = if Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then (b, b) -> b
forall a b. (a, b) -> a
fst (Vector (b, b)
prev Vector (b, b) -> Int -> (b, b)
forall a. Vector a -> Int -> a
V.! (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) else b
huge
best :: b
best = b -> b -> b
forall a. Ord a => a -> a -> a
min b
stayC b
diagC
prevI :: Int
prevI = if b
diagC b -> b -> Bool
forall a. Ord a => a -> a -> Bool
< b
stayC then Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else Int
i
in if b
best b -> b -> Bool
forall a. Ord a => a -> a -> Bool
>= b
huge then (b
huge, Int
i) else (Int -> Int -> b
dist Int
j Int
i b -> b -> b
forall a. Num a => a -> a -> a
+ b
best, Int
prevI)
rows :: [Vector (b, Int)]
rows = (Vector (b, Int) -> Int -> Vector (b, Int))
-> Vector (b, Int) -> [Int] -> [Vector (b, Int)]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl Vector (b, Int) -> Int -> Vector (b, Int)
forall {b}. Vector (b, b) -> Int -> Vector (b, Int)
step Vector (b, Int)
row0 [Int
1 .. Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]
backtrack :: Int -> Int -> [Int] -> [Int]
backtrack Int
j Int
i [Int]
acc
| Int
j Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int
i Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc
| Bool
otherwise = let (b
_, Int
prevI) = ([Vector (b, Int)]
rows [Vector (b, Int)] -> Int -> Vector (b, Int)
forall a. HasCallStack => [a] -> Int -> a
!! Int
j) Vector (b, Int) -> Int -> (b, Int)
forall a. Vector a -> Int -> a
V.! Int
i
in Int -> Int -> [Int] -> [Int]
backtrack (Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
prevI (Int
i Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc)
assignment :: [Int]
assignment = Int -> Int -> [Int] -> [Int]
backtrack (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) []
in (Int -> b) -> [Int] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map (Vector b
s Vector b -> Int -> b
forall a. Vector a -> Int -> a
V.!) [Int]
assignment
totalCost :: [[Int]] -> Int
totalCost :: [[Int]] -> Int
totalCost [] = Int
0
totalCost [[Int]
_] = Int
0
totalCost [[Int]]
chords = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ([Int] -> [Int] -> Int) -> [[Int]] -> [[Int]] -> [Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith [Int] -> [Int] -> Int
voiceLeadingCost [[Int]]
chords ([[Int]] -> [[Int]]
forall a. HasCallStack => [a] -> [a]
tail [[Int]]
chords)
cyclicCost :: [[Int]] -> Int
cyclicCost :: [[Int]] -> Int
cyclicCost [] = Int
0
cyclicCost [[Int]
x] = Int
0
cyclicCost [[Int]]
chords = [[Int]] -> Int
totalCost [[Int]]
chords Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> [Int] -> Int
voiceLeadingCost ([[Int]] -> [Int]
forall a. HasCallStack => [a] -> a
last [[Int]]
chords) ([[Int]] -> [Int]
forall a. HasCallStack => [a] -> a
head [[Int]]
chords)
pitchPlacements :: Int -> [Int]
pitchPlacements :: Int -> [Int]
pitchPlacements Int
pc =
let pcMod :: Int
pcMod = Int
pc Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
in (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Int
p -> Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
minPitch Bool -> Bool -> Bool
&& Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxPitch)
[Int
pcMod, Int
pcMod Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
12, Int
pcMod Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
24]
allVoicings :: [Int] -> [[Int]]
allVoicings :: [Int] -> [[Int]]
allVoicings [Int]
pcs
| [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
pcs = [[]]
| Bool
otherwise =
let placements :: [[Int]]
placements = (Int -> [Int]) -> [Int] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Int]
pitchPlacements (Int -> [Int]) -> (Int -> Int) -> Int -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12)) [Int]
pcs
allCombos :: [[Int]]
allCombos = [[Int]] -> [[Int]]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [[Int]]
placements
sorted :: [[Int]]
sorted = ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [[Int]]
allCombos
in Set [Int] -> [[Int]]
forall a. Set a -> [a]
Set.toList ([[Int]] -> Set [Int]
forall a. Ord a => [a] -> Set a
Set.fromList [[Int]]
sorted)
initialCompact :: Int -> [Int] -> [Int]
initialCompact :: Int -> [Int] -> [Int]
initialCompact Int
_ [] = []
initialCompact Int
rootPC [Int]
pcs =
let rootMod :: Int
rootMod = Int
rootPC Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
bassPos :: Int
bassPos = Int
rootMod Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
targetOctaveMin
otherPCs :: [Int]
otherPCs = (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Int
p -> Int
p Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
rootMod) ((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]
pcs)
stackAbove :: Int -> Int -> Int
stackAbove Int
bass Int
pc = [Int] -> Int
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ((Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
bass) (Int -> [Int]
pitchPlacements Int
pc))
uppers :: [Int]
uppers = (Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
stackAbove Int
bassPos) [Int]
otherPCs
in [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort (Int
bassPos Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
uppers)
type DPState = Map Int (Int, Int)
solveCyclicDP :: (Int -> [[Int]] -> [[Int]]) -> [Int] -> [[Int]] -> [[Int]]
solveCyclicDP :: (Int -> [[Int]] -> [[Int]]) -> [Int] -> [[Int]] -> [[Int]]
solveCyclicDP Int -> [[Int]] -> [[Int]]
_ [Int]
_ [] = []
solveCyclicDP Int -> [[Int]] -> [[Int]]
_ [Int]
_ [[Int]
x] = [Int -> [Int] -> [Int]
initialCompact ([Int] -> Int
bassPC [Int]
x) ([Int] -> [Int]
dedupPCs [Int]
x)]
solveCyclicDP Int -> [[Int]] -> [[Int]]
filterCandidates [Int]
rootPCs [[Int]]
rawChords =
let
chords :: [[Int]]
chords = ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> [Int]
dedupPCs [[Int]]
rawChords
n :: Int
n = [[Int]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Int]]
chords
rootPCsV :: Vector Int
rootPCsV = [Int] -> Vector Int
forall a. [a] -> Vector a
V.fromList [Int]
rootPCs
chordsV :: Vector [Int]
chordsV = [[Int]] -> Vector [Int]
forall a. [a] -> Vector a
V.fromList [[Int]]
chords
firstRootPC :: Int
firstRootPC = Vector Int -> Int
forall a. Vector a -> a
V.head Vector Int
rootPCsV
firstVoicing :: [Int]
firstVoicing = Int -> [Int] -> [Int]
initialCompact Int
firstRootPC (Vector [Int] -> [Int]
forall a. Vector a -> a
V.head Vector [Int]
chordsV)
candidatesPerPos :: V.Vector (V.Vector [Int])
candidatesPerPos :: Vector (Vector [Int])
candidatesPerPos = Int -> (Int -> Vector [Int]) -> Vector (Vector [Int])
forall a. Int -> (Int -> a) -> Vector a
V.generate Int
n ((Int -> Vector [Int]) -> Vector (Vector [Int]))
-> (Int -> Vector [Int]) -> Vector (Vector [Int])
forall a b. (a -> b) -> a -> b
$ \Int
i ->
if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then [Int] -> Vector [Int]
forall a. a -> Vector a
V.singleton [Int]
firstVoicing
else [[Int]] -> Vector [Int]
forall a. [a] -> Vector a
V.fromList ([[Int]] -> Vector [Int]) -> [[Int]] -> Vector [Int]
forall a b. (a -> b) -> a -> b
$ Int -> [[Int]] -> [[Int]]
filterCandidates (Vector Int
rootPCsV Vector Int -> Int -> Int
forall a. Vector a -> Int -> a
V.! Int
i) ([Int] -> [[Int]]
allVoicings (Vector [Int]
chordsV Vector [Int] -> Int -> [Int]
forall a. Vector a -> Int -> a
V.! Int
i))
getCandidates :: Int -> V.Vector [Int]
getCandidates :: Int -> Vector [Int]
getCandidates Int
i = Vector (Vector [Int])
candidatesPerPos Vector (Vector [Int]) -> Int -> Vector [Int]
forall a. Vector a -> Int -> a
V.! Int
i
initialDP :: DPState
initialDP :: DPState
initialDP = Int -> (Int, Int) -> DPState
forall k a. k -> a -> Map k a
Map.singleton Int
0 (Int
0, -Int
1)
forwardPass :: V.Vector DPState
forwardPass :: Vector DPState
forwardPass = [DPState] -> Vector DPState
forall a. [a] -> Vector a
V.fromList ([DPState] -> Vector DPState) -> [DPState] -> Vector DPState
forall a b. (a -> b) -> a -> b
$ (DPState -> Int -> DPState) -> DPState -> [Int] -> [DPState]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl DPState -> Int -> DPState
stepDP DPState
initialDP [Int
1..Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1]
where
stepDP :: DPState -> Int -> DPState
stepDP :: DPState -> Int -> DPState
stepDP DPState
prevState Int
pos =
let prevCands :: Vector [Int]
prevCands = Int -> Vector [Int]
getCandidates (Int
pos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
currCands :: Vector [Int]
currCands = Int -> Vector [Int]
getCandidates Int
pos
computeBest :: Int -> Maybe (Int, (Int, Int))
computeBest :: Int -> Maybe (Int, (Int, Int))
computeBest Int
currIdx =
let currVoicing :: [Int]
currVoicing = Vector [Int]
currCands Vector [Int] -> Int -> [Int]
forall a. Vector a -> Int -> a
V.! Int
currIdx
costs :: [(Int, Int, Int)]
costs = [(Int
prevIdx, Int
cost Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> [Int] -> Int
voiceLeadingCost [Int]
prevVoicing [Int]
currVoicing, Int
prevIdx)
| (Int
prevIdx, (Int
cost, Int
_)) <- DPState -> [(Int, (Int, Int))]
forall k a. Map k a -> [(k, a)]
Map.toList DPState
prevState
, let prevVoicing :: [Int]
prevVoicing = Vector [Int]
prevCands Vector [Int] -> Int -> [Int]
forall a. Vector a -> Int -> a
V.! Int
prevIdx]
in if [(Int, Int, Int)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Int, Int, Int)]
costs
then Maybe (Int, (Int, Int))
forall a. Maybe a
Nothing
else let (Int
_, Int
minCost, Int
backPtr) = ((Int, Int, Int) -> (Int, Int, Int) -> Ordering)
-> [(Int, Int, Int)] -> (Int, Int, Int)
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, Int, Int) -> Int)
-> (Int, Int, Int)
-> (Int, Int, Int)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (\(Int
_,Int
c,Int
_) -> Int
c)) [(Int, Int, Int)]
costs
in (Int, (Int, Int)) -> Maybe (Int, (Int, Int))
forall a. a -> Maybe a
Just (Int
currIdx, (Int
minCost, Int
backPtr))
in [(Int, (Int, Int))] -> DPState
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(Int, (Int, Int))] -> DPState) -> [(Int, (Int, Int))] -> DPState
forall a b. (a -> b) -> a -> b
$ [Maybe (Int, (Int, Int))] -> [(Int, (Int, Int))]
forall a. [Maybe a] -> [a]
catMaybes [Int -> Maybe (Int, (Int, Int))
computeBest Int
j | Int
j <- [Int
0 .. Vector [Int] -> Int
forall a. Vector a -> Int
V.length Vector [Int]
currCands Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
finalState :: DPState
finalState :: DPState
finalState = Vector DPState -> DPState
forall a. Vector a -> a
V.last Vector DPState
forwardPass
lastCands :: Vector [Int]
lastCands = Int -> Vector [Int]
getCandidates (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
bestEnding :: (Int, Int)
bestEnding :: (Int, Int)
bestEnding = ((Int, Int) -> (Int, Int) -> Ordering)
-> [(Int, Int)] -> (Int, Int)
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, Int) -> Int) -> (Int, Int) -> (Int, Int) -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, Int) -> Int
forall a b. (a, b) -> b
snd)
[(Int
lastIdx, Int
cost Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> [Int] -> Int
voiceLeadingCost (Vector [Int]
lastCands Vector [Int] -> Int -> [Int]
forall a. Vector a -> Int -> a
V.! Int
lastIdx) [Int]
firstVoicing)
| (Int
lastIdx, (Int
cost, Int
_)) <- DPState -> [(Int, (Int, Int))]
forall k a. Map k a -> [(k, a)]
Map.toList DPState
finalState]
backtrack :: Int -> Int -> [Int] -> [Int]
backtrack :: Int -> Int -> [Int] -> [Int]
backtrack Int
pos Int
candIdx [Int]
acc
| Int
pos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int
candIdx Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc
| Bool
otherwise =
let (Int
_, Int
backPtr) = (Vector DPState
forwardPass Vector DPState -> Int -> DPState
forall a. Vector a -> Int -> a
V.! Int
pos) DPState -> Int -> (Int, Int)
forall k a. Ord k => Map k a -> k -> a
Map.! Int
candIdx
in Int -> Int -> [Int] -> [Int]
backtrack (Int
pos Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
backPtr (Int
candIdx Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc)
path :: Vector Int
path = [Int] -> Vector Int
forall a. [a] -> Vector a
V.fromList ([Int] -> Vector Int) -> [Int] -> Vector Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> [Int] -> [Int]
backtrack (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ((Int, Int) -> Int
forall a b. (a, b) -> a
fst (Int, Int)
bestEnding) []
result :: [[Int]]
result = [Int -> Vector [Int]
getCandidates Int
i Vector [Int] -> Int -> [Int]
forall a. Vector a -> Int -> a
V.! (Vector Int
path Vector Int -> Int -> Int
forall a. Vector a -> Int -> a
V.! Int
i) | Int
i <- [Int
0..Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1]]
in [[Int]]
result
solveRoot :: [[Int]] -> [[Int]]
solveRoot :: [[Int]] -> [[Int]]
solveRoot [] = []
solveRoot [[Int]]
chords =
let rootPCs :: [Int]
rootPCs = ([Int] -> Int) -> [[Int]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> Int
bassPC [[Int]]
chords
filterByRoot :: Int -> [[Int]] -> [[Int]]
filterByRoot Int
rootPC [[Int]]
cands =
let valid :: [[Int]]
valid = ([Int] -> Bool) -> [[Int]] -> [[Int]]
forall a. (a -> Bool) -> [a] -> [a]
filter (\[Int]
v -> [Int] -> Int
bassPC [Int]
v Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
rootPC) [[Int]]
cands
in if [[Int]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Int]]
valid then [[Int]]
cands else [[Int]]
valid
solved :: [[Int]]
solved = (Int -> [[Int]] -> [[Int]]) -> [Int] -> [[Int]] -> [[Int]]
solveCyclicDP Int -> [[Int]] -> [[Int]]
filterByRoot [Int]
rootPCs [[Int]]
chords
in [[Int]] -> [[Int]]
normalizeByFirstRoot [[Int]]
solved
solveFlow :: [[Int]] -> [[Int]]
solveFlow :: [[Int]] -> [[Int]]
solveFlow [] = []
solveFlow [[Int]]
chords =
let rootPCs :: [Int]
rootPCs = ([Int] -> Int) -> [[Int]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map [Int] -> Int
bassPC [[Int]]
chords
noFilter :: p -> p -> p
noFilter p
_ p
cands = p
cands
solved :: [[Int]]
solved = (Int -> [[Int]] -> [[Int]]) -> [Int] -> [[Int]] -> [[Int]]
solveCyclicDP Int -> [[Int]] -> [[Int]]
forall {p} {p}. p -> p -> p
noFilter [Int]
rootPCs [[Int]]
chords
in [[Int]] -> [[Int]]
normalizeByFirstRoot [[Int]]
solved
liteVoicing :: [[Int]] -> [[Int]]
liteVoicing :: [[Int]] -> [[Int]]
liteVoicing [] = []
liteVoicing [[Int]]
raw = [[Int]] -> [[Int]]
normalizeByFirstRoot [[Int]]
raw
bassVoicing :: [[Int]] -> [[Int]]
bassVoicing :: [[Int]] -> [[Int]]
bassVoicing [] = []
bassVoicing [[Int]]
chords = ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map (\[Int]
chord -> if [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
chord then [] else [[Int] -> Int
bassPC [Int]
chord]) [[Int]]
chords
normalizeByFirstRoot :: [[Int]] -> [[Int]]
normalizeByFirstRoot :: [[Int]] -> [[Int]]
normalizeByFirstRoot [] = []
normalizeByFirstRoot voicings :: [[Int]]
voicings@([Int]
firstChord : [[Int]]
_)
| [Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
firstChord = [[Int]]
voicings
| Bool
otherwise =
let firstRoot :: Int
firstRoot = [Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int]
firstChord
firstRootPC :: Int
firstRootPC = Int
firstRoot Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
targetRoot :: Int
targetRoot = Int
firstRootPC Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
targetFirstRootMin
shift :: Int
shift = Int
targetRoot Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
firstRoot
in ([Int] -> [Int]) -> [[Int]] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> Int) -> [Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
shift)) [[Int]]
voicings
bassPC :: [Int] -> Int
bassPC :: [Int] -> Int
bassPC [] = Int
0
bassPC (Int
p : [Int]
_) = Int
p Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
dedupPCs :: [Int] -> [Int]
dedupPCs :: [Int] -> [Int]
dedupPCs = [Int] -> [Int]
forall a. Eq a => [a] -> [a]
nub ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (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)