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.Pattern

A 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

on_reschedule() None[source]

Rebuild the chord pattern from the shared harmonic state.

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 count entries. Each entry contains the Chord object (quality and pitch class) and the exact MIDI note number to use as that chord’s root. Pass both directly to p.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 key or mode is not recognised, or if root_midi does 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 Chord objects can be passed directly to p.chord() or chord.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 raise ValueError — use p.snap_to_scale() for pitch snapping instead.

Returns:

List of Chord objects, 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")