# pretty_midi: MIDI files as objects you can edit in Python

> pretty_midi turns a MIDI file into a tree of instruments and notes that a Python program can inspect, modify and write back out, with helpers for tempo estimation, chroma analysis and note name conversion. Synthesis is optional and depends on fluidsynth, and the package ships with the soundfont it needs.

**craffel/pretty-midi** — Utility functions for handling MIDI data in a nice/intuitive way.

- Repository: https://github.com/craffel/pretty-midi
- Stars: 1,049 · Forks: 173
- Language: Jupyter Notebook
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/craffel-pretty-midi

## A file becomes a tree of instruments and notes

The premise of pretty_midi is that MIDI data is awkward in its raw form and pleasant once it is structured. The package is described as utility functions and classes for handling MIDI data so that it is in a format which is easy to modify and extract information from, and the object model does that in three layers. A PrettyMIDI object is the file, it holds a list of Instrument objects, and each Instrument holds a list of Note objects with a pitch, a start time, an end time and a velocity.

The difference shows up immediately in code. Raising a drum pattern by five semitones is four lines with the object model, because each note is an attribute you can set, and the drum track can be skipped with a check on the instrument's is_drum flag. Working on the same file through a list of raw events means matching note-on and note-off pairs yourself.

There is a second, quieter benefit. Because notes are values in a list rather than rows in a file, a transformation is a function you can write and test, and a MIDI file becomes an intermediate representation inside a larger pipeline rather than the only thing your program knows how to read.

## Tempo estimation and chroma analysis in a few lines

The README's analysis example opens by loading a file and asking for an empirical estimate of its global tempo:

```python
import pretty_midi
# Load MIDI file into PrettyMIDI object
midi_data = pretty_midi.PrettyMIDI('example.mid')
# Print an empirical estimate of its global tempo
print(midi_data.estimate_tempo())
# Compute the relative amount of each semitone across the entire song, a proxy for key
total_velocity = sum(sum(midi_data.get_chroma()))
print([sum(semitone)/total_velocity for semitone in midi_data.get_chroma()])
```

The chroma call is the interesting one. It returns, per semitone, the accumulated velocity across the whole file, and dividing by the total gives the relative weight of each pitch class, which the comment describes as a proxy for key. That is a genuinely useful analysis in two lines, and it is the kind of thing the library is for.

The mutation half of the same example shows the object model at work, and the drum check matters because a drum track transposed by five semitones is nonsense:

```python
for instrument in midi_data.instruments:
    # Don't want to shift drum notes
    if not instrument.is_drum:
        for note in instrument.notes:
            note.pitch += 5
# Synthesize the resulting MIDI data using sine waves
audio_data = midi_data.synthesize()
```

## Building a file from note names, programs and velocities

The creation example starts from an empty PrettyMIDI object and adds a single instrument, and the convenience functions do the tedious translation work. instrument_name_to_program takes a name such as Cello and returns the General MIDI program number, note_name_to_number converts a name like C5 into a MIDI note number, and the Note constructor takes velocity, pitch, start and end.

```python
import pretty_midi
# Create a PrettyMIDI object
cello_c_chord = pretty_midi.PrettyMIDI()
# Create an Instrument instance for a cello instrument
cello_program = pretty_midi.instrument_name_to_program('Cello')
cello = pretty_midi.Instrument(program=cello_program)
```

The notes are then appended to the instrument, the instrument to the file, and the file written out:

```python
cello.notes.append(note)
cello_c_chord.instruments.append(cello)
# Write out the MIDI data
cello_c_chord.write('cello-C-chord.mid')
```

The note construction itself reads like a description of the music:

```python
note = pretty_midi.Note(velocity=100, pitch=note_number, start=0, end=.5)
```

A quarter second of a note at velocity 100, starting at time zero. Building a file this way is a very different experience from assembling one with a low-level MIDI writer, and it is the reason many people reach for this library in the first place.

## Synthesis is optional, and the soundfont travels with the package

The synthesize method is what turns the object model into audio, and it is the part with an external requirement. The README states that to synthesize MIDI data using fluidsynth you need the fluidsynth program and the pyfluidsynth package, and setup.py declares that as an optional extra:

```python
extras_require={
    'fluidsynth': ['pyfluidsynth>=1.3.1',],
}
```

So the base install is numpy, mido, six and importlib_resources, and only the audio path pulls in the synthesizer. The example in the README synthesizes with sine waves, which is the simplest possible timbre and is enough to hear that the notes are right.

One detail is easy to miss and saves a download. The package data includes TimGM6mb.sf2, a General MIDI soundfont, so the instrument sounds do not need to be fetched from somewhere else. The size of that file is part of the wheel you install, which is the trade for having a working timbres set out of the box.

The underlying MIDI parsing is done by mido, which pretty_midi requires at version 1.1.16 or newer. In other words the heavy lifting of the file format belongs to mido, and pretty_midi is the layer that makes the resulting data pleasant to work with.

## The examples folder shows four directions the library is used in

