| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
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,literalandroot.gridandflowsolve 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
- rotate :: Int -> ProgressionContext -> ProgressionContext
- excerpt :: Int -> Int -> ProgressionContext -> ProgressionContext
- insert :: CadenceState -> Int -> ProgressionContext -> ProgressionContext
- switch :: Int -> Int -> ProgressionContext -> ProgressionContext
- clone :: Int -> Int -> ProgressionContext -> ProgressionContext
- extract :: Int -> ProgressionContext -> CadenceState
- transposeP :: Int -> ProgressionContext -> ProgressionContext
- reverse :: ProgressionContext -> ProgressionContext
- fuse :: [ProgressionContext] -> ProgressionContext
- fuse2 :: ProgressionContext -> ProgressionContext -> ProgressionContext
- interleave :: ProgressionContext -> ProgressionContext -> ProgressionContext
- expandP :: Int -> ProgressionContext -> ProgressionContext
- progOverlap :: Int -> Progression -> Progression
- progOverlapF :: Int -> Progression -> Progression
- progOverlapB :: Int -> Progression -> Progression
- grid :: Progression -> [[Int]]
- flow :: Progression -> [[Int]]
- lite :: Progression -> [[Int]]
- literal :: Progression -> [[Int]]
- root :: Progression -> [[Int]]
- strataModeFlow :: Progression -> [[Int]]
- fromChords :: [[Int]] -> ProgressionContext
- prog :: [[Int]] -> ProgressionContext
- data ScaleSource
- = ExplicitScale [[Int]]
- | HarmonyAsScale Progression
- | HarmonyWithOverlap Progression (Int -> Progression -> Progression)
- melodyStateFrom :: ScaleSource -> Progression
- lead :: String -> IO CadenceState
- lead' :: String -> IO CadenceState
- leadJ :: String -> IO CadenceState
- parseLeadTokens :: String -> [LeadToken]
- data LeadToken
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.