| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Harmonic.Traversal.WalkingBass
Description
Produces a walking-bass line for a cyclic Progression as a pure function of (progression, voiceFn) via three sequential passes:
- Pass 1 — beat 1s. Every bar's beat 1 is a singleton PC derived from
the user-supplied VoiceFunction (
fundorroot). 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. - Pass 2 — beat 3s. Per bar, choose a chord tone minimising smoothness
to b1_i plus smoothness to b1_{i+1} plus consonance-to-fund cost
(via
beat3ConsTable). 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. - 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.
Synopsis
- walkLine :: VoiceFunction -> Progression -> [[Int]]
- walkLineP :: VoiceFunction -> Progression -> [ChromaSources] -> [[Int]]
- walkLineDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [[Int]]
- walkLinePDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [ChromaSources] -> [[Int]]
- data ChromaSources = ChromaSources {}
- progressionEntropy :: Progression -> Double
- progConsonance :: Progression -> Double
- inferKeyCentre :: Progression -> [PitchClass]
- hashProgEntropy :: Progression -> Double -> Int
- closestLowMidi :: Int -> Int
- closestMidMidi :: Int -> Int
- lowestMidi :: Int
- highestMidi :: Int
- beatsPerBar :: Int
- isSymmetricChord :: Set Int -> Bool
Main entry
walkLine :: VoiceFunction -> Progression -> [[Int]] Source #
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).
walkLineDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [[Int]] Source #
walkLinePDyn :: Maybe [Double] -> VoiceFunction -> Progression -> [ChromaSources] -> [[Int]] Source #
walkLineP with the optional dynamic vector of 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).
Instances
| Show ChromaSources Source # | |
Defined in Harmonic.Traversal.WalkingBass Methods showsPrec :: Int -> ChromaSources -> ShowS # show :: ChromaSources -> String # showList :: [ChromaSources] -> ShowS # | |
| Eq ChromaSources Source # | |
Defined in Harmonic.Traversal.WalkingBass Methods (==) :: ChromaSources -> ChromaSources -> Bool # (/=) :: ChromaSources -> ChromaSources -> Bool # | |
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.
inferKeyCentre :: Progression -> [PitchClass] Source #
Per-bar regional key centre, inferred from chord qualities over a local window.
BOUNDARY: this is a PURE, DERIVED quantity computed over a finished progression, consumed only inside the walk's connector selection. The generation system deliberately operates without key awareness — each state is abstract and deterministic, upholding the Markov property — so this function must never feed back into generation, become part of any state, or appear in a generation-path signature.
Heuristics (weights in votes): a dominant-quality chord is V of its key; a major-quality chord is I (strong) or IV (weak), plain major triads also V (weak); a minor-quality chord is ii (strong), vi, or iii (weak); half-diminished is vii. Relative major/minor are treated as one pool and reported as the major-pool pitch class. Each bar takes the key with the highest vote total over the surrounding window (cyclic, +/- 2 bars); ties resolve to the lowest pitch class.
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.