subsequence.harmony¶
Harmony helpers — diatonic chords without the chord-graph engine.
Standalone convenience functions (diatonic_chords, diatonic_chord,
diatonic_chord_sequence) for building chords from a key and mode, plus the
ChordPattern view. For generative progressions use progressions.
Module Contents¶
- class subsequence.harmony.ChordPattern(harmonic_state: subsequence.harmonic_state.HarmonicState, length: int = 4, root_midi: int = 52, velocity: int = subsequence.constants.velocity.DEFAULT_CHORD_VELOCITY, reschedule_lookahead: int = 1, channel: int | None = None, voice_leading: bool = False)[source]¶
Bases:
subsequence.pattern.PatternA repeating chord pattern that follows the shared harmonic state.
Initialize a chord pattern driven by composition-level harmony.
- Parameters:
harmonic_state – Shared harmonic state that provides chord changes
length – Pattern length in beats (default 4)
root_midi – Base MIDI note number for the chord root (default 52)
velocity – MIDI velocity 0-127 (default 90)
reschedule_lookahead – Reschedule lookahead in beats (default 1)
channel – MIDI channel (0-15, required)
voice_leading – When True, each chord automatically picks the inversion closest to the previous chord for smooth movement
- subsequence.harmony.diatonic_chord(key: str, mode: str = 'ionian', degree: int = 0) subsequence.chords.Chord[source]¶
Return a single diatonic chord by scale degree.
Convenience wrapper around
diatonic_chords()for the common case where only one chord is needed.- Parameters:
key – Root note name (e.g.
"E","Bb").mode – Scale mode (default
"ionian").degree – Zero-indexed scale degree (0 = I/tonic, 4 = V/dominant, etc.).
- Raises:
ValueError – If degree is out of range for the mode.
Example
tonic = diatonic_chord("E", "phrygian") # I dominant = diatonic_chord("E", "phrygian", degree=4) # V
- subsequence.harmony.diatonic_chord_sequence(key: str, root_midi: int, count: int, mode: str = 'ionian') List[Tuple[subsequence.chords.Chord, int]][source]¶
Return a list of
(Chord, midi_root)tuples stepping diatonically upward.Useful for mapping a continuous value (like altitude or brightness) to a chord, or for building explicit rising/falling progressions without using the chord graph engine.
The returned list has
countentries. Each entry contains theChordobject (quality and pitch class) and the exact MIDI note number to use as that chord’s root. Pass both directly top.chord(chord, root=midi_root).Counts larger than the number of scale degrees wrap into higher octaves automatically. The sequence always steps upward — reverse the list for a falling sequence.
- Parameters:
key – Note name for the key (e.g.,
"D","Eb","F#").root_midi – MIDI note number for the first chord’s root. Must fall on a scale degree of the chosen key and mode.
count – Number of
(Chord, midi_root)pairs to generate.mode – One of
"ionian"(or"major"),"dorian","phrygian","lydian","mixolydian","aeolian"(or"minor"),"locrian","harmonic_minor","melodic_minor".
- Returns:
List of
(Chord, int)tuples, one per step.- Raises:
ValueError – If
keyormodeis not recognised, or ifroot_mididoes not fall on a scale degree of the key.
Example
from subsequence.harmony import diatonic_chord_sequence # 7-step D Major ladder starting at D3 (MIDI 50) sequence = diatonic_chord_sequence("D", root_midi=50, count=7) # Map a 0-1 value to a chord (e.g. from ISS altitude) chord, root = sequence[int(ratio * (len(sequence) - 1))] p.chord(chord, root=root, sustain=True) # Falling sequence for chord, root in reversed(diatonic_chord_sequence("A", 57, 7, "minor")): ...
- subsequence.harmony.diatonic_chords(key: str, mode: str = 'ionian') List[subsequence.chords.Chord][source]¶
Return the diatonic triads for a key and mode.
This is a convenience function for generating chord sequences without using the chord graph engine. The returned
Chordobjects can be passed directly top.chord()orchord.tones()inside a pattern.- Parameters:
key – Note name for the key (e.g.,
"C","Eb","F#").mode – A mode with chord qualities defined (e.g.
"ionian","dorian","minor"). Scales without chord qualities (e.g."hirajoshi") will raiseValueError— usep.snap_to_scale()for pitch snapping instead.
- Returns:
List of
Chordobjects, one per scale degree.
Example
from subsequence.harmony import diatonic_chords # All 7 chords in Eb Major chords = diatonic_chords("Eb") # Natural minor chords in A chords = diatonic_chords("A", mode="minor") # Dorian chords in D chords = diatonic_chords("D", mode="dorian")