Chords and Fretboard

class pytheory.chords.Chord(tones: list[Tone])[source]

Bases: object

__init__(tones: list[Tone]) None[source]

Initialize a Chord from a list of Tone objects.

Parameters:

tones – A list of Tone instances that make up the chord.

classmethod from_tones(*note_names: str, octave: int = 4) Chord[source]

Create a Chord from note name strings.

Example:

>>> Chord.from_tones("C", "E", "G")
<Chord C major>
>>> Chord.from_tones("A", "C", "E", octave=3)
<Chord A minor>
classmethod from_name(name: str, octave: int = 4) Chord[source]

Create a Chord from a chord name like "Cmaj7" or "Am".

Uses the built-in chord chart to find the correct tones, then builds the chord at the given octave.

Example:

>>> Chord.from_name("C")
<Chord C major>
>>> Chord.from_name("Am7")
<Chord A minor 7th>
>>> Chord.from_name("G7", octave=3)
<Chord G dominant 7th>
classmethod from_intervals(root: str, *intervals: int, octave: int = 4) Chord[source]

Create a Chord from a root note and semitone intervals.

Example:

>>> Chord.from_intervals("C", 4, 7)          # C major
<Chord C major>
>>> Chord.from_intervals("G", 4, 7, 10)      # G7
<Chord G dominant 7th>
>>> Chord.from_intervals("D", 3, 7)           # D minor
<Chord D minor>
classmethod from_midi_message(*note_numbers: int) Chord[source]

Create a Chord from MIDI note numbers.

Example:

>>> Chord.from_midi_message(60, 64, 67)   # C4, E4, G4
<Chord C major>
__repr__() str[source]

Return repr(self).

__iter__() Iterator[Tone][source]

Iterate over the tones in this chord.

__len__() int[source]

Return the number of tones in this chord.

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

Check if a tone (by name or Tone object) is in this chord.

tritone_sub() Chord[source]

Return the tritone substitution of this chord.

In jazz harmony, any dominant chord can be replaced by the dominant chord a tritone (6 semitones) away. G7 → Db7, C7 → F#7. This works because the two chords share the same tritone interval (the 3rd and 7th swap roles).

Returns a new Chord transposed by 6 semitones.

inversion(n: int = 1) Chord[source]

Return the nth inversion of this chord.

An inversion moves the lowest tone(s) up by one octave:

  • 0th inversion = root position (unchanged)

  • 1st inversion = move root up an octave

  • 2nd inversion = move root and 3rd up an octave

Example:

>>> c_major = Chord([C4, E4, G4])
>>> c_major.inversion(1)   # E4, G4, C5
>>> c_major.inversion(2)   # G4, C5, E5
transpose(semitones: int) Chord[source]

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

Every tone in the chord is shifted up (positive) or down (negative) by the same interval, preserving the chord’s quality and voicing.

Example:

>>> c_major = Chord([C4, E4, G4])
>>> c_major.transpose(7).identify()
'G major'
property root: Tone | None

The root of this chord (if identifiable).

Returns the Tone that serves as the root based on chord identification, or None if the chord can’t be identified.

property quality: str | None

The quality of this chord (e.g. ‘major’, ‘minor 7th’).

Returns the quality string from chord identification, or None if the chord can’t be identified.

property intervals: list[int]

Semitone distances between adjacent tones in the chord.

Returns a list of integers, where each value is the absolute number of semitones between consecutive tones. This is octave-invariant — a major third is always 4 semitones whether it’s C4→E4 or C6→E6.

Common interval values:

1  = minor 2nd (half step)
2  = major 2nd (whole step)
3  = minor 3rd
4  = major 3rd
5  = perfect 4th
6  = tritone
7  = perfect 5th
12 = octave

Example:

>>> c_major = Chord(tones=[C4, E4, G4])
>>> c_major.intervals
[4, 3]  # major 3rd + minor 3rd

Returns an empty list for chords with fewer than 2 tones.

