Scales

class pytheory.scales.Scale(*, tones: tuple[Tone, ...], degrees: tuple[str, ...] | None = None, system: str | System = 'western')[source]

Bases: object

__init__(*, tones: tuple[Tone, ...], degrees: tuple[str, ...] | None = None, system: str | System = 'western') None[source]

Initialize a Scale from a sequence of Tones.

Parameters:
  • tones – The tones that make up the scale.

  • degrees – Optional names for each scale degree (must match length of tones).

  • system – A tone system name or System instance.

Raises:

ValueError – If degrees is provided but its length differs from tones.

property system: System | None

Return the tone system for this scale.

Resolves a system name to a System object on first access.

__repr__() str[source]

Return repr(self).

__iter__()[source]

Iterate over the tones in this scale.

__len__() int[source]

Return the number of tones in this scale (including the octave).

__contains__(item: str | Tone) bool[source]

Check whether a tone or note name belongs to this scale.

property note_names: list[str]

List of note names in this scale.

chord(*degrees: int) Chord[source]

Build a Chord from scale degrees (0-indexed).

Wraps around if degrees exceed the scale length, transposing up by an octave as needed.

Example: scale.chord(0, 2, 4) builds a triad from the 1st, 3rd, 5th.

transpose(semitones: int) Scale[source]

Return a new Scale transposed by the given number of semitones.

Every tone is shifted by the same interval, preserving the scale’s interval pattern.

Example:

>>> c_major = TonedScale(tonic="C4")["major"]
>>> d_major = c_major.transpose(2)
>>> d_major.note_names
['D', 'E', 'F#', 'G', 'A', 'B', 'C#', 'D']
triad(root: int = 0) Chord[source]

Build a triad starting from the given scale degree (0-indexed).

Returns a chord with the root, 3rd, and 5th above it.

seventh(root: int = 0) Chord[source]

Build a seventh chord from the given scale degree (0-indexed).

Returns a chord with the root, 3rd, 5th, and 7th.

progression(*numerals: str) list[Chord][source]

Build a chord progression from Roman numeral strings.

Accepts Roman numerals like "I", "IV", "V", "ii", "vi". Lowercase = minor triad, uppercase = major triad. Add "7" suffix for seventh chords.

Example:

>>> scale.progression("I", "IV", "V", "I")
[<Chord (C,E,G)>, <Chord (F,A,C)>, <Chord (G,B,D)>, <Chord (C,E,G)>]
nashville(*numbers: int | str) list[Chord][source]

Build a chord progression using Nashville number system.

The Nashville number system uses Arabic numerals instead of Roman numerals. It’s the standard chart system in Nashville recording studios.

Numbers 1-7 build diatonic triads. Suffix "7" for seventh chords, "m" to force minor.

Example:

>>> scale.nashville(1, 4, 5, 1)
[<Chord C major>, <Chord F major>, <Chord G major>, <Chord C major>]
static detect(*note_names: str) tuple[str, str, int] | None[source]

Detect the most likely scale from a set of note names.

Tries all scales in the Western system and returns the best match as a (tonic, scale_name, match_count) tuple.

Example:

>>> Scale.detect("C", "D", "E", "F", "G", "A", "B")
('C', 'major', 7)
>>> Scale.detect("C", "D", "Eb", "F", "G", "Ab", "Bb")
('C', 'minor', 7)
harmonize() list[Chord][source]

Build diatonic triads on every scale degree.

Returns a list of Chords — one triad for each degree of the scale. In a major scale this produces: I, ii, iii, IV, V, vi, vii°.

Example:

>>> [c.identify() for c in TonedScale(tonic="C4")["major"].harmonize()]
['C major', 'D minor', 'E minor', 'F major', 'G major', 'A minor', 'B diminished']
degree(item: str | int | slice, major: bool | None = None, minor: bool = False) Tone | tuple[Tone, ...] | None[source]
__getitem__(item: str | int | slice) Tone | tuple[Tone, ...][source]

Retrieve a tone by scale degree (integer, Roman numeral, or degree name).

Raises:

KeyError – If the given degree is not found in this scale.

pytheory.scales.PROGRESSIONS = {'12-bar blues': ('I', 'I', 'I', 'I', 'IV', 'IV', 'I', 'I', 'V', 'IV', 'I', 'V'), 'Andalusian': ('i', 'VII', 'VI', 'V'), 'Dorian vamp': ('i', 'IV'), 'I-IV-V-I': ('I', 'IV', 'V', 'I'), 'I-IV-vi-V': ('I', 'IV', 'vi', 'V'), 'I-V-vi-IV': ('I', 'V', 'vi', 'IV'), 'I-vi-IV-V': ('I', 'vi', 'IV', 'V'), 'I-vi-ii-V': ('I', 'vi', 'ii', 'V'), 'Mixolydian vamp': ('I', 'VII'), 'Pachelbel': ('I', 'V', 'vi', 'iii', 'IV', 'I', 'IV', 'V'), 'i-bVI-bIII-bVII': ('i', 'VI', 'III', 'VII'), 'ii-V-I': ('ii', 'V7', 'I'), 'iii-vi-ii-V': ('iii', 'vi', 'ii', 'V'), 'vi-IV-I-V': ('vi', 'IV', 'I', 'V')}

Common chord progressions as Roman numeral tuples.

Use with Scale.progression() or Key.progression():

Key("C", "major").progression(*PROGRESSIONS["I-V-vi-IV"])
class pytheory.scales.Key(tonic: str, mode: str = 'major', system: str | System | None = None)[source]

