Model or dataset
kennethreitz/pytheory avatar
kennethreitz/pytheory

PyTheory: Python Music Theory, MIDI Composition, and Playback

Music Theory for Humans.

1,660 stars84 forksPythonMIT

At a glance

What is it?
PyTheory is an MIT-licensed Python package for music theory, score generation, instrument diagrams, MIDI export, and immediate audio playback. It suits programmers who want musical structures expressed as code, although its alpha status and limited platform documentation make deployment details worth checking first.
Who is it for?
Python developers, music educators, and experimenters should adopt PyTheory when code-driven theory calculations, arrangement, playback, and MIDI export fit their workflow. Users who need a mature graphical DAW, documented cross-platform audio support, or stable production APIs should look elsewhere first.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

PyTheory for Code-Driven Music Workflows

PyTheory addresses a practical gap between music notation software and conventional programming. A digital audio workstation is well suited to adjusting a mix or editing a recorded performance by hand, but expressing a repeating progression, selecting a scale, or generating an accompaniment can require repeated mouse operations. PyTheory turns those musical operations into Python calls. The intended users are developers, music educators, and experimenters who prefer code for musical sketches.

The package covers several related tasks rather than a single feature. Its `Key`, `Chord`, and `Tone` classes calculate keys, chord identities, progressions, intervals, and pivot chords. `Score` objects combine parts, drum patterns, sections, automation, and playback settings. `Fretboard` generates fingering, chord, tab, and scale material for guitar and other stringed instruments. The CLI exposes much of the same scope through commands such as `pytheory key`, `pytheory progression`, and `pytheory identify`.

This makes PyTheory useful for two different workflows. One is algorithmic composition, where note selection and arrangement can be driven by Python logic. Another is practical score preparation, where a developer wants theory results or a MIDI draft without assembling the musical model from low-level events. The README also presents a browser playground and documentation, but the package itself remains the center of this review.

The package declares Python 3.10 and newer as its requirement. Its listed classifiers cover Python 3.10 through 3.13. That range makes it reasonably current for a Python audio project, although the project is classified as `Development Status :: 3 - Alpha`, so it should be treated as software whose interfaces may still change.

How PyTheory Builds Scores from Musical Objects

The central composition model is `Score`. A score has a time signature and tempo, such as `"4/4"` and `bpm=140`. It creates named parts, and each part receives a synthesizer, envelope, and optional processing controls. Notes and chords are then added to those parts. This separation lets one score contain several musical roles, such as a bass line, chord bed, lead, or percussion pattern.

The data path is visible in the README example. `Score` creates drum material with a named pattern and repeat count. Separate calls to `score.part()` create instrument voices. Chord symbols are parsed through `Chord.from_symbol()`, while note names such as `"A2"` are accepted by the bass part. Durations come from `Duration`, including named values such as `Duration.WHOLE` and `Duration.QUARTER`. The same assembled `Score` can be sent through `play_score(score)` for playback or `score.save_midi("sketch.mid")` for transfer to a DAW.

Theory queries follow a smaller, more direct path. `Key("G", "major").progression("I", "V", "vi", "IV")` returns chord symbols, while `Chord.from_symbol("F#m7b5").identify()` returns a descriptive chord name. `Tone.from_string()` converts textual note names into tone objects that can be compared by interval. `Scale.recommend()` searches supplied pitch material and returns ranked scale suggestions.

Composition adds timing and automation above those primitives. Sections can be named, parameters can change during a score, and LFO modulation can alter a parameter over a defined number of bars. This is a more expressive model than a single chord calculator. It also means that a composition is not merely a list of names: it includes performance controls and arrangement structure that the playback and MIDI export layers can interpret.

Installing PyTheory and Generating a First Score

The README gives a PyPI installation command. PyTheory requires Python 3.10 or later according to `pyproject.toml`, so an older interpreter should be upgraded before installation. The package declares `sounddevice`, `scipy`, and `rich` as runtime dependencies. The documentation does not specify Linux audio packages, macOS permissions, or browser requirements, so the first check should be whether the local environment exposes a usable audio output device.

Install the package with the command documented by the project:

bash
pip install pytheory

After installation, the README presents a generated demo as the shortest path to hearing the package:

bash
pytheory demo