property harmony: float

Consonance score based on frequency ratio simplicity.

Computed by examining the frequency ratio between every pair of tones, reducing it to its simplest fractional form (limited to denominators ≤ 32), and summing 1 / (numerator + denominator).

The psychoacoustic basis: intervals whose frequencies form simple integer ratios are perceived as consonant. A perfect fifth (3:2) scores higher than a tritone (45:32) because simpler ratios produce fewer interfering overtones.

Reference consonance scores for common intervals:

Octave (2:1)     → 1/(2+1)  = 0.333
Perfect 5th (3:2) → 1/(3+2)  = 0.200
Perfect 4th (4:3) → 1/(4+3)  = 0.143
Major 3rd (5:4)  → 1/(5+4)  = 0.111
Tritone (45:32)  → 1/(45+32) = 0.013

For chords with multiple tones, all pairwise ratios are summed — a C major triad (C-E-G) scores higher than C-E-Gb because the C-G fifth contributes a large consonance term.

Returns 0 for chords with fewer than 2 tones.

property dissonance: float

Sensory dissonance score using the Plomp-Levelt roughness model.

When two tones are close in frequency, their waveforms interfere and produce a perceived “roughness.” This roughness peaks when the frequency difference is about 25% of the critical bandwidth (roughly 1/4 of the lower frequency) and diminishes for wider or narrower separations.

The model: for each pair of tones, compute x = freq_diff / critical_bandwidth using the Bark-scale critical bandwidth formula (Zwicker & Terhardt, 1980): CB = 25 + 75 * (1 + 1.4 * (f/1000)^2)^0.69 then apply the Plomp-Levelt curve x * e^(1-x). This peaks at x=1 (maximum roughness) and decays for larger intervals.

Practical implications:

  • A minor 2nd (C4-Db4, ~15 Hz apart) produces high roughness

  • A major 3rd (C4-E4, ~68 Hz apart) produces moderate roughness

  • A perfect 5th (C4-G4, ~130 Hz apart) produces low roughness

  • Roughness is frequency-dependent: the same interval sounds rougher in lower registers because the critical bandwidth is narrower relative to the frequency difference

Based on: Plomp, R. & Levelt, W.J.M. (1965). “Tonal consonance and critical bandwidth.” Journal of the Acoustical Society of America, 38(4), 548-560.

Returns 0 for chords with fewer than 2 tones.

property beat_frequencies: list[tuple[Tone, Tone, float]]

Beat frequencies (Hz) between all pairs of tones in the chord.

When two tones with frequencies f1 and f2 are played together, their waveforms interfere and produce an amplitude modulation at the beat frequency: |f1 - f2| Hz.

Perceptual ranges:

  • < 1 Hz: very slow pulsing, used in tuning (e.g. tuning a guitar string against a reference — you hear the beats slow down as you approach the correct pitch)

  • 1–15 Hz: audible beating, perceived as a rhythmic pulse

  • 15–30 Hz: transition zone — too fast for individual beats, perceived as roughness/buzzing

  • > 30 Hz: no longer perceived as beating; becomes part of the perceived timbre or is heard as a difference tone

Returns a list of (tone_a, tone_b, beat_hz) tuples sorted by beat frequency ascending (slowest/most perceptible first).

Example:

>>> chord = Chord(tones=[A4, A4_slightly_sharp])
>>> chord.beat_frequencies
[(A4, A4+, 2.5)]  # 2.5 Hz beating — clearly audible

Returns an empty list for chords with fewer than 2 tones.

property beat_pulse: float

The slowest (most perceptible) beat frequency in the chord, in Hz.

This is the beat frequency between the two tones closest in pitch — the pair that produces the most audible amplitude modulation. In a well-tuned chord this value is typically 0 (unison pairs) or very large (distinct intervals); a non-zero value under ~15 Hz indicates perceptible beating that may suggest the chord is slightly out of tune.

