Instruments and Fingerings

The Fretboard class models any stringed instrument and generates chord fingerings. PyTheory includes 25 instrument presets spanning Western, Asian, Middle Eastern, Latin American, and Russian traditions.

How It Works

Each fret on a stringed instrument raises the pitch by exactly one semitone. The open string is fret 0; fret 1 is one semitone up, and so on. Even fretless instruments (violin, oud, erhu) can be modeled this way — the “fret” positions are just semitone steps along the fingerboard.

Guitars

Standard guitar tuning:

String 6: E2  (lowest)
String 5: A2
String 4: D3
String 3: G3
String 2: B3
String 1: E4  (highest)

This tuning uses intervals of a perfect 4th (5 semitones) between most strings, except between G and B which is a major 3rd (4 semitones).

Note

Since v0.43.0, fingerings and string lists read low to high (lowest-pitched string first) by default — matching how chord diagrams and tab are conventionally written. To get the pre-0.43 high-to-low order, pass high_to_low=True to any fretboard constructor, e.g. Fretboard.guitar(high_to_low=True). A custom tuning tuple and manual fingering() positions are likewise read in the board’s orientation.

>>> from pytheory import Fretboard

>>> guitar  = Fretboard.guitar()                # Standard EADGBE
>>> twelve  = Fretboard.twelve_string()          # 12-string (6 doubled courses)
>>> bass    = Fretboard.bass()                  # Standard 4-string EADG
>>> bass5   = Fretboard.bass(five_string=True)  # 5-string with low B

Alternate tunings — 7 built-in presets (plus standard):

>>> Fretboard.guitar("drop d")          # DADGBE — heavy riffs, metal
>>> Fretboard.guitar("open g")          # DGDGBD — slide guitar, Keith Richards
>>> Fretboard.guitar("open d")          # DADF#AD — slide, folk
>>> Fretboard.guitar("open e")          # EBEG#BE — slide blues
>>> Fretboard.guitar("open a")          # EAEAC#E — slide
>>> Fretboard.guitar("dadgad")          # DADGAD — Celtic, fingerstyle
>>> Fretboard.guitar("half step down")  # Eb standard — Hendrix, SRV

>>> # Custom tuning with any notes
>>> Fretboard.guitar(("C4", "G3", "C3", "G2", "C2", "G1"))

Capo — a capo raises all strings by a number of frets, letting you play open chord shapes in higher keys:

>>> # Capo on fret 2 — open G shape now sounds as A major
>>> fb = Fretboard.guitar(capo=2)

>>> # Or apply a capo to an existing fretboard
>>> fb = Fretboard.guitar()
>>> fb_capo3 = fb.capo(3)

The Mandolin Family

The mandolin family mirrors the violin family — all tuned in perfect fifths, with each member a fifth or octave lower than the last:

>>> Fretboard.mandolin()          # E5 A4 D4 G3  — soprano (= violin)
>>> Fretboard.mandola()           # A4 D4 G3 C3  — alto (= viola)
>>> Fretboard.octave_mandolin()   # E4 A3 D3 G2  — tenor (octave below mandolin)
>>> Fretboard.mandocello()        # A3 D3 G2 C2  — bass (= cello)

The mandolin’s doubled courses (pairs of strings) create a natural chorus effect. The octave mandolin is popular in Irish and Celtic folk music.

The Bowed String Family

The orchestral string family is tuned in perfect fifths (except the double bass, which uses fourths):

>>> Fretboard.violin()       # E5 A4 D4 G3  — soprano
>>> Fretboard.viola()        # A4 D4 G3 C3  — alto (5th below violin)
>>> Fretboard.cello()        # A3 D3 G2 C2  — tenor/bass (octave below viola)
>>> Fretboard.double_bass()  # G2 D2 A1 E1  — bass (tuned in 4ths!)

Bowed strings have no frets — the player can produce any pitch along the fingerboard, enabling continuous vibrato and microtonal inflections not possible on fretted instruments.

The erhu — a 2-stringed Chinese bowed instrument with a hauntingly vocal quality:

>>> Fretboard.erhu()         # A4 D4  — tuned a 5th apart, no fingerboard

Plucked Strings

>>> Fretboard.ukulele()         # A4 E4 C4 G4  — re-entrant tuning
>>> Fretboard.banjo()           # open G (bluegrass) — 5th string is a high drone
>>> Fretboard.banjo("open d")   # open D (clawhammer, old-time)
>>> Fretboard.banjo("double c") # G C G C D (old-time)
>>> Fretboard.harp()            # 47 strings, C1 to G7 (concert pedal harp)

The banjo’s short 5th string is a high drone — a defining feature of the instrument’s sound.

The harp has one string per diatonic note across nearly 7 octaves. Pedals alter each note name by up to two semitones across all octaves simultaneously.

World Instruments

