theHarmonicAlgorithm-3.1.0: Real-time harmonic progression generation for TidalCycles live performance
Safe HaskellNone
LanguageGHC2021

Harmonic.Evaluation.Analysis.KeyArea

Description

Chord-scale analysis over a finished progression: a cyclic Viterbi walk over a 24-key lattice (12 major + 12 composite minor areas) assigns every bar a key area and a scale form, from which the M (mode, 7-PC) and S (anhemitonic pentatonic, 5-PC) layers of gen / genJ contexts are derived (chordscale).

A minor key is COMPOSITE: one tonic with three interchangeable forms — natural (the relative-major set), harmonic minor, melodic minor — chosen per bar by chord fit. A minor ii-V-i therefore reads as ONE key area: the iiO7 and V7b9 bars take the harmonic form (Locrian ♮6 / Phrygian dominant), the tonic bars the melodic/natural forms. Melodic minor is never an independent key whose ii-V-i sits on its own scale degrees.

BOUNDARY: analysis is a PURE, DERIVED annotation computed over a finished progression. The generation system deliberately operates without key awareness — each state is abstract and deterministic, upholding the Markov property — so nothing here may feed back into generation, become part of a generation state, or appear in a generation-path signature. Producers attach the RESULTS to the finished context (chordscale); the walking bass reads the same detector (barPalettes). Under identity chord selection the walk and the layers therefore agree; under a reordering selection the walk re-analyses the PERFORMED bar sequence — deliberately — and its lines also add chromatic approach tones beyond any stored set.

All numeric constants are probe-calibrated — see archive/analysis/keyarea.md / penta.md (2026-08-29): the lambda / bonus sweep on live gen/genJ output plus hand-encoded cyclic standards froze kaLambda = 6, kaDomBonus = 3, kaTonicBonus = 1.5 (97-98% chord-in-key coverage at ~3.8-bar mean segments) and kaPentaLambda = 4 (~3.3 pentatonic switches per progression, 80% guide-tone coverage, zero avoid-note hits).

Synopsis

Types

data KeyQuality Source #

Major, or composite minor (natural + harmonic + melodic forms).

Constructors

MajorKey 
MinorKey 

data KeyArea Source #

A key area: tonic pitch class + quality.

Constructors

KeyArea 

Fields

Instances

Instances details
Show KeyArea Source # 
Instance details

Defined in Harmonic.Evaluation.Analysis.KeyArea

Eq KeyArea Source # 
Instance details

Defined in Harmonic.Evaluation.Analysis.KeyArea

Methods

(==) :: KeyArea -> KeyArea -> Bool #

(/=) :: KeyArea -> KeyArea -> Bool #

Ord KeyArea Source # 
Instance details

Defined in Harmonic.Evaluation.Analysis.KeyArea

data KeyForm Source #

Which scale form realises a bar inside its key area.

Constructors

MajForm 
NatForm 
HarmForm 
MelForm 

data ModeTier Source #

Which tier of the override ladder produced a bar's M set: the key form itself, the seeded special cases, the generic 28-mode search, or the best-coverage gap fallback (chord not fully contained).

data BarAnalysis Source #

Per-bar analysis result.

Constructors

BarAnalysis 

Fields

showKeyArea :: KeyArea -> String Source #

Render a key area the way musicians say it: "Bb", "Gm".

Analysis

analyzeProgression :: Progression -> [BarAnalysis] Source #

Analyze a finished progression: one BarAnalysis per bar. Pure and deterministic; cyclic (the wrap edge counts, so rotating the bars rotates the answers).

barPalettes :: Progression -> Vector (Set Int) Source #

Per-bar 7-PC palettes for the walking bass — the M sets of analyzeProgression, in the exact shape the walk consumes.

Layer derivation

chordscale :: ProgressionContext -> ProgressionContext Source #

Fill the S (pentatonic) and M (mode) layers of a context from the key-area analysis of its triad layer. Identity on FStrata and FPoly contexts, whose layers are already meaningful. Layer bars are built exactly like genP's aux layers (Unison movement, chroma expressed as intervals from the bar root), so they voice through the same chroma engine (strataModeFlow) and print as mode names via the 7-PC display path. The M bar is rooted on the bar's harmonic root (the mode OF the bar — every tier of the override ladder contains it); the S bar is rooted on the PENTATONIC's own root — a pentatonic legitimately excludes the chord root (the pent-on-the-fifth over a maj7 does so by design), and the set is named from its own root. (Bar roots seed only bar 0's lattice in the chroma engine; pattern indices then track their lattice slot, not the bar root.) Provenance stays Nothing (provenance is strata-specific and gates strata regen / scoring).

The derived bars are forced to normal form as part of the result's WHNF: ProgressionContext fields are lazy, and the first thing to inspect an unforced layer can be the derived Eq inside an arrange / lineHarmony cache lookup — i.e. the audio thread. Generated contexts are forced when the generator prints them, so their analysis always lands at generation time; a hand-applied chordscale evaluates at its own first use — print it (or run chordscaleReport on it) at build time to keep the work off the performance path.

Calibrated constants

kaLambda :: Double Source #

Key-switch penalty (probe-calibrated, see module header).

kaDomBonus :: Double Source #

Boundary bonus when the bar BEFORE the switch is dominant-functioning of the new key (V7 shell a P5 above the tonic, or a dim/half-dim shell a semitone below it) — modulations announced by their dominant switch cheaper.

kaTonicBonus :: Double Source #

Boundary bonus when the arrival bar is tonic-functioning in the new key.

kaPentaLambda :: Double Source #

Pentatonic-switch penalty (probe-calibrated, see module header).