Returns 0 for chords with fewer than 2 tones, or when all tones are identical (perfect unison).

identify() str | None[source]

Identify this chord by name (root + quality).

Tries each tone as a potential root and checks if the remaining intervals match a known chord pattern. Returns the name with the simplest match (fewest tones in the pattern preferred for ties).

Known patterns include major, minor, diminished, augmented, sus2, sus4, power chords, and all common 7th/9th chords.

Returns:

A string like "C major", "A minor 7th", or None if no known pattern matches.

Example:

>>> Chord([C4, E4, G4]).identify()
'C major'
>>> Chord([A4, C5, E5]).identify()
'A minor'
voice_leading(other: Chord) list[tuple[Tone, Tone, int]][source]

Find the smoothest voice leading to another chord.

Voice leading is the art of moving individual voices (tones) from one chord to the next with minimal motion. Good voice leading prefers stepwise motion (1-2 semitones) and contrary motion between voices.

This method finds the assignment of tones that minimizes the total semitone movement. For chords of different sizes, extra tones are held or dropped as needed.

Parameters:

other – The target Chord to voice-lead to.

Returns:

A list of (from_tone, to_tone, semitones) tuples describing how each voice moves. Sorted by voice (highest to lowest). semitones is signed: positive = up, negative = down.

Example:

>>> c_major = Chord([C4, E4, G4])
>>> f_major = Chord([C4, F4, A4])
>>> c_major.voice_leading(f_major)
[(<Tone G4>, <Tone A4>, 2),
 (<Tone E4>, <Tone F4>, 1),
 (<Tone C4>, <Tone C4>, 0)]
analyze(key_tonic: str | Tone, mode: str = 'major') str | None[source]

Roman numeral analysis of this chord relative to a key.

In tonal music, every chord has a function determined by its relationship to the key center. The Roman numeral system describes this: uppercase for major chords, lowercase for minor, with degree symbols for diminished.

Parameters:
  • key_tonic – The tonic note name (e.g. "C") or a Tone.

  • mode"major" or "minor" (default "major").

Returns:

A string like "I", "IV", "V7", "ii", "vi", or None if the chord doesn’t fit the key.

Example:

>>> Chord([C4, E4, G4]).analyze("C")
'I'
>>> Chord([G4, B4, D5]).analyze("C")
'V'
>>> Chord([D4, F4, A4]).analyze("C")
'ii'
property tension: dict

Harmonic tension score and resolution suggestions.

Tension in tonal music arises from specific intervallic content — primarily the tritone (6 semitones), the most unstable interval in Western harmony. The dominant 7th chord (e.g. G7 = G-B-D-F) contains a tritone between B and F, which “wants” to resolve: B pulls up to C, F pulls down to E.

This property analyzes:

  • Tritone count: each tritone adds significant tension

  • Minor 2nd count: semitone clashes add dissonance

  • Dominant function: the combination of major 3rd + minor 7th is the strongest tendency tone pattern in Western music

Returns:

  • score (float): 0.0 = fully resolved, 1.0 = max tension

  • tritones (int): number of tritone intervals

  • minor_seconds (int): number of semitone clashes

  • has_dominant_function (bool): contains the 3-7 tritone

Return type:

A dict with

Example:

>>> g7 = Chord([G4, B4, D5, F5])
>>> g7.tension['has_dominant_function']
True
>>> g7.tension['tritones']
1
add_tone(tone) Chord[source]

Return a new Chord with an additional tone.

Example:

>>> c_major = Chord.from_tones("C", "E", "G")
>>> c_major.add_tone(Tone.from_string("B4", system="western"))
<Chord C major 7th>
remove_tone(tone_name: str) Chord[source]

Return a new Chord with tones of the given name removed.

Parameters:

tone_name – The note name to remove (e.g. “G”).

Example:

>>> cmaj7 = Chord.from_name("Cmaj7")
>>> cmaj7.remove_tone("B")   # Remove the 7th
<Chord C major>
fingering(*positions: int) Chord[source]

