subsequence.chords

Chord definitions and pitch class utilities.

This module provides chord quality definitions, pitch class mappings, and the Chord class for representing and manipulating chords.

Module-level constants:

  • NOTE_NAME_TO_PC: Maps note names (e.g., "C", "F#", "Bb") to pitch classes (0-11)

  • PC_TO_NOTE_NAME: Maps pitch classes to note names

  • CHORD_INTERVALS: Maps chord quality names to interval lists (semitones from root)

  • CHORD_SUFFIX: Maps chord quality names to human-readable suffixes (e.g., "m", "7")

Module-level helpers:

  • key_name_to_pc(key_name): Validate a key name and return its pitch class (0–11). Raises ValueError for unknown names. This is the canonical key validation function used by harmony.py, pattern_builder.snap_to_scale(), and chord_graphs.validate_key_name().

Chord qualities: "major", "minor", "diminished", "augmented", "dominant_7th", "major_7th", "minor_7th", "half_diminished_7th", "sus2", "sus4"

Module Contents

class subsequence.chords.Chord[source]

Represents a chord as a root pitch class and quality.

bass_note(root_midi: int, octave_offset: int = -1) int[source]

Return the chord root shifted by a number of octaves.

Commonly used to produce a bass register note one or two octaves below the chord voicing.

Parameters:
  • root_midi – Reference MIDI note number (passed to root_note()).

  • octave_offset – Octaves to shift; negative moves down (default -1).

Returns:

MIDI note number of the chord root in the target register.

Example

chord = Chord(root_pc=4, quality="major")  # E major
chord.bass_note(64)        # → 52  (E3, one octave down from E4)
chord.bass_note(64, -2)    # → 40  (E2, two octaves down)
intervals() List[int][source]

Return the chord intervals for this chord quality.

name() str[source]

Return a human-friendly chord name.

A registered quality without a suffix prints as root(quality) (e.g. "C(quartal)") rather than masquerading as a plain major.

root_note(root_midi: int) int[source]

Return the MIDI note number for the chord root nearest to root_midi.

This is equivalent to self.tones(root_midi)[0] but makes intent explicit when you only need the single root pitch.

Parameters:

root_midi – Reference MIDI note number used to find the closest octave of this chord’s root pitch class.

Returns:

MIDI note number of the chord root.

Example

chord = Chord(root_pc=4, quality="major")  # E major
chord.root_note(60)   # → 64  (E4, nearest to C4)
chord.root_note(69)   # → 64  (E4, nearest to A4)
tones(root: int, inversion: int = 0, count: int | None = None) List[int][source]

Return MIDI note numbers for chord tones starting from a root.

Finds the MIDI note corresponding to the chord’s root pitch class that is closest to the provided root argument.

Parameters:
  • root – MIDI note number (e.g., 60 = middle C) to center the chord around.

  • inversion – Chord inversion (0 = root position, 1 = first, 2 = second, …). Wraps around for values >= number of notes.

  • count – Number of notes to return. When set, the chord intervals cycle into higher octaves until count notes are produced. When None (default), returns the natural chord tones.

Returns:

List of MIDI note numbers for chord tones

Example

chord = Chord(root_pc=0, quality="major")  # C major
chord.tones(root=60)               # [60, 64, 67] - root position around C4
chord.tones(root=62)               # [60, 64, 67] - still finds C4 as closest root
chord.tones(root=70)               # [72, 76, 79] - finds C5 as closest root
subsequence.chords.key_name_to_pc(key_name: str) int[source]

Validate a key name and return its pitch class (0–11).

Parameters:

key_name – Note name (e.g. "C", "F#", "Bb").

Returns:

Pitch class integer (0–11).

Raises:

ValueError – If the key name is not recognised.

Example

key_name_to_pc("C")   # → 0
key_name_to_pc("F#")  # → 6
key_name_to_pc("Bb")  # → 10
subsequence.chords.parse_chord(name: str) Chord[source]

Parse a chord name like "Cm7" or "Dbmaj7" into a Chord.

The name is a root note (AG with an optional # or b) followed by a quality suffix: "" major, m minor, dim diminished, +/aug augmented, 7 dominant 7th, maj7 major 7th, m7 minor 7th, m7b5/ø half-diminished 7th, sus2, sus4. A few common alternates (min, -, M7, …) are accepted too.

Raises ValueError for anything it can’t read, so a typo surfaces at the call site rather than as a silently wrong chord.

Example

parse_chord("Cm7")    # → Chord(root_pc=0, quality="minor_7th")
parse_chord("Dbmaj7") # → Chord(root_pc=1, quality="major_7th")
parse_chord("F#")     # → Chord(root_pc=6, quality="major")
subsequence.chords.register_chord_quality(name: str, intervals: List[int], suffix: str | None = None) None[source]

Register a custom chord quality for use everywhere chords are used.

The counterpart to subsequence.intervals.register_scale() — it opens the quality table so quartal stacks, clusters, and extended chords become first-class symbolic chords: they work in progressions, graphs, voice leading, and describe() output.

Built-in qualities (e.g. "minor") cannot be overwritten. Custom names may be re-registered freely — live reload re-runs registration on every save, so this must not raise.

Parameters:
  • name – Quality name (used as Chord(root_pc, quality=name)).

  • intervals – Semitone offsets from the root (e.g. [0, 5, 10] for a quartal stack, [0, 3, 7, 10, 14] for a minor 9th). Must start with 0, ascend strictly, and stay within 0–24 (extensions reach past the octave).

  • suffix – Optional chord-name suffix. When given, parse_chord() accepts "A" + suffix and Chord.name() prints it — so register_chord_quality("minor_9th", [0, 3, 7, 10, 14], suffix="m9") makes "Am9" parse from then on. Must not collide with a built-in suffix.

Example

import subsequence

subsequence.register_chord_quality("quartal", [0, 5, 10], suffix="q4")
subsequence.parse_chord("Dq4")   # → Chord(root_pc=2, quality="quartal")