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

Harmonic.Framework.Builder.Core

Description

Internal chain building, candidate pool construction, R-constraint filtering, consonance fallback generation, state advancement, and progression conversion. These functions run inside the Bolt action monad for Neo4j access.

Synopsis

Chain Building (online, requires Neo4j)

buildChain Source #

Arguments

:: GeneratorConfig 
-> GenIO

Shared random generator

-> Double

Entropy [0,1]

-> HarmonicContext 
-> ParsedContext

Pre-parsed context for O(1) lookups

-> ComposerWeights

Composer blend weights

-> CadenceState

Starting state

-> Int

Number of steps to generate

-> BoltActionT IO [CadenceState] 

Build the cadence chain step by step.

Simplified algorithm: 1. Start from initial CadenceState 2. For each step: build candidate pool, gamma-select next 3. Pool = filtered graph transitions + consonanceFallback (unlimited)

buildChainWithDiag Source #

Arguments

:: GeneratorConfig 
-> GenIO

Shared random generator

-> Double

Entropy [0,1]

-> HarmonicContext 
-> ParsedContext

Pre-parsed context for O(1) lookups

-> ComposerWeights

Composer blend weights

-> CadenceState

Starting state

-> Int

Number of steps to generate

-> BoltActionT IO ([CadenceState], [StepDiagnostic]) 

Build cadence chain with diagnostic collection (verbosity level 1)

buildChainWithDiagV Source #

Arguments

:: GeneratorConfig 
-> GenIO

Shared random generator

-> Int

Verbosity level (1 or 2)

-> Double

Entropy [0,1]

-> HarmonicContext 
-> ParsedContext

Pre-parsed context for O(1) lookups

-> ComposerWeights

Composer blend weights

-> CadenceState

Starting state

-> Int

Number of steps to generate

-> BoltActionT IO ([CadenceState], [StepDiagnostic]) 

Build cadence chain with diagnostic collection (configurable verbosity) Verbosity levels: 1 = standard diagnostics (sdRenderedChord populated) 2 = maximum diagnostics (full TransformTrace and AdvanceTrace)

Chain Building (offline, no Neo4j required)

buildChainOffline :: GeneratorConfig -> GenIO -> Double -> HarmonicContext -> ParsedContext -> CadenceState -> Int -> IO [CadenceState] Source #

Build cadence chain offline (no Neo4j required).

Uses only the consonanceFallback mechanism — no graph traversal. Progressions are shaped by context filters (overtones, key, roots, drift, inversion spacing) and entropy. Fully musical without corpus-trained style.

buildChainOfflineWithDiag :: GeneratorConfig -> GenIO -> Double -> HarmonicContext -> ParsedContext -> CadenceState -> Int -> IO ([CadenceState], [StepDiagnostic]) Source #

Build cadence chain offline with standard diagnostic collection.

buildChainOfflineWithDiagV :: GeneratorConfig -> GenIO -> Int -> Double -> HarmonicContext -> ParsedContext -> CadenceState -> Int -> IO ([CadenceState], [StepDiagnostic]) Source #

Build cadence chain offline with configurable verbosity diagnostics.

Strata chain building (per-bar narrowed ParsedContext)

buildStrataChain Source #

Arguments

:: GeneratorConfig 
-> GenIO 
-> Maybe Int

verbosity

-> Double

entropy

-> HarmonicContext

base context (threaded unchanged for non-overtone R rules)

-> (Int -> ParsedContext)

bar index (1-based) → per-bar pctx

-> ComposerWeights 
-> CadenceState

starting state

-> Int

number of steps

-> BoltActionT IO ([CadenceState], [StepDiagnostic]) 

Like buildChain but accepts a per-bar ParsedContext supplier. Used by genP to narrow _hcOvertones to the active strata's 5-PC chroma at each bar while still running the full R→E→T pipeline (graph candidates + fallback scoring + gamma selection).

The supplier is called once per bar with the 1-based bar index; it should return a ParsedContext whose pcEffectiveOvertones is the strata's chroma, with pcSoftBoost set by the caller to reflect the (strata, tristrata) continuity against prior bars.