Apply fret positions to each tone, returning a new Chord.

Each position value is added (in semitones) to the corresponding tone. The number of positions must match the number of tones.

Parameters:

*positions – One integer per tone indicating the fret offset.

Returns:

A new Chord with each tone shifted by its position.

Raises:

ValueError – If the number of positions doesn’t match the number of tones.

class pytheory.chords.Fretboard(*, tones: list[Tone])[source]

Bases: object

__init__(*, tones: list[Tone]) None[source]

Initialize a Fretboard from a list of open-string Tone objects.

Parameters:

tones – A list of Tone instances representing the open strings (high to low).

__repr__() str[source]

Return repr(self).

capo(fret: int) Fretboard[source]

Return a new Fretboard with a capo at the given fret.

A capo clamps across all strings at a fret, raising every string’s pitch by that many semitones. This lets you play open chord shapes in higher keys.

Common uses:

  • Capo 2 + G shapes = A major voicings

  • Capo 4 + C shapes = E major voicings

  • Capo 7 + D shapes = A major voicings (bright, high register)

Example:

>>> fb = Fretboard.guitar(capo=2)
>>> # Open strings are now F#4 C#4 A3 E3 B2 F#2
>>> # Playing a "G shape" sounds as A major
Parameters:

fret – The fret number to place the capo (1-12).

Returns:

A new Fretboard with all strings raised by fret semitones.

__iter__() Iterator[Tone][source]

Iterate over the open-string tones of this fretboard.

__len__() int[source]

Return the number of strings on this fretboard.

INSTRUMENTS = ['guitar', 'twelve_string', 'bass', 'ukulele', 'mandolin', 'mandola', 'octave_mandolin', 'mandocello', 'violin', 'viola', 'cello', 'double_bass', 'banjo', 'harp', 'pedal_steel', 'keyboard', 'bouzouki', 'oud', 'sitar', 'shamisen', 'erhu', 'charango', 'pipa', 'balalaika', 'lute']

List of all available instrument preset names.

TUNINGS = {'dadgad': ('D4', 'A3', 'G3', 'D3', 'A2', 'D2'), 'drop d': ('E4', 'B3', 'G3', 'D3', 'A2', 'D2'), 'half step down': ('D#4', 'A#3', 'F#3', 'C#3', 'G#2', 'D#2'), 'open a': ('E4', 'C#4', 'A3', 'E3', 'A2', 'E2'), 'open d': ('D4', 'A3', 'F#3', 'D3', 'A2', 'D2'), 'open e': ('E4', 'B3', 'G#3', 'E3', 'B2', 'E2'), 'open g': ('D4', 'B3', 'G3', 'D3', 'G2', 'D2'), 'standard': ('E4', 'B3', 'G3', 'D3', 'A2', 'E2')}
classmethod guitar(tuning: str | tuple[str, ...] = 'standard', capo: int = 0) Fretboard[source]

Guitar with the given tuning and optional capo.

Parameters:
  • tuning – Tuning name or tuple of tone strings (high to low). Built-in tunings: standard, drop d, open g, open d, open e, open a, dadgad, half step down.

  • capo – Fret number for the capo (0 = no capo). Raises all strings by this many semitones.

classmethod bass(five_string: bool = False) Fretboard[source]

Standard bass guitar tuning.

Parameters:

five_string – If True, adds a low B string (B0).

classmethod ukulele() Fretboard[source]

Standard ukulele tuning (A4 E4 C4 G4).

Re-entrant tuning: the G4 string is higher than C4.

classmethod mandolin() Fretboard[source]

Standard mandolin tuning (E5 A4 D4 G3).

Tuned in fifths, same as a violin but one octave relationship. Strings are typically doubled (paired courses).

classmethod mandola() Fretboard[source]

Standard mandola tuning (A4 D4 G3 C3).

