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

Harmonic.Interface.Tidal.Arranger

Description

Shorthand for manipulating progressions in a TidalCycles performance context. All functions are designed for live-coding ergonomics: short names, intuitive parameter order, and no IO.

Two families, both wrapping the more verbose Harmonic.Rules.Types.Progression functions:

Rearranging
rotate, excerpt, insert, switch, clone, extract, transposeP, reverse, fuse, fuse2, interleave, expandP, progOverlap, progOverlapF, progOverlapB.
Voicing
five strategies that turn a progression into concrete pitches — grid, flow, lite, literal and root. grid and flow solve a cyclic DP for smooth voice leading; the others are literal or bass-only.

Rearranging composes on the progression before it reaches a voicing:

s  <- seek "*" $ len 8 $ entropy 0.4 $ gen
s' = fuse (excerpt 0 4 s) (rotate 2 s)

The voicing is then chosen per instrument at the point of play, so two lines can read the same progression differently:

, cello      T (0,1) k vl flow Tenor8vb
, contrabass T (0,1) k vl grid Bass8vb
Synopsis

Position/Range Operations

rotate :: Int -> ProgressionContext -> ProgressionContext Source #

Rotate a progression by n bars (positive = left, negative = right). Bar-aligned: provenance and family travel with the bars.

excerpt :: Int -> Int -> ProgressionContext -> ProgressionContext Source #

Extract bars start to end (1-indexed, inclusive). Bar-aligned: provenance and family travel with the bars.

insert :: CadenceState -> Int -> ProgressionContext -> ProgressionContext Source #

Insert a CadenceState at position (1-indexed), replacing the existing one. Bar substitution: the foreign bar breaks strata/polytonal invariants, so provenance drops and those families downgrade.

switch :: Int -> Int -> ProgressionContext -> ProgressionContext Source #

Switch two bars at positions m and n (1-indexed). Treated as substitution (drops provenance, downgrades strata/polytonal families); promotable to the aligned tier via a lockstep update pair if per-bar identity is ever wanted here.

clone :: Int -> Int -> ProgressionContext -> ProgressionContext Source #

Clone bar m to position n (overwrites n with contents of m). Treated as substitution — see switch.

extract :: Int -> ProgressionContext -> CadenceState Source #

Extract a single CadenceState at index (1-indexed, modulo wrap) from the triad layer

Transformation Operations

transposeP :: Int -> ProgressionContext -> ProgressionContext Source #

Transpose a progression by n semitones. Strata provenance is anchored to ABSOLUTE pitch classes (the octatripentatonic universe has no transposition closure), so provenance and family survive only octave shifts; any other interval drops them.

reverse :: ProgressionContext -> ProgressionContext Source #

Reverse a progression. Bar-aligned: provenance and family travel.

fuse :: [ProgressionContext] -> ProgressionContext Source #

Fuse multiple progressions into one (concatenation)

fuse2 :: ProgressionContext -> ProgressionContext -> ProgressionContext Source #

Binary fuse for convenience in live coding

interleave :: ProgressionContext -> ProgressionContext -> ProgressionContext Source #

Interleave two progressions (alternating chords) Example: interleave [A,B,C] [X,Y,Z] = [A,X,B,Y,C,Z]

expandP :: Int -> ProgressionContext -> ProgressionContext Source #

Expand a progression by repeating the WHOLE progression n times (expandP 2 on C F G A yields C F G A C F G A). Bar-aligned replication: provenance and family travel.

Overlap Operations (Progression-level)

progOverlap :: Int -> Progression -> Progression Source #

Bidirectional overlap: merge pitches from n bars in both directions

progOverlapF :: Int -> Progression -> Progression Source #

Forward-only overlap: merge pitches from n bars ahead

progOverlapB :: Int -> Progression -> Progression Source #

Backward-only overlap: merge pitches from n bars behind

Voicing Extractors (Voicing paradigms)

grid :: Progression -> [[Int]] Source #

GRID paradigm: Root locked in bass with smooth compact voice leading. Uses cyclic DP to find globally optimal voicings. First chord starts compact with root in bass; all subsequent chords maintain root in bass with minimal voice movement.

flow :: Progression -> [[Int]] Source #

FLOW paradigm: Smoothest voice leading with any inversion allowed. Uses cyclic DP to find globally optimal voicings. Voice crossings permitted for optimal smoothness; bass doesn't need to be the root if an inversion provides smoother voice leading.

lite :: Progression -> [[Int]] Source #

LITE paradigm: Literal voicings with first-root normalization. Returns pitches as stored, but normalized so first chord's root is in [-12,-1]. No voice leading optimization applied (only octave normalization).

literal :: Progression -> [[Int]] Source #

Alias for lite (legacy compatibility)

root :: Progression -> [[Int]] Source #

ROOT paradigm: Root note only (root pitch class per chord). Extracts the root note (first element, mod 12) from each chord. Returns as single-element lists in [0,11] range.

strataModeFlow :: Progression -> [[Int]] Source #

STRATA-MODE-FLOW paradigm: a fixed pitch LATTICE grounded on bar 0. Bar 0's chroma builds a compressed-ascending stack from its root (initialCompact + normalizeByFirstRoot, root anchored in [-12, -1]); every later bar keeps that lattice's slots in place and inflects each slot to the current bar's chroma — the key signature changes, the hand position does not. Pattern index i addresses the i-th lattice slot, so a held index pedals its pitch across key areas (inflecting by accidental where the new set demands it) instead of transposing with each bar's root, and increments of 1 still ascend by one set member.

