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

Harmonic.Traversal.WalkingBass

Description

Produces a walking-bass line for a cyclic Progression as a pure function of (progression, voiceFn) via three sequential passes:

  1. Pass 1 — beat 1s. Every bar's beat 1 is a singleton PC derived from the user-supplied VoiceFunction (fund or root). Octave placement is greedy left-to-right by smoothness to the previous beat 1, with a soft direction-persistence bias, a half-weight loop-closure pull on the final bar, and a root-fifth alternation option inside runs of consecutive identical chords. Bar 0 anchors at the register centre.
  2. Pass 2 — beat 3s. Per bar, choose from a tiered pool minimising smoothness to b1_i plus smoothness to b1_{i+1} plus consonance-to- fund cost (via beat3ConsTable) plus a tier surcharge: a target tone is free, a non-target anchor, a favourable passing tone and a bare palette tone cost progressively more, and avoid tones are not in the pool at all. Unison repeats carry a dedicated penalty so a non-repeat chord tone wins when nearby. Symmetric chords (dim / aug / dim7 / whole-tone) bypass the consonance term since no chord tone is privileged in a rotation-invariant shape.
  3. Pass 3 — beats 2 and 4. Per beat, choose from a (cyclic) local-scale pool. Connector heuristics favour chord tones adjacent to the next beat 1, penalise copying the next beat 1 outright on beat 4, reward chromatic approaches to the next beat 1 regardless of scale/chord membership (so root-as-leading-tone can win), resolve static (b1==b3) bars via the chord's P5 or — on symmetric chords — any non-root chord tone, and reward root-on-b4 (full weight) or P5-on-b4 (half weight) when that tone sits 1–2 semitones from the next b1. If b3 already used the root / P5 at tone distance, the approach bonus shifts to the chromatic in-between tone so the line avoids a b3→b4 unison. Stranded connectors (neither flank within a whole step) pay a sandwich penalty; quality-defining chord tones are reserved for strong beats (only root/P5 earn the beat-4 chord-tone bonus).

The entropy parameter that used to be user-facing is now derived from the progression's root-motion angularity and chord-internal dissonance. Calm diatonic progressions land near 0 (more settled repeats allowed); angular tritone-heavy progressions land near 1 (fewer repeats, more chromatic motion). Progression-level consonance (progConsonance) independently scales strong-beat strictness and connector tension licence. Pure-function guarantees are preserved: same progression and voiceFn always produce the same line.

Three family variants share these passes, differing only in what they feed them: walkLine walks the plain per-bar tone sets at whatever cardinality each bar carries (gen and genE), walkLineP narrows the pools to the octatripentatonic strata (genP), and walkLineJ reads each bar through a BassVocab derived from its chord symbol (genJ). Each has a Dyn twin taking a per-bar dynamics vector. Callers normally reach them through lineHarmony, which dispatches on the progression's family.

Synopsis

Main entry

walkLine :: VoiceFunction -> Progression -> [[Int]] Source #

Generate a walking-bass line. Entropy is derived from the progression's harmonic character; the caller supplies only the progression and a voice function (fund or root) defining each bar's beat 1.

walkLineP :: VoiceFunction -> Progression -> [ChromaSources] -> [[Int]] Source #

Octatripentatonic-aware walking-bass line. Pass 1 (beat 1s from voiceFn) and Pass 2 (beat 3s) are unchanged from walkLine; Pass 3 (beats 2 & 4) swaps the chromatic-±1 candidate path for tier-scored strata / overlap / mode candidates supplied per bar via ChromaSources. Caller is responsible for matching length chromas to progLength prog (mismatch falls back to the legacy walkLine path for safety).

walkLineJ :: VoiceFunction -> Progression -> [BassVocab] -> [[Int]] Source #

Jazz-aware walking-bass line: walkLineJDyn with no dynamics vector.

walkLineDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [[Int]] Source #

walkLine with an optional per-bar dynamic vector coupling the beat-1 register arc to the piece's dynamics (see kappaDynArc). Nothing is byte-identical to walkLine.

walkLinePDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [ChromaSources] -> [[Int]] Source #

walkLineP with the optional dynamic vector of walkLineDyn.

walkLineJDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [BassVocab] -> [[Int]] Source #

Walking-bass line over a jazz-corpus progression, guided by per-bar BassVocab (typically bassVocabFor . cadenceIntervals per bar, as LineHarmony derives for FJazz contexts). Corpus tone sets describe working voicings, not bass vocabulary: 13th chords omit the 5th and 11th, altered qualities replace the 5th, and notated colour tones (b9 / #9 / #11 / b13) must not land on strong beats. The vocabulary restores THE fifth for every fifth-driven term, anchors strong beats on bvStrong, prices bvPassing at a middle beat-3 tier, and gates the connector chord-tone bonuses on strong-plus-passing membership — while the raw notated set still shapes the connector pools, so colour tones remain reachable as weak-beat tension. Caller matches length vocabs to the progression (mismatch falls back to walkLineDyn).

data ChromaSources Source #

Per-bar chroma sources for the walkLineP Pass-3 connector pool. csStrata is the bar's full 5-PC strata chroma; csMode is the full 7-PC mode chroma. Both are supplied by the caller (typically derived from strataLayer / modeLayer of a genP-origin ProgressionContext).

Constructors

ChromaSources 

Fields

Derived entropy (exported for tests / diagnostics)

progressionEntropy :: Progression -> Double Source #

Entropy derived from the progression's harmonic character. Calm diatonic progressions land near 0; angular / tritone-heavy progressions approach 1. Deterministic: same progression always yields the same value.

progConsonance :: Progression -> Double Source #

Mean per-bar consonance of the progression in [0, 1], 1 = consonant. dissonanceScore grows with chord cardinality (major/minor triads score 6 while the most consonant tetrads score 19), so each bar is normalised against anchors for its own chord size before averaging — otherwise every tetrad progression would read as maximally dissonant. Consumed by the walk to scale strong-beat strictness and connector tension licence; orthogonal to progressionEntropy, which is dominated by root motion.

Utilities (exported for tests)

hashProgEntropy :: Progression -> Double -> Int Source #

Deterministic mixing of progression shape and entropy into a seed.

closestLowMidi :: Int -> Int Source #

Lowest MIDI in [lowestMidi, highestMidi] whose pitch class equals pc. Always in range: the register spans more than an octave, so the lowest PC-matching value sits at most 11 semitones above lowestMidi.

closestMidMidi :: Int -> Int Source #

In-register instance of a pitch class nearest registerCenter (lower on tie). Anchoring bar 0 here gives the greedy beat-1 chain headroom in both directions and evens out the single-instance asymmetry of the PCs that occur only once in the register.

lowestMidi :: Int Source #

Walking-bass register and metre constants. lowestMidi 28 and highestMidi 48 bound the line to a double-bass register; beatsPerBar is 4 (the walking idiom is quarter-note based); registerCenter 38 is the pitch the line is drawn back toward when free to choose.

highestMidi :: Int Source #

Walking-bass register and metre constants. lowestMidi 28 and highestMidi 48 bound the line to a double-bass register; beatsPerBar is 4 (the walking idiom is quarter-note based); registerCenter 38 is the pitch the line is drawn back toward when free to choose.

beatsPerBar :: Int Source #

Walking-bass register and metre constants. lowestMidi 28 and highestMidi 48 bound the line to a double-bass register; beatsPerBar is 4 (the walking idiom is quarter-note based); registerCenter 38 is the pitch the line is drawn back toward when free to choose.

isSymmetricChord :: Set Int -> Bool Source #

True iff the chord contains no perfect-fourth/fifth (5 or 7 semitones) between any pair of tones. Covers diminished triads ([0,3,6]), augmented triads ([0,4,8]), diminished sevenths ([0,3,6,9]), and whole-tone hexachords — synthetic shapes with no privileged fifth, where every chord tone is equally anchor-worthy.