For a first real composition, create a score with a tempo, a drum pattern, and three parts. This example follows the documented composition shape. It creates a bossa nova pattern, assigns chord, lead, and bass parts, adds chord and bass material, and finishes with playback and MIDI export.

python
from pytheory import Score, Chord, Duration
from pytheory.play import play_score

score = Score("4/4", bpm=140)
score.drums("bossa nova", repeats=4)

chords = score.part("chords", synth="fm", envelope="pad", reverb=0.4)
lead = score.part("lead", synth="saw", envelope="pluck", delay=0.3, lowpass=3000)
bass = score.part("bass", synth="sine", lowpass=500)

for sym in ["Am", "Dm", "E7", "Am"]:
    chords.add(Chord.from_symbol(sym), Duration.WHOLE)

lead.arpeggio("Am", bars=2, pattern="updown", octaves=2)
lead.arpeggio("Dm", bars=2, pattern="updown", octaves=2)
for n in ["A2", "E2", "A2", "C3"]:
    bass.add(n, Duration.QUARTER)

play_score(score)
score.save_midi("sketch.mid")

The full README example adds further lead phrases and repeated bass notes, so readers should treat this shorter snippet as a starting structure rather than a complete arrangement. The CLI also exposes a quick theory check without creating a score:

bash
pytheory identify Cmaj7
pytheory progression C major I V vi IV

Playback, MIDI, and Parameter Control

PyTheory's practical distinction from a theory calculator is that a score can be heard and exported. `play_score(score)` invokes the playback layer, while `save_midi()` writes a `.mid` file for a DAW. The README does not document the exact audio backend selection, sample-rate behavior, buffering policy, or whether every synthesis and effect is available on every operating system. Those omissions matter for a library intended to produce sound locally.

The package lists 56 synthesizer waveforms, including conventional oscillator shapes and modeled instruments. It also describes effects such as distortion, chorus, lowpass filtering, delay, reverb, and LFO modulation. Convolution reverb is available through seven listed impulse responses, including a cathedral, plate, spring, cave, and canyon. These are stated as PyTheory features, but the README does not provide signal measurements, supported-device matrices, or a method for comparing their output.

Parameter changes are part of the score model. A part can be created with initial effects, then altered later with `set()`. An LFO can vary a filter parameter over a stated number of bars. The composition example also uses section markers and repeats, which makes it possible to build a song-like arrangement without manually duplicating every part event.

Live MIDI input and Ableton Link synchronization are optional rather than part of the core installation. The project gives exact extra commands for them:

bash
pip install "pytheory[live]"
pip install "pytheory[link]"

Those extras add `python-rtmidi` and `LinkPython-extern`. The README does not state that they are required for ordinary playback, and it does not explain permissions, supported hardware, or setup for the browser studio and live synth commands. They should be installed only when the corresponding integration is required.

Instrument Diagrams and Multiple Musical Systems

The instrument side of PyTheory is built around `Fretboard`. The README documents guitar chord fingering, ASCII tablature, scale diagrams, and support for 24 other stringed instruments. Its example creates a guitar fretboard, prints a tab for an A minor chord, and requests a fingering for G. The result is text-oriented output, which fits a terminal or code notebook more naturally than a large graphical notation window.

The examples directory also includes dedicated files for chord charts, fretboard exploration, intervals, key detection, scale exploration, overtone series, progressions, and world scales. This layout suggests that the repository is intended as a reference and experimentation surface, not only as one executable command. It also includes a tutorial notebook and song-oriented examples.

PyTheory is not limited to Western major and minor scales. The README lists Western, Hindustani, Arabic Maqam, Japanese, Blues/Pentatonic, and Javanese Gamelan systems, with more than 40 scales. It also documents instrument presets for guitar, bass, ukulele, mandolin family, violin family, banjo, harp, oud, sitar, and erhu. The package topics include scales and SymPy, but the project metadata does not expose the internal mathematical implementation, so the repository layout is more reliable than assumptions about the algorithms.

That breadth has a cost. A single package now spans theory analysis, notation helpers, synthesis, percussion, effects, recording-oriented commands, and several non-Western systems. Users who only need chord identification may install more dependencies than they expected, while users working with a specific instrument may need to consult the examples to discover the accepted names and output formats.

PyTheory Compared with a DAW Workflow