>>> # Middle Eastern
>>> Fretboard.oud()          # C4 G3 D3 A2 G2 C2 — fretless, ancestor of the lute
>>> Fretboard.sitar()        # 7 main strings — Indian classical

>>> # East Asian
>>> Fretboard.shamisen()     # C4 G3 C3 — 3-string Japanese, honchoshi tuning
>>> Fretboard.pipa()         # D4 A3 E3 A2 — 4-string Chinese lute
>>> Fretboard.erhu()         # A4 D4 — 2-string Chinese bowed

>>> # European
>>> Fretboard.bouzouki()     # D4 A3 D3 G2 — Irish (Celtic music)
>>> Fretboard.bouzouki("greek")  # D4 A3 F3 C3 — Greek
>>> Fretboard.lute()         # G4 D4 A3 F3 C3 G2 — Renaissance (6 courses)
>>> Fretboard.balalaika()    # A4 E4 E4 — Russian (2 unison strings)

>>> # Latin American
>>> Fretboard.charango()     # E5 A4 E5 C5 G4 — Andean (re-entrant tuning)

>>> # Steel guitar
>>> Fretboard.pedal_steel()  # 10 strings, E9 Nashville — country music

The oud is fretless, allowing the quarter-tone inflections essential to maqam performance. The sitar has moveable frets and sympathetic strings that resonate in harmony with the played notes.

Keyboards

>>> Fretboard.keyboard()             # 88-key piano (A0 to C8)
>>> Fretboard.keyboard(61, "C2")     # 61-key synth controller
>>> Fretboard.keyboard(49, "C2")     # 49-key controller
>>> Fretboard.keyboard(25, "C3")     # 25-key mini MIDI controller

While keyboards don’t have strings or frets, they map naturally to a sequence of tones. A full 88-key piano spans over 7 octaves — the widest range of any standard acoustic instrument.

Getting Fingerings

Common chords come from a library of curated voicings, so fb.chord("C") returns the open shape a guitarist actually plays. Anything not in that library — any symbol from_symbol() can parse, such as "F#m7b5" or "Csus2" — is voiced automatically: PyTheory searches the neck for its notes and scores each candidate hand position by

  1. Preferring open strings (fret 0) — they ring freely

  2. Preferring ascending fret patterns — easier hand position

  3. Minimizing the number of fingers needed

>>> from pytheory import Fretboard

>>> fb = Fretboard.guitar()
>>> f = fb.chord("C")
>>> f
Fingering(E=x, A=3, D=2, G=0, B=1, e=0)

>>> f["A"]            # index by string name
3
>>> f[1]              # ...or by position (low to high)
3

>>> f.identify()
'C major'

>>> chord = f.to_chord()
>>> chord.identify()
'C major'

Subscripting the fretboard itself is shorthand for chord():

>>> fb["G"]
Fingering(E=3, A=2, D=0, G=0, B=0, e=3)

Because uncharted symbols are voiced on the fly, you are not limited to the common chords — any symbol that parses gets a computed shape:

>>> fb.chord("F#m7b5")
Fingering(E=2, A=0, D=2, G=2, B=1, e=0)
>>> fb.chord("Csus2")
Fingering(E=x, A=3, D=0, G=0, B=3, e=3)
>>> fb.chord("Gadd9")
Fingering(E=3, A=0, D=0, G=0, B=0, e=3)
>>> fb.chord("Cdim7")
Fingering(E=8, A=0, D=7, G=8, B=7, e=8)

See Working with Chords for the chord vocabulary PyTheory understands.

You can also go from fret positions to chord identification:

>>> # "What chord am I playing?" (positions read low to high)
>>> fb = Fretboard.guitar()
>>> f = fb.fingering(0, 2, 2, 0, 0, 0)
>>> f
Fingering(E=0, A=2, D=2, G=0, B=0, e=0)
>>> f.identify()
'E minor'

Reading Fingerings

Each position is labeled with its string name. Duplicate string names are disambiguated — on a standard guitar, high E appears as e and low E as E. Strings read low to high (lowest first):

E|--x--    (muted — low E)
A|--3--    (fret 3 — C)
D|--2--    (fret 2 — E)
G|--0--    (open — G)
B|--1--    (fret 1 — C)
e|--0--    (open — high E)

A value of x (None) means the string is muted (not played).

ASCII Tablature

For a more visual representation, use tab(). Tablature follows the standard convention — the highest-pitched string (high e) is drawn on top and the low E on the bottom, regardless of the board’s data orientation:

>>> print(fb.tab("C"))
C major
e|--0--
B|--1--
G|--0--
D|--2--
A|--3--
E|--x--

Generating Full Charts

Generate fingerings for every chord at once:

>>> fb = Fretboard.guitar()
>>> chart = fb.chart()

>>> chart["C"]
Fingering(E=x, A=3, D=2, G=0, B=1, e=0)