The mandola (or tenor mandola) is to the mandolin what the viola is to the violin — a fifth lower, with a warmer, darker tone. Tuned in fifths like all the mandolin family.

classmethod octave_mandolin() Fretboard[source]

Octave mandolin tuning (E4 A3 D3 G2).

Also called the octave mandola in European terminology. One octave below the mandolin — same tuning as the violin family’s cello-to-violin relationship. Popular in Irish and Celtic folk music.

classmethod mandocello() Fretboard[source]

Mandocello tuning (A3 D3 G2 C2).

The bass of the mandolin family. Tuned like a cello — an octave below the mandola. Rare but beautiful; used in mandolin orchestras.

classmethod violin() Fretboard[source]

Standard violin tuning (E5 A4 D4 G3).

Tuned in perfect fifths. The violin has no frets — intonation is continuous, allowing vibrato and microtonal inflections not possible on fretted instruments.

classmethod viola() Fretboard[source]

Standard viola tuning (A4 D4 G3 C3).

A perfect fifth below the violin. The viola’s darker, warmer tone comes from its larger body and lower register.

classmethod cello() Fretboard[source]

Standard cello tuning (A3 D3 G2 C2).

An octave below the viola. Tuned in fifths. The cello spans the range of the human voice — tenor through bass.

classmethod banjo(tuning: str | tuple[str, ...] = 'open g') Fretboard[source]

Banjo with the given tuning.

Parameters:

tuning"open g" (default, bluegrass) or "open d" (old-time, clawhammer). The 5th string is a high drone — a defining feature of the banjo sound.

Standard open G: G4 D3 G3 B3 D4 (5th string is the short high G4 drone).

classmethod double_bass() Fretboard[source]

Standard double bass (upright bass) tuning (G2 D2 A1 E1).

The largest and lowest-pitched bowed string instrument in the orchestra. Unlike the rest of the string family, the double bass is tuned in fourths (like a bass guitar) rather than fifths.

The 5-string double bass adds a low B0 or C1.

classmethod harp() Fretboard[source]

Concert harp strings — 47 strings spanning C1 to G7.

The pedal harp has 7 strings per octave (one per note name), tuned to Cb major. Pedals alter each note name by up to two semitones across all octaves simultaneously.

This returns the full set of 47 strings in the default Cb (enharmonic B) tuning.

classmethod pedal_steel() Fretboard[source]

Pedal steel guitar — E9 Nashville tuning (10 strings).

The standard tuning for country music. The pedal steel has foot pedals and knee levers that change string pitches during play, enabling its signature swooping, crying sound.

classmethod bouzouki(variant: str | tuple[str, ...] = 'irish') Fretboard[source]

Bouzouki tuning.

Parameters:

variant"irish" (default, GDAD) or "greek" (CFAD).

The Irish bouzouki is a staple of Celtic music, usually tuned in unison or octave pairs. The Greek bouzouki traditionally has 3 or 4 courses and a brighter, more metallic sound.

classmethod oud() Fretboard[source]

Standard Arabic oud tuning (C4 G3 D3 A2 G2 C2).

The oud is the ancestor of the European lute and the defining instrument of Arabic, Turkish, and Persian classical music. It is fretless, allowing the quarter-tone inflections essential to maqam performance. 6 courses (11 strings), typically tuned in fourths.

classmethod sitar() Fretboard[source]

Sitar main playing strings (approximation).

The sitar typically has 6-7 main strings and 11-13 sympathetic strings (taraf). This models the main playing strings in a common tuning. The actual tuning varies by raga and tradition.

Main strings: Sa Sa Pa Sa Re Sa Ma (approximated in 12-TET). Represented here as the most common Ravi Shankar school tuning.

classmethod shamisen() Fretboard[source]

Standard shamisen tuning — honchoshi (C4 G3 C3).