The clearest documented alternative is a digital audio workstation, or DAW. The README explicitly contrasts the two approaches: a DAW is used for tweaking sounds, while PyTheory is intended for thinking about music through code. PyTheory can generate a score programmatically, play it immediately, and export MIDI for later work in a DAW. A DAW instead gives the user a graphical arrangement view and direct control over recorded or manually entered parts.

The difference is therefore not that one product can never do the other's job. The project itself describes PyTheory output as something to finish in a DAW, and many DAWs support MIDI editing. The difference is where the initial workflow begins. PyTheory is a better fit when the musical material should emerge from repetition, data, progression rules, or a Python program. A DAW is more natural when the composer needs immediate visual arranging, extensive editing controls, or a familiar timeline.

For example, the documented PyTheory workflow can add chord symbols, generate arpeggios, add bass notes, and save a MIDI file without a graphical arrangement interface. A DAW workflow would begin with a project window, tracks, clips, and a MIDI editor. PyTheory's advantage in this comparison is code reuse and algorithmic arrangement. Its limitation is that the README does not describe interchange workflows with project formats beyond MIDI, so a DAW-based production pipeline should verify that export before committing to it.

PyTheory is also the wrong tool when the required output is a finished recording with detailed human performance editing. Its MIDI and synthesis model supports sketches and generated arrangements, but the project documentation does not claim recording-editing features comparable to a full DAW. For a musician whose primary need is recording, editing, and mixing an existing performance, the code-first score model is not the primary benefit.

Release Activity, Upgrade Cost, and the MIT License

The repository is not archived. Its last push was on 2026-10-15, and the project has recent releases including v0.57.13 on 2026-07-07, v0.57.12 on 2026-06-30, and v0.57.11 on 2026-06-30. The release descriptions identify changes such as a real oud voice for Maqam playback, tempo validation fixes, and tempo-map import and legato synth fixes. Those are project-specific signs of continued change, not evidence that every API is stable.

The package is distributed under the MIT License. The repository includes a `LICENSE` file and the project metadata identifies the license as MIT. The README does not provide legal interpretation, so users who need to comply with attribution, notice, or dependency terms should inspect the license files themselves. The runtime dependencies also have their own licensing terms, which are separate from PyTheory's license.

The project is labeled alpha in `pyproject.toml`. That status matters when planning upgrades. A change in command names, score APIs, synth names, or audio behavior may affect code that depends on exact output. The repository includes a `CHANGELOG.md`, so users should inspect it before upgrading an existing project. The `uv.lock` file also indicates a reproducible dependency lock for development work, although the README does not describe a supported upgrade policy or migration procedure.

The package does not require the optional live or link extras for its basic theory, composition, playback, or MIDI features. Its core runtime dependency list is small enough to state explicitly, but audio hardware behavior remains undocumented. Before deployment, verify Python version, audio availability, and whether a DAW-based workflow depends on exact MIDI structure.

Editorial conclusion

Python developers, music educators, and experimenters should adopt PyTheory when code-driven theory calculations, arrangement, playback, and MIDI export fit their workflow. Users who need a mature graphical DAW, documented cross-platform audio support, or stable production APIs should look elsewhere first. Before adoption, verify Python 3.10 compatibility, local audio output, the exported MIDI in the target DAW, and any required `live` or `link` extras.

Frequently asked questions

What Python version does PyTheory require?

PyTheory requires Python 3.10 or later. Its project metadata lists support for Python 3.10, 3.11, 3.12, and 3.13.

How do I install and run PyTheory?

Install it with `pip install pytheory`, then run `pytheory demo` to hear a generated track. The project also provides commands such as `pytheory key`, `pytheory identify`, and `pytheory progression` for theory work.

Can PyTheory export music as MIDI?

Yes. A `Score` can be saved with `score.save_midi("sketch.mid")`. The README presents MIDI export as a way to open the result in a DAW.

Does PyTheory need extra packages for MIDI input or Ableton Link?

Those features are optional. Install `pip install "pytheory[live]"` for MIDI input through `python-rtmidi`, or `pip install "pytheory[link]"` for Ableton Link synchronization through `LinkPython-extern`.

Official sources

  1. kennethreitz/pytheory on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kennethreitz-pytheory.svg)](https://hysenlabs.com/projects/kennethreitz-pytheory)