Bases: object

A musical key — a convenient entry point for scales and harmony.

A Key represents a tonic note and a mode. It provides quick access to the scale, diatonic chords, and common progressions.

Example:

>>> key = Key("C", "major")
>>> key.scale.note_names
['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C']
>>> key.chords
['C major', 'D minor', 'E minor', 'F major', ...]
>>> key.progression("I", "V", "vi", "IV")
[<Chord (C,E,G)>, <Chord (G,B,D)>, ...]
__init__(tonic: str, mode: str = 'major', system: str | System | None = None) None[source]
classmethod detect(*note_names: str) Key | None[source]

Detect the most likely key from a set of note names.

Tries every possible major and minor key and returns the one whose scale contains the most of the given notes.

Example:

>>> Key.detect("C", "D", "E", "F", "G", "A", "B")
<Key C major>
>>> Key.detect("A", "B", "C", "D", "E", "F", "G")
<Key C major>
>>> Key.detect("A", "C", "E")
<Key C major>
Returns:

The best-matching Key, or None if no notes given.

__repr__() str[source]

Return repr(self).

property scale: Scale

The scale for this key.

property note_names: list[str]

Note names in this key’s scale.

property chords: list[str]

Names of all diatonic triads in this key.

property seventh_chords: list[str]

Names of all diatonic seventh chords in this key.

triad(degree: int) Chord[source]

Build a diatonic triad on the given degree (0-indexed).

seventh(degree: int) Chord[source]

Build a diatonic seventh chord on the given degree (0-indexed).

progression(*numerals: str) list[Chord][source]

Build a chord progression from Roman numerals.

Example:

>>> Key("G", "major").progression("I", "IV", "V7", "I")
nashville(*numbers: int | str) list[Chord][source]

Build a chord progression using Nashville numbers.

Example:

>>> Key("G", "major").nashville(1, 4, 5, 1)
secondary_dominant(degree: int) Chord[source]

Build a secondary dominant (V/x) for the given scale degree.

A secondary dominant is the dominant chord of a non-tonic degree. For example, in C major, V/V is D major (the V chord of G). Secondary dominants create momentary tonicizations that add color and forward motion.

Common secondary dominants:

  • V/V (e.g. D7 in C major) — approaches the dominant

  • V/ii (e.g. A7 in C major) — approaches the supertonic

  • V/vi (e.g. E7 in C major) — approaches the relative minor

Parameters:

degree – Scale degree to target (1-indexed). 5 means “build the V of the 5th degree.”

Returns:

A dominant 7th Chord that resolves to the given degree.

Example:

>>> Key("C", "major").secondary_dominant(5)  # V/V = D7
<Chord D dominant 7th>
classmethod all_keys() list[Key][source]

Return all 24 major and minor keys.

Returns:

A list of Key objects for all 12 major and 12 minor keys.

Example:

>>> for k in Key.all_keys():
...     print(k)
property signature: dict

The key signature — number and names of sharps or flats.

In Western music, each key has a unique key signature that tells you which notes are sharped or flatted throughout a piece.

Returns:

  • sharps (int): number of sharps (0 if flat key)

  • flats (int): number of flats (0 if sharp key)

  • accidentals (list[str]): the sharped/flatted note names

Return type:

A dict with

Example:

>>> Key("G", "major").signature
{'sharps': 1, 'flats': 0, 'accidentals': ['F#']}
>>> Key("F", "major").signature
{'sharps': 0, 'flats': 1, 'accidentals': ['Bb']}
>>> Key("C", "major").signature
{'sharps': 0, 'flats': 0, 'accidentals': []}
property borrowed_chords: list[str]

Chords borrowed from the parallel key.

Modal interchange (or modal mixture) borrows chords from the parallel major or minor key. In C major, the parallel minor is C minor, which provides chords like Ab major, Bb major, and Eb major — commonly heard in rock, film, and pop music.

Returns:

A list of chord names from the parallel key that are NOT in the current key’s diatonic chords.

Example:

>>> Key("C", "major").borrowed_chords
['C minor', 'D diminished', 'D# major', ...]
random_progression(length: int = 4) list[source]

Generate a random diatonic chord progression.

Uses weighted probabilities based on common chord function: I and vi are most common, IV and V are very common, ii is common, iii and viidim are rare. Always starts on I and ends on I or V.

Parameters:

length – Number of chords (default 4).

Returns:

A list of Chord objects.

Example:

>>> Key("C", "major").random_progression(4)
[<Chord C major>, <Chord F major>, <Chord G major>, <Chord C major>]
property relative: Key | None

The relative major or minor key.

If this is a major key, returns the relative minor (vi). If this is a minor key, returns the relative major (bIII).

property parallel: Key | None

The parallel major or minor key (same tonic, different mode).

class pytheory.scales.TonedScale(*, system: str | System = <System semitones=12>, tonic: str | Tone)[source]

Bases: object

__init__(*, system: str | System = <System semitones=12>, tonic: str | Tone) None[source]

Initialize a TonedScale with a tonic note and tone system.

Parameters:
  • system – A tone system name or System instance.

  • tonic – The tonic note as a string (e.g. "C4") or Tone.

__repr__() str[source]

Return repr(self).

__getitem__(scale: str) Scale[source]

Retrieve a scale by name.

Raises:

KeyError – If the named scale is not found in this system.

get(scale: str) Scale | None[source]

Look up a scale by name, returning None if not found.

property scales: tuple[str, ...]

Tuple of all available scale names in this system.