module Harmonic.Evaluation.Scoring.Progression
(
ProgressionScore(..)
, ProgressionScoreWeights(..)
, defaultWeights
, defaultWeightsOffline
, scoreProgression
, totalScore
, TransitionMap
, cadenceFavFromMap
, scoreProgressionOnline
, scoreProgressionJazz
, PolyScore(..)
, polyLayerWeights
, polyDivergenceWeight
, polyDivergence
, scorePoly
, scorePolyOnline
, jazzChangeKey
, TransitionCache
, newTransitionCache
, resolveJazzBlend
, cadenceFavFromKeys
, computeCadenceFav
) where
import Control.Monad (forM)
import Control.Monad.IO.Class (liftIO)
import Data.IORef (IORef, newIORef, readIORef, modifyIORef')
import Data.Bifunctor (first)
import Data.Foldable (toList)
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import qualified Data.Text as T
import Data.Text (Text)
import Data.List (nub, sort)
import Harmonic.Database (DbActionT)
import qualified Harmonic.Rules.Types.Progression as Prog
import qualified Harmonic.Rules.Types.ProgressionContext as PC
import qualified Harmonic.Rules.Types.Harmony as H
import qualified Harmonic.Rules.Types.Pitch as P
import qualified Harmonic.Rules.Import.Jazz as J
import qualified Harmonic.Evaluation.Scoring.Dissonance as D
import qualified Harmonic.Evaluation.Scoring.VoiceLeading as VL
import qualified Harmonic.Evaluation.Database.Query as Q
data ProgressionScore = ProgressionScore
{ ProgressionScore -> Double
psRootMotion :: !Double
, ProgressionScore -> Double
psVoiceLeading :: !Double
, ProgressionScore -> Double
psCadenceFav :: !Double
, ProgressionScore -> Double
psModeValidity :: !Double
} deriving (Int -> ProgressionScore -> ShowS
[ProgressionScore] -> ShowS
ProgressionScore -> String
(Int -> ProgressionScore -> ShowS)
-> (ProgressionScore -> String)
-> ([ProgressionScore] -> ShowS)
-> Show ProgressionScore
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ProgressionScore -> ShowS
showsPrec :: Int -> ProgressionScore -> ShowS
$cshow :: ProgressionScore -> String
show :: ProgressionScore -> String
$cshowList :: [ProgressionScore] -> ShowS
showList :: [ProgressionScore] -> ShowS
Show, ProgressionScore -> ProgressionScore -> Bool
(ProgressionScore -> ProgressionScore -> Bool)
-> (ProgressionScore -> ProgressionScore -> Bool)
-> Eq ProgressionScore
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ProgressionScore -> ProgressionScore -> Bool
== :: ProgressionScore -> ProgressionScore -> Bool
$c/= :: ProgressionScore -> ProgressionScore -> Bool
/= :: ProgressionScore -> ProgressionScore -> Bool
Eq)
data ProgressionScoreWeights = ProgressionScoreWeights
{ ProgressionScoreWeights -> Double
wRootMotion :: !Double
, ProgressionScoreWeights -> Double
wVoiceLeading :: !Double
, ProgressionScoreWeights -> Double
wCadenceFav :: !Double
, ProgressionScoreWeights -> Double
wModeValidity :: !Double
} deriving (Int -> ProgressionScoreWeights -> ShowS
[ProgressionScoreWeights] -> ShowS
ProgressionScoreWeights -> String
(Int -> ProgressionScoreWeights -> ShowS)
-> (ProgressionScoreWeights -> String)
-> ([ProgressionScoreWeights] -> ShowS)
-> Show ProgressionScoreWeights
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ProgressionScoreWeights -> ShowS
showsPrec :: Int -> ProgressionScoreWeights -> ShowS
$cshow :: ProgressionScoreWeights -> String
show :: ProgressionScoreWeights -> String
$cshowList :: [ProgressionScoreWeights] -> ShowS
showList :: [ProgressionScoreWeights] -> ShowS
Show, ProgressionScoreWeights -> ProgressionScoreWeights -> Bool
(ProgressionScoreWeights -> ProgressionScoreWeights -> Bool)
-> (ProgressionScoreWeights -> ProgressionScoreWeights -> Bool)
-> Eq ProgressionScoreWeights
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ProgressionScoreWeights -> ProgressionScoreWeights -> Bool
== :: ProgressionScoreWeights -> ProgressionScoreWeights -> Bool
$c/= :: ProgressionScoreWeights -> ProgressionScoreWeights -> Bool
/= :: ProgressionScoreWeights -> ProgressionScoreWeights -> Bool
Eq)
defaultWeights :: ProgressionScoreWeights
defaultWeights :: ProgressionScoreWeights
defaultWeights = ProgressionScoreWeights
{ wRootMotion :: Double
wRootMotion = Double
0.25
, wVoiceLeading :: Double
wVoiceLeading = Double
0.25
, wCadenceFav :: Double
wCadenceFav = Double
0.5
, wModeValidity :: Double
wModeValidity = Double
0
}
defaultWeightsOffline :: ProgressionScoreWeights
defaultWeightsOffline :: ProgressionScoreWeights
defaultWeightsOffline = ProgressionScoreWeights
{ wRootMotion :: Double
wRootMotion = Double
0.5
, wVoiceLeading :: Double
wVoiceLeading = Double
0.5
, wCadenceFav :: Double
wCadenceFav = Double
0
, wModeValidity :: Double
wModeValidity = Double
0
}
scoreProgression :: PC.ProgressionContext -> ProgressionScore
scoreProgression :: ProgressionContext -> ProgressionScore
scoreProgression ProgressionContext
pc = ProgressionScore
{ psRootMotion :: Double
psRootMotion = Progression -> Double
scoreRootMotion (ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc)
, psVoiceLeading :: Double
psVoiceLeading = Progression -> Double
scoreVoiceLeading (ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc)
, psCadenceFav :: Double
psCadenceFav = Double
0.0
, psModeValidity :: Double
psModeValidity = ProgressionContext -> Double
scoreModeValidity ProgressionContext
pc
}
scoreRootMotion :: Prog.Progression -> Double
scoreRootMotion :: Progression -> Double
scoreRootMotion Progression
prog =
let states :: [CadenceState]
states = Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression Progression
prog)
n :: Int
n = [CadenceState] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CadenceState]
states
in if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 then Double
1.0
else
let rootPC :: CadenceState -> Int
rootPC CadenceState
s = PitchClass -> Int
P.unPitchClass (NoteName -> PitchClass
P.pitchClass (CadenceState -> NoteName
H.stateCadenceRoot CadenceState
s))
rootPCs :: [Int]
rootPCs = (CadenceState -> Int) -> [CadenceState] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map CadenceState -> Int
rootPC [CadenceState]
states
edges :: [(Int, Int)]
edges = [Int] -> [Int] -> [(Int, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int]
rootPCs (Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
drop Int
1 [Int]
rootPCs [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
take Int
1 [Int]
rootPCs)
rawSum :: Double
rawSum = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer
D.rootMotionScore ((Int
b Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
a) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12))
| (Int
a, Int
b) <- [(Int, Int)]
edges
] :: Double
avgRaw :: Double
avgRaw = Double
rawSum Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([(Int, Int)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Int, Int)]
edges)
in Double -> Double
clamp01 ((Double
6.0 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
avgRaw) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
5.0)
vlLowAnchorCal, vlHighAnchorCal :: Double
vlLowAnchorCal :: Double
vlLowAnchorCal = Double
3.0
vlHighAnchorCal :: Double
vlHighAnchorCal = Double
8.0
scoreVoiceLeading :: Prog.Progression -> Double
scoreVoiceLeading :: Progression -> Double
scoreVoiceLeading Progression
prog
| [CadenceState] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CadenceState]
states Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 = Double
0.5
| Bool
otherwise =
let voicings :: [[Int]]
voicings = (CadenceState -> [Int]) -> [CadenceState] -> [[Int]]
forall a b. (a -> b) -> [a] -> [b]
map CadenceState -> [Int]
honestVoicing [CadenceState]
states
n :: Int
n = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 ([[Int]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Int]]
voicings)
cost :: Double
cost = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([[Int]] -> Int
VL.cyclicCost [[Int]]
voicings) :: Double
perEdge :: Double
perEdge = Double
cost Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
in Double -> Double
clamp01 ((Double
vlHighAnchor Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
perEdge) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
vlHighAnchor Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
vlLowAnchor))
where
states :: [CadenceState]
states = Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression Progression
prog)
honestVoicing :: CadenceState -> [Int]
honestVoicing CadenceState
cs =
let r :: Int
r = PitchClass -> Int
P.unPitchClass (NoteName -> PitchClass
P.pitchClass (CadenceState -> NoteName
H.stateCadenceRoot CadenceState
cs))
in [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [ (PitchClass -> Int
P.unPitchClass PitchClass
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
r) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12
| PitchClass
i <- Cadence -> [PitchClass]
H.cadenceIntervals (CadenceState -> Cadence
H.stateCadence CadenceState
cs) ]
vlLowAnchor :: Double
vlLowAnchor = Double
vlLowAnchorCal
vlHighAnchor :: Double
vlHighAnchor = Double
vlHighAnchorCal
scoreModeValidity :: PC.ProgressionContext -> Double
scoreModeValidity :: ProgressionContext -> Double
scoreModeValidity ProgressionContext
pc =
case ProgressionContext -> Maybe (Seq (Tristrata, StrataLabel))
PC.pcProvenance ProgressionContext
pc of
Maybe (Seq (Tristrata, StrataLabel))
Nothing -> Double
1.0
Just Seq (Tristrata, StrataLabel)
_ ->
let states :: [CadenceState]
states = Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression (ProgressionContext -> Progression
PC.modeLayer ProgressionContext
pc))
n :: Int
n = [CadenceState] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CadenceState]
states
in if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Double
1.0
else let ok :: Int
ok = [()] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ () | CadenceState
s <- [CadenceState]
states
, [PitchClass] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Cadence -> [PitchClass]
H.cadenceIntervals (CadenceState -> Cadence
H.stateCadence CadenceState
s)) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
7
]
in Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ok Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
totalScore :: ProgressionScoreWeights -> ProgressionScore -> Double
totalScore :: ProgressionScoreWeights -> ProgressionScore -> Double
totalScore ProgressionScoreWeights
w ProgressionScore
ps =
ProgressionScoreWeights -> Double
wRootMotion ProgressionScoreWeights
w Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScore -> Double
psRootMotion ProgressionScore
ps
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ ProgressionScoreWeights -> Double
wVoiceLeading ProgressionScoreWeights
w Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScore -> Double
psVoiceLeading ProgressionScore
ps
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ ProgressionScoreWeights -> Double
wCadenceFav ProgressionScoreWeights
w Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScore -> Double
psCadenceFav ProgressionScore
ps
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ ProgressionScoreWeights -> Double
wModeValidity ProgressionScoreWeights
w Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScore -> Double
psModeValidity ProgressionScore
ps
data PolyScore = PolyScore
{ PolyScore -> ProgressionScore
pyT :: !ProgressionScore
, PolyScore -> ProgressionScore
pyS :: !ProgressionScore
, PolyScore -> ProgressionScore
pyM :: !ProgressionScore
, PolyScore -> Double
pyQuality :: !Double
, PolyScore -> Double
pyDivergence :: !Double
, PolyScore -> Double
pyTotal :: !Double
} deriving (Int -> PolyScore -> ShowS
[PolyScore] -> ShowS
PolyScore -> String
(Int -> PolyScore -> ShowS)
-> (PolyScore -> String)
-> ([PolyScore] -> ShowS)
-> Show PolyScore
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PolyScore -> ShowS
showsPrec :: Int -> PolyScore -> ShowS
$cshow :: PolyScore -> String
show :: PolyScore -> String
$cshowList :: [PolyScore] -> ShowS
showList :: [PolyScore] -> ShowS
Show, PolyScore -> PolyScore -> Bool
(PolyScore -> PolyScore -> Bool)
-> (PolyScore -> PolyScore -> Bool) -> Eq PolyScore
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PolyScore -> PolyScore -> Bool
== :: PolyScore -> PolyScore -> Bool
$c/= :: PolyScore -> PolyScore -> Bool
/= :: PolyScore -> PolyScore -> Bool
Eq)
polyLayerWeights :: (Double, Double, Double)
polyLayerWeights :: (Double, Double, Double)
polyLayerWeights = (Double
0.5, Double
0.25, Double
0.25)
polyDivergenceWeight :: Double
polyDivergenceWeight :: Double
polyDivergenceWeight = Double
0.40
barPCs :: H.CadenceState -> [Int]
barPCs :: CadenceState -> [Int]
barPCs CadenceState
cs =
let r :: Int
r = PitchClass -> Int
P.unPitchClass (NoteName -> PitchClass
P.pitchClass (CadenceState -> NoteName
H.stateCadenceRoot CadenceState
cs))
ivs :: [Int]
ivs = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
P.unPitchClass (Cadence -> [PitchClass]
H.cadenceIntervals (CadenceState -> Cadence
H.stateCadence CadenceState
cs))
in [Int] -> [Int]
forall a. Eq a => [a] -> [a]
nub [ (Int
iv Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
r) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
12 | Int
iv <- [Int]
ivs ]
barRootPC :: H.CadenceState -> Int
barRootPC :: CadenceState -> Int
barRootPC = PitchClass -> Int
P.unPitchClass (PitchClass -> Int)
-> (CadenceState -> PitchClass) -> CadenceState -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NoteName -> PitchClass
P.pitchClass (NoteName -> PitchClass)
-> (CadenceState -> NoteName) -> CadenceState -> PitchClass
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CadenceState -> NoteName
H.stateCadenceRoot
polyDivergence :: PC.ProgressionContext -> Double
polyDivergence :: ProgressionContext -> Double
polyDivergence ProgressionContext
pc =
let bars :: [(CadenceState, CadenceState, CadenceState)]
bars = [CadenceState]
-> [CadenceState]
-> [CadenceState]
-> [(CadenceState, CadenceState, CadenceState)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 (Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression (ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc)))
(Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression (ProgressionContext -> Progression
PC.strataLayer ProgressionContext
pc)))
(Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression (ProgressionContext -> Progression
PC.modeLayer ProgressionContext
pc)))
in case [(CadenceState, CadenceState, CadenceState)]
bars of
[] -> Double
0.0
[(CadenceState, CadenceState, CadenceState)]
_ -> [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((CadenceState, CadenceState, CadenceState) -> Double)
-> [(CadenceState, CadenceState, CadenceState)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (CadenceState, CadenceState, CadenceState) -> Double
barDivergence [(CadenceState, CadenceState, CadenceState)]
bars) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([(CadenceState, CadenceState, CadenceState)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(CadenceState, CadenceState, CadenceState)]
bars)
barDivergence :: (H.CadenceState, H.CadenceState, H.CadenceState) -> Double
barDivergence :: (CadenceState, CadenceState, CadenceState) -> Double
barDivergence (CadenceState
t, CadenceState
s, CadenceState
m) =
let sPCs :: [Int]
sPCs = CadenceState -> [Int]
barPCs CadenceState
s
shared :: Int
shared = [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. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` CadenceState -> [Int]
barPCs CadenceState
m) [Int]
sPCs)
geom :: Double
geom = if Int
shared Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 then Double
0.0 else Double
1.0
ic :: a -> a -> Double
ic a
a a
b = let d :: a
d = a -> a
forall a. Num a => a -> a
abs (a
a a -> a -> a
forall a. Num a => a -> a -> a
- a
b) in a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a -> a
forall a. Ord a => a -> a -> a
min a
d (a
12 a -> a -> a
forall a. Num a => a -> a -> a
- a
d)) :: Double
spread :: Double
spread = (Int -> Int -> Double
forall {a}. Integral a => a -> a -> Double
ic (CadenceState -> Int
barRootPC CadenceState
t) (CadenceState -> Int
barRootPC CadenceState
s)
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Int -> Int -> Double
forall {a}. Integral a => a -> a -> Double
ic (CadenceState -> Int
barRootPC CadenceState
t) (CadenceState -> Int
barRootPC CadenceState
m)
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Int -> Int -> Double
forall {a}. Integral a => a -> a -> Double
ic (CadenceState -> Int
barRootPC CadenceState
s) (CadenceState -> Int
barRootPC CadenceState
m)) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
18.0
in Double
0.5 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
geom Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
0.5 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
spread
layerAlone :: (PC.ProgressionContext -> Prog.Progression)
-> PC.ProgressionContext -> PC.ProgressionContext
layerAlone :: (ProgressionContext -> Progression)
-> ProgressionContext -> ProgressionContext
layerAlone ProgressionContext -> Progression
sel = Progression -> ProgressionContext
PC.fromProgression (Progression -> ProgressionContext)
-> (ProgressionContext -> Progression)
-> ProgressionContext
-> ProgressionContext
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressionContext -> Progression
sel
assemblePoly :: ProgressionScoreWeights
-> ProgressionScore -> ProgressionScore -> ProgressionScore
-> Double -> PolyScore
assemblePoly :: ProgressionScoreWeights
-> ProgressionScore
-> ProgressionScore
-> ProgressionScore
-> Double
-> PolyScore
assemblePoly ProgressionScoreWeights
w ProgressionScore
t ProgressionScore
s ProgressionScore
m Double
d =
let (Double
wt, Double
ws, Double
wm) = (Double, Double, Double)
polyLayerWeights
q :: Double
q = Double
wt Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScoreWeights -> ProgressionScore -> Double
totalScore ProgressionScoreWeights
w ProgressionScore
t Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
ws Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScoreWeights -> ProgressionScore -> Double
totalScore ProgressionScoreWeights
w ProgressionScore
s Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
wm Double -> Double -> Double
forall a. Num a => a -> a -> a
* ProgressionScoreWeights -> ProgressionScore -> Double
totalScore ProgressionScoreWeights
w ProgressionScore
m
wd :: Double
wd = Double
polyDivergenceWeight
in PolyScore
{ pyT :: ProgressionScore
pyT = ProgressionScore
t, pyS :: ProgressionScore
pyS = ProgressionScore
s, pyM :: ProgressionScore
pyM = ProgressionScore
m
, pyQuality :: Double
pyQuality = Double
q
, pyDivergence :: Double
pyDivergence = Double
d
, pyTotal :: Double
pyTotal = (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
wd) Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
q Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
wd Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
d
}
scorePoly :: ProgressionScoreWeights -> PC.ProgressionContext -> PolyScore
scorePoly :: ProgressionScoreWeights -> ProgressionContext -> PolyScore
scorePoly ProgressionScoreWeights
w ProgressionContext
pc =
ProgressionScoreWeights
-> ProgressionScore
-> ProgressionScore
-> ProgressionScore
-> Double
-> PolyScore
assemblePoly ProgressionScoreWeights
w
(ProgressionContext -> ProgressionScore
scoreProgression ((ProgressionContext -> Progression)
-> ProgressionContext -> ProgressionContext
layerAlone ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc))
(ProgressionContext -> ProgressionScore
scoreProgression ((ProgressionContext -> Progression)
-> ProgressionContext -> ProgressionContext
layerAlone ProgressionContext -> Progression
PC.strataLayer ProgressionContext
pc))
(ProgressionContext -> ProgressionScore
scoreProgression ((ProgressionContext -> Progression)
-> ProgressionContext -> ProgressionContext
layerAlone ProgressionContext -> Progression
PC.modeLayer ProgressionContext
pc))
(ProgressionContext -> Double
polyDivergence ProgressionContext
pc)
scorePolyOnline :: TransitionCache -> Text -> ProgressionScoreWeights
-> PC.ProgressionContext -> DbActionT PolyScore
scorePolyOnline :: TransitionCache
-> Text
-> ProgressionScoreWeights
-> ProgressionContext
-> DbActionT PolyScore
scorePolyOnline TransitionCache
cache Text
blend ProgressionScoreWeights
w ProgressionContext
pc = do
t <- TransitionCache
-> Text -> ProgressionContext -> DbActionT ProgressionScore
scoreProgressionOnline TransitionCache
cache Text
blend ((ProgressionContext -> Progression)
-> ProgressionContext -> ProgressionContext
layerAlone ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc)
s <- scoreProgressionOnline cache blend (layerAlone PC.strataLayer pc)
m <- scoreProgressionOnline cache blend (layerAlone PC.modeLayer pc)
pure (assemblePoly w t s m (polyDivergence pc))
type TransitionMap = Map Text [(Text, Double)]
cadenceFavFromMap :: TransitionMap -> Prog.Progression -> Double
cadenceFavFromMap :: TransitionMap -> Progression -> Double
cadenceFavFromMap TransitionMap
srcMap Progression
prog =
TransitionMap -> [Text] -> Double
cadenceFavFromKeys TransitionMap
srcMap
((CadenceState -> Text) -> [CadenceState] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Text
T.pack (String -> Text)
-> (CadenceState -> String) -> CadenceState -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cadence -> String
forall a. Show a => a -> String
show (Cadence -> String)
-> (CadenceState -> Cadence) -> CadenceState -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cadence -> Cadence
H.walkTriadCadence (Cadence -> Cadence)
-> (CadenceState -> Cadence) -> CadenceState -> Cadence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CadenceState -> Cadence
H.stateCadence)
(Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression Progression
prog)))
cadenceFavFromKeys :: TransitionMap -> [Text] -> Double
cadenceFavFromKeys :: TransitionMap -> [Text] -> Double
cadenceFavFromKeys TransitionMap
srcMap [Text]
keys =
let n :: Int
n = [Text] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Text]
keys
in if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 then Double
0
else
let edges :: [(Text, Text)]
edges = [Text] -> [Text] -> [(Text, Text)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Text]
keys (Int -> [Text] -> [Text]
forall a. Int -> [a] -> [a]
drop Int
1 [Text]
keys [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ Int -> [Text] -> [Text]
forall a. Int -> [a] -> [a]
take Int
1 [Text]
keys)
perEdge :: [Double]
perEdge = ((Text, Text) -> Double) -> [(Text, Text)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (TransitionMap -> (Text, Text) -> Double
edgeScore TransitionMap
srcMap) [(Text, Text)]
edges
in [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Double]
perEdge Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
perEdge)
edgeScore :: TransitionMap -> (Text, Text) -> Double
edgeScore :: TransitionMap -> (Text, Text) -> Double
edgeScore TransitionMap
srcMap (Text
srcKey, Text
dstKey) =
case Text -> TransitionMap -> Maybe [(Text, Double)]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
srcKey TransitionMap
srcMap of
Maybe [(Text, Double)]
Nothing -> Double
0
Just [(Text, Double)]
transitions ->
let totalW :: Double
totalW = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((Text, Double) -> Double) -> [(Text, Double)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Double) -> Double
forall a b. (a, b) -> b
snd [(Text, Double)]
transitions)
matched :: Double
matched = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [ Double
w | (Text
k, Double
w) <- [(Text, Double)]
transitions, Text
k Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
dstKey ]
in if Double
totalW Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
0 Bool -> Bool -> Bool
|| Double
matched Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
0
then Double
0
else Double
0.5 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
0.5 Double -> Double -> Double
forall a. Num a => a -> a -> a
* (Double
matched Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
totalW)
scoreProgressionOnline
:: TransitionCache
-> Text
-> PC.ProgressionContext
-> DbActionT ProgressionScore
scoreProgressionOnline :: TransitionCache
-> Text -> ProgressionContext -> DbActionT ProgressionScore
scoreProgressionOnline TransitionCache
cache Text
seekStr ProgressionContext
pc = do
let basePure :: ProgressionScore
basePure = ProgressionContext -> ProgressionScore
scoreProgression ProgressionContext
pc
cf <- TransitionCache -> Text -> Progression -> DbActionT Double
computeCadenceFav TransitionCache
cache Text
seekStr (ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc)
pure basePure { psCadenceFav = cf }
type TransitionCache = IORef TransitionMap
newTransitionCache :: IO TransitionCache
newTransitionCache :: IO TransitionCache
newTransitionCache = TransitionMap -> IO TransitionCache
forall a. a -> IO (IORef a)
newIORef TransitionMap
forall k a. Map k a
Map.empty
computeCadenceFav
:: TransitionCache
-> Text
-> Prog.Progression
-> DbActionT Double
computeCadenceFav :: TransitionCache -> Text -> Progression -> DbActionT Double
computeCadenceFav TransitionCache
cache Text
seekStr Progression
prog = do
let cads :: [Cadence]
cads = (CadenceState -> Cadence) -> [CadenceState] -> [Cadence]
forall a b. (a -> b) -> [a] -> [b]
map (Cadence -> Cadence
H.walkTriadCadence (Cadence -> Cadence)
-> (CadenceState -> Cadence) -> CadenceState -> Cadence
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CadenceState -> Cadence
H.stateCadence) (Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression Progression
prog))
srcKeys :: [Text]
srcKeys = [Text] -> [Text]
forall a. Eq a => [a] -> [a]
nub ((Cadence -> Text) -> [Cadence] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Text
T.pack (String -> Text) -> (Cadence -> String) -> Cadence -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cadence -> String
forall a. Show a => a -> String
show) [Cadence]
cads)
blend :: ComposerWeights
blend = Text -> ComposerWeights
Q.parseComposerWeights Text
seekStr
pairs <- [Text]
-> (Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [Text]
srcKeys ((Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])])
-> (Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])]
forall a b. (a -> b) -> a -> b
$ \Text
k -> do
resolved <- TransitionCache
-> Text -> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
fetchCached TransitionCache
cache Text
k (DbActionT [(Text, Double)] -> DbActionT [(Text, Double)])
-> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ do
raw <- if ComposerWeights -> Bool
forall k a. Map k a -> Bool
Map.null ComposerWeights
blend
then Text -> DbActionT [(Cadence, Double)]
Q.fetchTransitionsAggregate Text
k
else ComposerWeights
-> [(Cadence, ComposerWeights)] -> [(Cadence, Double)]
forall a.
ComposerWeights -> [(a, ComposerWeights)] -> [(a, Double)]
Q.resolveWeights ComposerWeights
blend ([(Cadence, ComposerWeights)] -> [(Cadence, Double)])
-> ReaderT DbConn IO [(Cadence, ComposerWeights)]
-> DbActionT [(Cadence, Double)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> ReaderT DbConn IO [(Cadence, ComposerWeights)]
Q.fetchTransitions Text
k
pure [ (T.pack (show c), w) | (c, w) <- raw ]
pure (k, resolved)
let srcMap = [(Text, [(Text, Double)])] -> TransitionMap
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Text, [(Text, Double)])]
pairs
pure (cadenceFavFromMap srcMap prog)
fetchCached :: TransitionCache -> Text -> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
fetchCached :: TransitionCache
-> Text -> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
fetchCached TransitionCache
cache Text
k DbActionT [(Text, Double)]
fetch = do
m <- IO TransitionMap -> ReaderT DbConn IO TransitionMap
forall a. IO a -> ReaderT DbConn IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (TransitionCache -> IO TransitionMap
forall a. IORef a -> IO a
readIORef TransitionCache
cache)
case Map.lookup k m of
Just [(Text, Double)]
v -> [(Text, Double)] -> DbActionT [(Text, Double)]
forall a. a -> ReaderT DbConn IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [(Text, Double)]
v
Maybe [(Text, Double)]
Nothing -> do
v <- DbActionT [(Text, Double)]
fetch
liftIO (modifyIORef' cache (Map.insert k v))
pure v
jazzChangeKey :: H.CadenceState -> Text
jazzChangeKey :: CadenceState -> Text
jazzChangeKey CadenceState
cs =
let cad :: Cadence
cad = CadenceState -> Cadence
H.stateCadence CadenceState
cs
set :: [Int]
set = (PitchClass -> Int) -> [PitchClass] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map PitchClass -> Int
P.unPitchClass (Cadence -> [PitchClass]
H.cadenceIntervals Cadence
cad)
in case [Int] -> Maybe Text
J.jazzFunctionality [Int]
set of
Just Text
nm -> Text
"( " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Movement -> String
forall a. Show a => a -> String
show (Cadence -> Movement
H.cadenceMovement Cadence
cad)) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" -> " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nm Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" )"
Maybe Text
Nothing -> String -> Text
T.pack (Cadence -> String
forall a. Show a => a -> String
show Cadence
cad)
scoreProgressionJazz
:: TransitionCache
-> Q.ComposerWeights
-> PC.ProgressionContext
-> DbActionT ProgressionScore
scoreProgressionJazz :: TransitionCache
-> ComposerWeights
-> ProgressionContext
-> DbActionT ProgressionScore
scoreProgressionJazz TransitionCache
cache ComposerWeights
jazzBlend ProgressionContext
pc = do
let basePure :: ProgressionScore
basePure = ProgressionContext -> ProgressionScore
scoreProgression ProgressionContext
pc
prog :: Progression
prog = ProgressionContext -> Progression
PC.triadLayer ProgressionContext
pc
keys :: [Text]
keys = (CadenceState -> Text) -> [CadenceState] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map CadenceState -> Text
jazzChangeKey (Seq CadenceState -> [CadenceState]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Progression -> Seq CadenceState
Prog.unProgression Progression
prog))
pairs <- [Text]
-> (Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM ([Text] -> [Text]
forall a. Eq a => [a] -> [a]
nub [Text]
keys) ((Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])])
-> (Text -> ReaderT DbConn IO (Text, [(Text, Double)]))
-> ReaderT DbConn IO [(Text, [(Text, Double)])]
forall a b. (a -> b) -> a -> b
$ \Text
k -> do
resolved <- TransitionCache
-> Text -> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
fetchCached TransitionCache
cache Text
k (DbActionT [(Text, Double)] -> DbActionT [(Text, Double)])
-> DbActionT [(Text, Double)] -> DbActionT [(Text, Double)]
forall a b. (a -> b) -> a -> b
$
if ComposerWeights -> Bool
forall k a. Map k a -> Bool
Map.null ComposerWeights
jazzBlend
then ((ChangeCandidate, Double) -> (Text, Double))
-> [(ChangeCandidate, Double)] -> [(Text, Double)]
forall a b. (a -> b) -> [a] -> [b]
map ((ChangeCandidate -> Text)
-> (ChangeCandidate, Double) -> (Text, Double)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ChangeCandidate -> Text
Q.ccShow) ([(ChangeCandidate, Double)] -> [(Text, Double)])
-> ReaderT DbConn IO [(ChangeCandidate, Double)]
-> DbActionT [(Text, Double)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> ReaderT DbConn IO [(ChangeCandidate, Double)]
Q.fetchChangeAggregate Text
k
else ((ChangeCandidate, Double) -> (Text, Double))
-> [(ChangeCandidate, Double)] -> [(Text, Double)]
forall a b. (a -> b) -> [a] -> [b]
map ((ChangeCandidate -> Text)
-> (ChangeCandidate, Double) -> (Text, Double)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ChangeCandidate -> Text
Q.ccShow) ([(ChangeCandidate, Double)] -> [(Text, Double)])
-> ([(ChangeCandidate, ComposerWeights)]
-> [(ChangeCandidate, Double)])
-> [(ChangeCandidate, ComposerWeights)]
-> [(Text, Double)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ComposerWeights
-> [(ChangeCandidate, ComposerWeights)]
-> [(ChangeCandidate, Double)]
forall a.
ComposerWeights -> [(a, ComposerWeights)] -> [(a, Double)]
Q.resolveWeights ComposerWeights
jazzBlend
([(ChangeCandidate, ComposerWeights)] -> [(Text, Double)])
-> ReaderT DbConn IO [(ChangeCandidate, ComposerWeights)]
-> DbActionT [(Text, Double)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> ReaderT DbConn IO [(ChangeCandidate, ComposerWeights)]
Q.fetchChangeTransitions Text
k
pure (k, resolved)
let cf = TransitionMap -> [Text] -> Double
cadenceFavFromKeys ([(Text, [(Text, Double)])] -> TransitionMap
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Text, [(Text, Double)])]
pairs) [Text]
keys
pure basePure { psCadenceFav = cf }
resolveJazzBlend :: Text -> DbActionT Q.ComposerWeights
resolveJazzBlend :: Text -> DbActionT ComposerWeights
resolveJazzBlend Text
seekStr = do
let blend :: ComposerWeights
blend = Text -> ComposerWeights
Q.parseComposerWeights Text
seekStr
if ComposerWeights -> Bool
forall k a. Map k a -> Bool
Map.null ComposerWeights
blend
then ComposerWeights -> DbActionT ComposerWeights
forall a. a -> ReaderT DbConn IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ComposerWeights
forall k a. Map k a
Map.empty
else do
jazzKeys <- DbActionT (Set Text)
Q.fetchJazzComposers
pure (fst (Q.splitSeekByCorpus jazzKeys blend))
clamp01 :: Double -> Double
clamp01 :: Double -> Double
clamp01 Double
x
| Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
0 = Double
0
| Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
1 = Double
1
| Bool
otherwise = Double
x