kennethreitz fde1011194 Expand test suite to 178 tests and fix additional bugs
- Add pytest as dev dependency in pyproject.toml
- Fix sawtooth_wave: numpy.linspace requires int for num parameter
- Fix Scale.degree() lookup by name ("tonic", "dominant") was broken
- Add tests for: Tone.from_tuple, from_index, _index, error paths,
  multi-octave arithmetic, descending chromatic walk, all pitch frequencies,
  Pythagorean temperament, all scale degrees by Roman numeral and name,
  Scale repr/slice/degrees mismatch, TonedScale repr/get/with-Tone-object,
  D/F/A/E/B major/minor scales, D Dorian, G Mixolydian, octave boundary
  crossing, all mode intervals including Phrygian/Aeolian/Locrian/Ionian,
  chord intervals/beat_pulse/empty chord, Chord/Fretboard fingering errors,
  all NamedChord qualities (m6/m9/maj9/9), fix_fingering, flat-to-sharp
  conversion, charts total count, charts_for_fretboard, all wave generators,
  wave output types, Synth with real pitches, circle of fifths/fourths,
  relative minor equivalence, enharmonic equivalence in scales, I-IV-V
  progression integration test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 05:39:12 -04:00
2018-09-02 04:13:48 -04:00

PyTheory: Music Theory for Humans

This (work in progress) library attempts to make exploring music theory approachable to humans.

logo

True Scale -> Pitch Evaluation

>>> from pytheory import TonedScale

>>> c_minor = TonedScale(tonic='C4')['minor']

>>> c_minor
<Scale I=C4 II=D4 III=Eb4 IV=F4 V=G4 VI=Ab4 VII=Bb5 VIII=C5>

>>> c_minor[0].pitch()
523.251130601197

>>> c_minor["I"].pitch(symbolic=True)
440*2**(1/4)

>>> c_minor["tonic"].pitch(temperament='pythagorean', symbolic=True)
14080/27

Audibly play a note (or chord)

>>> from pytheory import play
play(c_minor[0], t=1_000)

Chord Fingerings for Custom Tunings

>>> from pytheory import Tone, Fretboard, CHARTS

>>> tones = (
...     Tone.from_string("F2"),
...     Tone.from_string("C3"),
...     Tone.from_string("G3"),
...     Tone.from_string("D4"),
...     Tone.from_string("A5"),
...     Tone.from_string("E5")
... )

>>> fretboard = Fretboard(tones=tones)
>>>
>>> c_chord = CHARTS['western']["C"]

>>> print(c_chord.fingering(fretboard=fretboard))
(0, 0, 0, 3, 3, 3)

It can also generate charts for all known chords for any instrument (accuracy to be determined!).

🍰

S
Description
Languages
Python 100%