Four example scripts sit in examples/, and their names tell you the range of things people do with MIDI data. align_midi.py is about aligning files to each other, which is the problem of deciding where one recording should start relative to another. chiptunes.py is about the 8-bit style, where a small set of square-wave channels carry the whole piece, and writing such music needs a different relationship between pitch and waveform than a sampled instrument.

chord_catalog.py builds a catalog of chords, and reverse_pianoroll.py works with the piano roll representation, the grid of pitch against time that is the usual way to look at a performance and the natural way to feed a machine learning model. Together they cover alignment, synthesis in a constrained style, theory and analysis.

The repository also ships example.mid at the root, which is the file the README's own examples load, and a Tutorial.ipynb that is linked both on nbviewer and as a Colab notebook, so a reader can work through the library with nothing installed locally. The docs/ directory holds the generated API documentation that is also published at craffel.github.io/pretty-midi, and the tests/ directory holds the test suite.

## Where pretty_midi is the wrong tool

The first wrong-tool case is real-time audio. The library is built around files, loading a file, editing objects and writing or synthesizing the result, and the synth path is a batch operation on the whole object. Anything that has to decode a stream, react to a live performer or run inside an audio callback wants a different architecture entirely.

The second is a project that needs a maintained library. The setup.py classifiers declare Development Status 3 - Alpha, and the version numbering has stayed in the 0.2 series, with 0.2.11 published in October 2025, 0.2.10 in March 2023 and 0.2.9 in April 2020. The last push was on 2026-10-06, so the code still moves, but the releases are irregular and the alpha label has never been lifted. For research code that is fine. For a product with a support obligation, it is a risk you have to accept deliberately.

The third is a case where the analysis, rather than the representation, is the hard part. pretty_midi gives you tempo estimation and chroma, which are answers to specific questions. If your task is key detection, beat tracking, chord recognition or transcription from audio, this library parses MIDI rather than analysing sound, and it will not get you there.

## MIT licensing and a request to cite the paper

The project is MIT licensed, with LICENSE.txt at the repository root and the licence declared again in the package metadata. The classifiers list the OSI approved MIT license and the intended audience as developers, with the topic under sound and audio MIDI.

There is one request in the README that deserves attention because it is easy to miss. If you use pretty_midi in a published research project, the README asks you to cite a specific report: Colin Raffel and Daniel P. W. Ellis, Intuitive Analysis, Creation and Manipulation of MIDI Data with pretty_midi, from the Proceedings of the 15th International Conference on Music Information Retrieval Late Breaking and Demo Papers, 2014. A citation request is not a licence condition, and MIT requires only that the copyright notice be kept, but in a research context a citation is how the work gets credited, and the author is asking for it directly.

The library is a good example of a permissive licence on a piece of research code that has become infrastructure. MIT lets you use it in a commercial product as long as you keep the copyright and licence notice, which is why it shows up in pipelines, and the package is installed from PyPI with pip, with setup.py retained for source installs.

## Conclusion

Adopt pretty_midi if you are doing research or prototyping on MIDI data, where the object model saves you from working with raw event lists, and if you can live with the alpha status the package declares. Do not adopt it for a real-time audio pipeline, for anything that needs a maintained guarantee of behaviour, or as a production dependency without pinning a version, since the project is still marked Development Status 3 - Alpha. Before you rely on it, install the package with pip, add the fluidsynth extra only if you need audio rather than MIDI data, and cite the ISMIR 2014 paper if your work is published, as the README requests.

## FAQ

### How do I install pretty_midi?

Install it from PyPI with pip, or use the setup.py script for a source install. The base install pulls in numpy, mido, six and importlib_resources.

### What do I need to synthesize audio with pretty_midi?

The fluidsynth program and the pyfluidsynth package, which setup.py exposes as an optional extra named fluidsynth. The General MIDI soundfont TimGM6mb.sf2 ships with the package, so no separate soundfont download is needed.

### How do I transpose notes in a MIDI file with pretty_midi?

Iterate over midi_data.instruments, skip the ones where instrument.is_drum is true, and add to note.pitch for each note in instrument.notes. The README example shifts every non-drum note up by five semitones.

### What license is pretty_midi released under?

MIT, with LICENSE.txt at the repository root and the licence declared in the package metadata. The README separately asks that published research projects cite the ISMIR 2014 paper by Colin Raffel and Daniel P. W. Ellis.

### Is pretty_midi suitable for real-time MIDI processing?

The package is built around files, with methods to load, modify, write and synthesize a whole MIDI object, and the classifiers declare Development Status 3 - Alpha. It is aimed at analysis and batch work over files rather than live event streams.

## Sources

- [craffel/pretty-midi on GitHub](https://github.com/craffel/pretty-midi)
- [Issues](https://github.com/craffel/pretty-midi/issues)
- [License: MIT](https://github.com/craffel/pretty-midi/blob/main/LICENSE)
- [README](https://github.com/craffel/pretty-midi/blob/main/README.md)
- [Releases](https://github.com/craffel/pretty-midi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/craffel-pretty-midi
