theHarmonicAlgorithm-3.0.0: Real-time harmonic progression generation for TidalCycles live performance
Safe HaskellSafe-Inferred
LanguageHaskell2010

Harmonic.Evaluation.Scoring.Progression

Description

Composable score of a ProgressionContext along four axes:

  • psRootMotion — per-edge root motion smoothness (Hindemith-derived)
  • psVoiceLeading — cyclic voice-leading cost over the triad layer
  • psCadenceFav — Neo4j-backed cadence transition favourability (0.0 if computed offline; online callers override)
  • psModeValidity — fraction of bars whose mode layer carries the expected 7-PC chroma (Phase 1 invariant guarantees walk-generated progressions score 1.0)

Each component lives in [0, 1] with higher = better. totalScore combines components via a weighted sum; defaultWeights makes cadence-favourability the dominant axis (the user's stated preference).

The normalisations applied to per-component raw measurements are intentionally simple placeholders — to be refined from observed distributions once multi-attempt generation is live (see the project's data-driven tuning memory). The function signatures are stable; only the internal transforms inside scoreRootMotion / scoreVoiceLeading / scoreModeValidity are subject to retuning.

Synopsis

Score record

data ProgressionScore Source #

Per-progression scoring breakdown. Each component is in [0, 1]; higher is better.

Default weights

defaultWeights :: ProgressionScoreWeights Source #

Cadence-favourability dominant: 0.4 fav, 0.2 each on root motion, voice leading, mode validity.

defaultWeightsOffline :: ProgressionScoreWeights Source #

Offline-mode weights — cadence favourability dropped, remaining three renormalised to 1/3 each.

Scoring (offline)

scoreProgression :: ProgressionContext -> ProgressionScore Source #

Pure score: computes root-motion, voice-leading, and mode-validity components. psCadenceFav is left at 0.0 — online callers override this field after consulting the graph.

totalScore :: ProgressionScoreWeights -> ProgressionScore -> Double Source #

Weighted sum of components. Conventional weights sum to 1.0 → total in [0, 1].

Cadence-favourability (online + pure helper)

type TransitionMap = Map Text [(Cadence, Double)] Source #

A pre-fetched, composer-blend-resolved map from source cadence (keyed by its show representation) to its outgoing transitions. Each transition carries the destination Cadence and the blended weight (output of applyComposerBlend).

cadenceFavFromMap :: TransitionMap -> Progression -> Double Source #

Compute psCadenceFav from a pre-fetched transition map. Pure — no IO.

The progression is treated as a cyclic loop: edges are (C₀ → C₁), …, (C_{N-2} → C_{N-1}), (C_{N-1} → C₀). Each edge is scored by edgeScore (hybrid presence + share). The per-progression score is the mean of per-edge scores — length-independent and in [0, 1].

Matching by show (not Eq) matches the DB's identity convention (MATCH (c:Cadence {show: $show}) at Query.hs:113-137). The DB-side Cadence is reconstructed via constructCadence (movement, chord), which may differ from a generated Cadences cadenceIntervals field; the show instance projects to (movement, functionality) only.

scoreProgressionOnline Source #

Arguments

:: Text

Seek string (composer blend; same format as _gcSeek).

-> ProgressionContext 
-> BoltActionT IO ProgressionScore 

Online variant of scoreProgression. Pure components match the offline version exactly; psCadenceFav is populated from Neo4j edge weights under the composer blend parsed from the supplied seek string.

Runs inside 'Bolt.BoltActionT IO' so the caller controls connection lifecycle (typically a single shared pipe across a multi-attempt loop).

computeCadenceFav :: Text -> Progression -> BoltActionT IO Double Source #

Cyclic per-edge favourability mean, computed against Neo4j. Builds the TransitionMap by fetching each unique source cadence's outgoing transitions once, applying the composer blend, then delegating to the pure cadenceFavFromMap.

Number of graph queries = number of distinct source-cadence show keys in the progression (≤ N for an N-bar progression).