The shamisen is a 3-stringed Japanese instrument played with a large plectrum (bachi). Three standard tunings:

  • honchoshi (本調子): root-5th-root

  • niagari (二上り): root-5th-2nd (raises 2nd string)

  • sansagari (三下り): root-5th-b7th (lowers 3rd string)

classmethod erhu() Fretboard[source]

Standard erhu tuning (A4 D4).

The erhu is a 2-stringed Chinese bowed instrument with a hauntingly vocal quality. Tuned a fifth apart. No fingerboard — the player presses the strings without touching the neck, allowing continuous pitch bending.

classmethod charango() Fretboard[source]

Standard charango tuning (E5 A4 E5 C5 G4).

A small Andean stringed instrument, traditionally made from an armadillo shell. 5 doubled courses with re-entrant tuning — the 3rd course (E5) is the highest pitched, creating the charango’s bright, sparkling sound.

classmethod pipa() Fretboard[source]

Standard pipa tuning (D4 A3 E3 A2).

The pipa is a 4-stringed Chinese lute with a pear-shaped body, dating back over 2000 years. Known for its percussive attack and rapid tremolo technique.

classmethod balalaika() Fretboard[source]

Standard balalaika prima tuning (A4 E4 E4).

The Russian balalaika has a distinctive triangular body and 3 strings. The two lower strings are tuned in unison — a unique feature that gives it a natural chorus effect.

classmethod keyboard(keys: int = 88, start: str = 'A0') Fretboard[source]

Piano or keyboard with the given number of keys.

Parameters:
  • keys – Number of keys (default 88 for a full piano). Common sizes: 25, 37, 49, 61, 76, 88.

  • start – The lowest note (default "A0" for standard piano).

A full 88-key piano spans A0 (27.5 Hz) to C8 (4186 Hz) — the widest range of any standard acoustic instrument. Smaller MIDI controllers typically start at C.

Examples:

Fretboard.keyboard()            # 88-key piano
Fretboard.keyboard(61, "C2")    # 61-key controller
Fretboard.keyboard(25, "C3")    # 25-key mini controller
classmethod lute() Fretboard[source]

Renaissance lute in G tuning (6 courses).

The European lute was the dominant instrument of the Renaissance (15th-17th century). Tuned in fourths with a major third between the 3rd and 4th courses — the same intervallic pattern as a modern guitar.

classmethod twelve_string() Fretboard[source]

12-string guitar in standard tuning.

The lower 4 courses are doubled at the octave; the upper 2 are doubled in unison. This creates the characteristic shimmering, chorus-like sound.

Represented as 12 strings (high to low, pairs together).

scale_diagram(scale, frets: int = 12) str[source]

Render an ASCII diagram showing where scale notes fall on the neck.

Each string is shown with dots on frets where scale notes appear. Useful for learning scale patterns on guitar, mandolin, etc.

Parameters:
  • scale – A Scale object (or anything with a note_names attribute).

  • frets – Number of frets to display (default 12).

Returns:

A multi-line string showing the fretboard diagram.

Example:

>>> from pytheory import Fretboard, TonedScale
>>> fb = Fretboard.guitar()
>>> pentatonic = TonedScale(tonic="A4")["minor"]
>>> print(fb.scale_diagram(pentatonic, frets=5))
fingering(*positions: int) Chord[source]

Apply fret positions to each string, returning a Chord.

Each position value is added (in semitones) to the corresponding open-string tone. The number of positions must match the number of strings.

Parameters:

*positions – One integer per string indicating the fret number.

Returns:

A Chord with each tone shifted by its fret position.

Raises:

ValueError – If the number of positions doesn’t match the number of strings.

pytheory.chords.analyze_progression(chords: list[Chord], key: str = 'C', mode: str = 'major') list[str | None][source]

Analyze a list of chords and return their Roman numeral functions.

Example:

>>> chords = [Chord.from_name("C"), Chord.from_name("Am"), Chord.from_name("F"), Chord.from_name("G")]
>>> analyze_progression(chords, key="C")
['I', 'vi', 'IV', 'V']