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

Harmonic.Evaluation.Database.Query

Description

This module implements the Evaluation (E) component of the Creative Systems Framework. It fetches transition probabilities from Neo4j and resolves composer-weighted scores for candidate cadences.

The database is treated as abstract/pitch-agnostic. Root notes and voicings are computed at runtime from user-defined starting conditions.

Synopsis

Composer Weight Parsing

type ComposerWeights = Map Text Double Source #

Map from composer name to weight (e.g., "bach" -> 0.7)

parseComposerWeights :: Text -> ComposerWeights Source #

Parse a composer selection string into normalized weights.

Composer names are matched case-insensitively against the corpus — Bach, "bach", BACH, "bAcH" all collapse to the same key. Names are lower-cased here at parse time; resolveWeights lowercases corpus edge keys at lookup time so the match is robust regardless of the case convention used during corpus ingestion.

Supported formats: "bach debussy" -> equal weights, normalized to sum 1.0 "Bach:30 Debussy:70" -> weighted, normalized; case-insensitive "bach:0.3, debussy:0.7" -> already normalized (or re-normalized if needed)

Examples: parseComposerWeights "bach debussy" == Map.fromList [("bach", 0.5), ("debussy", 0.5)] parseComposerWeights "Bach:30 DEBUSSY:70" == Map.fromList [("bach", 0.3), ("debussy", 0.7)]

normalizeWeights :: ComposerWeights -> ComposerWeights Source #

Normalize weights so they sum to 1.0

Graph Queries

fetchTransitions :: Text -> BoltActionT IO [(Cadence, ComposerWeights)] Source #

Fetch all outgoing transitions from a cadence node.

Returns: List of (Cadence, ComposerWeights) pairs for all [:NEXT] edges. The Cadence is reconstructed from Neo4j node properties (movement, chord).

Query: MATCH (c:Cadence {show: $show})-[r:NEXT]->(n:Cadence) RETURN n.movement, n.chord, r.weights

Weight Resolution

resolveWeights :: ComposerWeights -> [(Cadence, ComposerWeights)] -> [(Cadence, Double)] Source #

Resolve transition weights using the active composer blend.

For each candidate (Cadence, ComposerWeights), compute a single score by multiplying each composer's edge weight by the user's blend weight and summing.

Example: candidate weights: {"bach": 5, "debussy": 3} user blend: {"bach": 0.7, "debussy": 0.3} score = 5 * 0.7 + 3 * 0.3 = 4.4

applyComposerBlend :: ComposerWeights -> [(Cadence, ComposerWeights)] -> [(Cadence, Double)] Source #

Apply composer blend to filter transitions, keeping only those with score > 0