>>> # Works with any instrument
>>> uke_chart = Fretboard.ukulele().chart()
>>> mando_chart = Fretboard.mandolin().chart()

Scale Diagrams with Chord Highlighting

The scale_diagram() method renders an ASCII fretboard showing where scale notes fall on each string:

>>> from pytheory import Fretboard, TonedScale, Chord

>>> fb = Fretboard.guitar()
>>> pentatonic = TonedScale(tonic="A4", system="blues")["minor pentatonic"]
>>> print(fb.scale_diagram(pentatonic, frets=5))
    0   1   2   3   4   5
E| E | - | - | G | - | A |
A| A | - | - | C | - | D |
D| D | - | E | - | - | G |
G| G | - | A | - | - | C |
B| - | C | - | D | - | E |
E| E | - | - | G | - | A |

Note

Pentatonic and blues scales live in the blues system, not the default western one — hence system="blues" above. See Working with Scales for the full catalogue.

Pass an optional chord argument to highlight chord tones in UPPERCASE while scale-only tones appear in lowercase — a quick way to see your target notes for soloing:

>>> am = Chord.from_symbol("Am")
>>> print(fb.scale_diagram(pentatonic, frets=5, chord=am))
    0   1   2   3   4   5
E| E | - | - | g | - | A |
A| A | - | - | C | - | d |
D| d | - | E | - | - | g |
G| g | - | A | - | - | C |
B| - | C | - | d | - | E |
E| E | - | - | g | - | A |

Scalable Diagrams (SVG and PNG)

ASCII tab is perfect in a terminal, but you can’t drop it into a video, a slide, or a worksheet. PyTheory renders the same fretboard data as clean, scalable SVG — no extra dependencies. For PNG, install the optional extra (pip install pytheory[diagrams], which pulls in cairosvg) and pass fmt="png" or a .png path.

Every diagram method returns the SVG markup as a string, or — when you give it a path — writes the file and returns the path.

Chord boxes

tab_image() is the graphical counterpart of tab(): a vertical chord box like the ones in songbooks, with open/muted markers, automatic barre detection, and the root highlighted in red.

>>> from pytheory import Fretboard

>>> fb = Fretboard.guitar()

>>> # Write a chord box to a file...
>>> fb.tab_image("Am", "Am.svg")
'Am.svg'

>>> # ...or get the SVG markup back as a string
>>> svg = fb.tab_image("Am")
>>> svg[:39]
'<svg xmlns="http://www.w3.org/2000/svg"'

A Fingering can render itself the same way with to_svg() — handy when you built the voicing by hand. The barre in an F major shape is detected automatically:

>>> fb.chord("F").to_svg(path="F.svg")
'F.svg'

Scale shapes

scale_shapes() splits a scale into the positional boxes a player moves between — for a pentatonic scale, the familiar five positions. Each is a ScaleShape you can render on its own:

>>> from pytheory import Fretboard, TonedScale

>>> fb = Fretboard.guitar()
>>> pentatonic = TonedScale(tonic="A4", system="blues")["minor pentatonic"]

>>> shapes = fb.scale_shapes(pentatonic)
>>> len(shapes)
5
>>> shapes[0]
<ScaleShape A pos 1 frets 0-3>

>>> shapes[0].to_svg(path="A_pent_pos1.svg")
'A_pent_pos1.svg'

scale_shape_image() is a shortcut for a single position (1-based):

>>> fb.scale_shape_image(pentatonic, 2, "A_pent_pos2.svg")
'A_pent_pos2.svg'

Arpeggio maps

arpeggio_diagram() maps every chord tone across the whole neck, labelled by its role (R, 3, 5, 7…) with roots in red — for practising where a chord’s notes live. The chord can be a Chord or just a symbol string:

>>> Fretboard.guitar().arpeggio_diagram("Am", "Am_arp.svg")
'Am_arp.svg'

Non-String Instruments

Looking for drums and percussion? PyTheory also supports drum pattern programming through the sequencing engine. See the Drums guide for drum kits, patterns, and fills.

Custom Instruments

Any instrument can be modeled with custom string tunings:

>>> from pytheory import Tone, Fretboard

>>> # Baritone ukulele (DGBE — top 4 guitar strings, low to high)
>>> bari_uke = Fretboard(tones=[
...     Tone.from_string("D3"),
...     Tone.from_string("G3"),
...     Tone.from_string("B3"),
...     Tone.from_string("E4"),
... ])

>>> # Tres cubano (Cuban guitar, 3 doubled courses, low to high)
>>> tres = Fretboard(tones=[
...     Tone.from_string("G3"),
...     Tone.from_string("B3"),
...     Tone.from_string("E4"),
... ])

If it has strings, you can model it. Define the tuning, and PyTheory handles the rest – fingerings, charts, scale diagrams, all of it. Got a weird instrument or a custom tuning? That’s what the Fretboard constructor is for.