Bar n (equal cardinality — the normal case: S layers uniformly 5-PC, M layers uniformly 7-PC): the minimum-cost cyclic-monotone bijection from the anchor lattice onto the bar's PC set. Each of the n cyclic rotations of the bar's sorted PCs is realised monotonically against the anchor (slot 0 nearest bar 0's slot 0, each later slot the smallest pitch above its predecessor); the rotation minimising total |placed_MIDI - anchor_MIDI| wins (tie-break: smaller net signed displacement). A bijection — not per-slot nearest-tone, which can collapse two slots onto one pitch — so every bar stays distinct, ascending, and surjective onto its chroma, and the octave-wrap identity in Harmonic.Interface.Tidal.Bridge (index n = slot 0 + 12) keeps working.

Anchoring every bar to bar 0 (rather than chaining to the previous bar) bounds drift: each slot stays within a tritone of its anchor pitch, the pattern wrap (bar N-1 → bar 0) returns home, and a bar whose chroma equals bar 0's lands on bar 0's exact MIDI.

Bars whose cardinality differs from the anchor's (silent bars, 6-PC override edges, hand-built mixed material arriving via hasBigChroma) fall back to shiftBar — slot identity is undefined across a slot-count change. O(n²) per bar, n ≤ 7; eager forcing in Harmonic.Interface.Tidal.Bridge hoists the work to REPL evaluation time.

Explicit Progression Construction

fromChords :: [[Int]] -> ProgressionContext Source #

Construct a Progression from explicit pitch-class sets. This is the main function for composing/arranging workflow (not generation). Takes an enharmonic spelling and a list of chord pitch-class sets, returns a Progression ready for arrange.

Example: fromChords [[0,4,7], [5,9,0], [7,11,2]] --> C major → F major → G major

prog :: [[Int]] -> ProgressionContext Source #

Legacy alias for fromChords (matches legacy prog function)

Scale Source (Switch Mechanism)

data ScaleSource Source #

Scale source for melody mapping. Enables flexible melody construction by allowing harmony (with optional overlap) to serve as the scale source instead of explicit scale definitions.

Constructors

ExplicitScale [[Int]]

User-defined scale per chord

HarmonyAsScale Progression

Use harmony chords as scales

HarmonyWithOverlap Progression (Int -> Progression -> Progression)

Use harmony with overlap function applied

melodyStateFrom :: ScaleSource -> Progression Source #

Create melody state from scale source. Converts a ScaleSource into a Progression suitable for melody arrangement.

Starting State Construction

lead :: String -> IO CadenceState Source #

Construct a CadenceState from a human-readable string.

Parses root, quality, and movement from space-separated tokens. Unspecified components fall through to randomness. Prints "root quality" to the console after construction.

Examples: start <- lead "E min (5)" -- E minor, ascending 5th start <- lead "E min" -- E minor, random movement start <- lead "min" -- random root, minor quality, random movement start <- lead E -- E, random quality, random movement start <- lead "" -- fully random start <- lead "(5)" -- random root and quality, fixed movement 5

lead' :: String -> IO CadenceState Source #

Construct a CadenceState from an explicit list of note names — the arbitrary-cardinality counterpart to lead. The first note is the root/bass; the rest become root-relative intervals (any count, so hand-built 4-note cues and beyond are first-class). Never truncates: builds via mkCadenceStatePCs, so all pitch content survives into the cue. Enharmonics follow the typed accidentals (Eb spells flat, D sharp; double accidentals accepted and resolved). An optional (N) token fixes the approach movement, otherwise it is randomized exactly like lead. Unrecognized tokens are reported and skipped; with no valid notes at all, falls back to fully random lead.

Examples: start <- lead' "Eb Gb Bb Db" -- Eb m7, random movement start <- lead' "A C E G (5)" -- A m7, ascending 5th approach start <- lead' "C E G" -- plain triad, same as lead "C maj"

leadJ :: String -> IO CadenceState Source #

Construct a CadenceState from a leadsheet chord symbol — the jazz counterpart to lead, for cueing genJ. Accepts the Bunks corpus grammar: root, quality, optional slash bass (Cm7, EbM7, G7b9, "Dm7/G"). Qualities occupy the jazz namespace (qualityIntervals), entirely separate from lead's triadic quality table, so triadic behaviour is untouched. A notated slash bass is honoured exactly: unioned into the pitch-class set and made the anchor, so "Dm7/G" cues from G with the full Dm7 sounding above it. An optional (N) token fixes the approach movement, otherwise it is randomized exactly like lead; either way the movement shapes bar 1's stored metadata only — a fresh walk departs from the functionality's hub node regardless. An unparseable symbol is reported and falls back to the corpus workhorse C m7.

Examples: start <- leadJ Cm7 -- C m7, random movement start <- leadJ "Dm7/G" -- G anchor, Dm7 above (a 9sus4 set) start <- leadJ "EbM7 (5)" -- Eb maj7, ascending 5th approach

parseLeadTokens :: String -> [LeadToken] Source #

Parse a lead string into a list of typed tokens. Each space-separated token is independently classified as root, quality, or movement.

data LeadToken Source #

Token type for parseLeadTokens

Instances

Instances details
Show LeadToken Source # 
Instance details

Defined in Harmonic.Interface.Tidal.Arranger

Eq LeadToken Source # 
Instance details

Defined in Harmonic.Interface.Tidal.Arranger