Step primitives (exposed for genP-style per-bar context narrowing)

stepChainCore :: GeneratorConfig -> GenIO -> Maybe Int -> Double -> HarmonicContext -> ParsedContext -> ComposerWeights -> ((CadenceState, [CadenceState], Int), [StepDiagnostic]) -> Int -> BoltActionT IO ((CadenceState, [CadenceState], Int), [StepDiagnostic]) Source #

Unified single step for chain building (online, requires Neo4j).

Fetches graph transitions via Bolt then delegates all logic to stepChainBody. When verbosity is Nothing, skips diagnostic construction entirely. When verbosity is Just n, collects diagnostics at level n: Just 1 = standard diagnostics (rendered chord populated) Just 2 = maximum diagnostics (full TransformTrace and AdvanceTrace)

fuseState Source #

Arguments

:: GenIO 
-> Double

Entropy [0,1]

-> ParsedContext 
-> Maybe CadenceState

Previous fused bar (drift reference); Nothing for the cue

-> CadenceState

The selected triad state

-> IO (CadenceState, Maybe FusionDiag) 

Fuse one palette tone into a triad state, producing the 4-note bar the gen4 family emits. State-local by construction: the candidate set is pcEffectiveOvertones \ triadAbsPCs — the set-theoretic collapse of "every R-valid triad sharing exactly 2 pitches with the selected triad, unioned over the original root" (any such triad unions to T ∪ {x}). R adherence is therefore automatic: the added tone is always in the palette, the bass never moves, and pedal tones can only gain members.

Selection: candidates ranked consonant-first by dissonanceScore of the full 4-PC set, drawn by the same entropy-scaled gamma as the walk. When drift is active and the previous FUSED bar is supplied, candidates are first advisorily filtered by fused-chord dissonance against it (consonant → dissonant →=), relaxing to the full set when empty — mirroring applyDriftFilter. The triad stage has already drift-filtered triad-vs-triad, so both the skeleton and the heard surface obey the modifier.

Degenerate palette (palette == triad, only possible under a 3-tone tonal context): returns the input unchanged — a plain triad bar. Root, movement, and spelling are preserved verbatim.

stepChainOffline :: GeneratorConfig -> GenIO -> Maybe Int -> Double -> HarmonicContext -> ParsedContext -> ((CadenceState, [CadenceState], Int), [StepDiagnostic]) -> Int -> IO ((CadenceState, [CadenceState], Int), [StepDiagnostic]) Source #

Offline single step for chain building (no Neo4j required).

Passes empty transitions to stepChainBody, so generation relies entirely on the consonanceFallback mechanism (~660 candidates shaped by context filters).

Conversion

chainToProgression :: [CadenceState] -> Progression Source #

Convert a chain of CadenceStates to a Progression

extractCadence :: CadenceState -> Cadence Source #

Extract Cadence from CadenceState

Filtering (exposed for testing)

matchesContext :: HarmonicContext -> CadenceState -> Cadence -> Bool Source #

Check if a cadence matches the harmonic context filters.

Filter logic (matching legacy behavior): 1. Compute effective overtones: key-filtered overtone palette 2. All chord pitches must be in effective overtones 3. Root must be in resolved roots (handles "key"/"tones" options)

matchesContextWithTarget :: Maybe Int -> ParsedContext -> CadenceState -> Cadence -> Bool Source #

Core filter with optional bass target override from rise/fall direction. When bassTarget is Just, the bass note must equal the target exactly. When Nothing, falls back to the standard set-membership check.

applyDriftFilter :: Drift -> CadenceState -> [(Cadence, Double)] -> [(Cadence, Double)] Source #

Filter the candidate pool by dissonance drift direction.

  • Dissonant: keep only candidates with dissonance >= current state's dissonance
  • Consonant: keep only candidates with dissonance <= current state's dissonance
  • Free: no filtering (return pool unchanged)

Safety fallback: if filtering empties the pool, returns the original unfiltered pool so generation never fails.