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

Harmonic.Rules.Import.Transform

Description

Transforms raw CSV corpus records into Cadence structures suitable for Neo4j graph storage: fundamental extraction, triad generation via Harmonic.Rules.Constraints.Overtone, and dissonance scoring.

BEFORE RE-INGESTING THE CORPUS, READ THIS ==

The LIVE database's node keys (show = movement + functionality) carry functionality names produced under LEGACY naming rules — e.g. zero form [0,3,8] is stored as maj_1stInv, [0,2,7] as sus4_1stInv, [0,5,10] as sus4_2ndInv. The CURRENT namers in this pipeline (toTriad via toCadence below) deliberately diverge from those rules (min#5, sus2, 7sus4 for the same forms). Every read-side fetch key is therefore built through corpusFunctionality, whose 55-form corpusNameTable (Harmonic.Rules.Types.Harmony) was transcribed verbatim from the live database (2026-08-19).

Consequence: running this ingestion pipeline as-is would create a graph whose keyspace DIVERGES from corpusNameTable — every fetch would miss and generation would silently drop to fallback-only. Any re-ingestion must do one of:

(a) route write-side naming through corpusFunctionality so the new keyspace is identical to the table (preferred — keeps read and write sides on one contract), or (b) re-ingest with the current namers and then REGENERATE corpusNameTable from the fresh database: MATCH (c:Cadence) RETURN DISTINCT c.chord, c.show.

Either way, verify afterwards with an online gen' run: graph counts ([nG/...]) must stay nonzero across steps that select inversion forms.

Synopsis

Cadence construction

buildCadences :: [ChordSlice] -> [Cadence] Source #

Convert a sequence of chord slices into a cadence list that reflects every reasonable triad interpretation. Instead of picking a single "best" triad, we duplicate the top three options (3/2/1 copies) and cross-multiply adjacent slices so the Markov model can learn from alternate paths without fractional weights.

buildCadencesPerPiece :: [[ChordSlice]] -> [Cadence] Source #

Build cadences piece by piece, then concatenate. Keeping pieces separate matters: it stops a transition being invented across the boundary between the last chord of one piece and the first of the next.

Helpers

fundamentals :: Vector [Int] -> [Int] Source #

Extract the fundamental bass note of each chord: the lowest pitch present. Empty chords yield 0.