rust-music-theory: notes, scales and chords as Rust values
A music theory guide written in Rust.
At a glance
- What is it?
- rust-music-theory is a Rust library and executable for using music theory programmatically, with Note, Pitch, Scale, Chord and Interval types, a lead-sheet chord symbol parser added in 0.5, seven rotations of the harmonic and melodic minor families, and optional MIDI export and real-time playback. The version numbers are slightly ahead of the published release.
- Who is it for?
- Adopt rust-music-theory if you are writing a generator, sequencer or analysis tool in Rust and want pitch spelling, scale membership and chord voicings to be typed values rather than MIDI numbers you compute by hand, and if you want to hand the result to a hardware or software synthesizer.
- 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 104 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Pitch is a value, not a MIDI number
rust-music-theory is a library and an executable that provides a programmatic implementation of the basis of music theory. The stated purpose is to let music theory notions like Note, Chord, Scale and Interval be used in other programs to produce music and audio in a programmatic way.
The design decision that makes the library worth using is that pitch is a typed value rather than a number. A Note is built from a pitch and an octave, and the pitch carries a letter and an accidental, so the library knows that a note is spelled a certain way rather than merely how many semitones it sits at. That distinction is the difference between C sharp and D flat, and it is the distinction that a library generating scales and chords has to get right.
The core usage is short. You add the crate to your Cargo.toml:
[dependencies]
rust-music-theory = "0.5"And then build the objects you need, with a scale taking a type, a tonic, an octave, a mode and a direction:
extern crate rust_music_theory as rustmt;
use rustmt::note::{Note, Notes, Pitch, PitchSymbol::*};
use rustmt::scale::{Scale, ScaleType, Mode, Direction};
use rustmt::chord::{Chord, Number as ChordNumber, Quality as ChordQuality};
// to create a Note, specify a pitch and an octave;
let note = Note::new(Pitch::from(As), 4);
// Scale Example;
let scale = Scale::new(
ScaleType::Diatonic, // scale type
Pitch::from(C), // tonic
4, // octave
Some(Mode::Ionian), // scale mode
Direction::Ascending, // scale direction
).unwrap();
// returns a Vector of the Notes of the scale
let scale_notes = scale.notes();The same pattern covers chords, where a root, a quality and a number give you back the notes of the chord, and the readme points at the tests folder for more detailed examples.
The 0.5 chord parser normalizes what a lead sheet prints
Version 0.5 added a normalized lead-sheet chord model and a compact parser, and this is the part of the library with the most direct application to real chart files. A lead sheet writes chords as C, Cmaj7, Cm7b5, C7sus4, Cadd9, Cmaj9#11, C7alt, C/E, and dozens of aliases such as CΔ, C^7, CM7, Cmi7, C°7, Cø7 and C+7. Every real chart uses some subset of that, and every parser has to agree on what the aliases mean.
The approach is that parsing preserves generic note spelling, resolves modifiers in musical order, and formats every accepted alias as portable ASCII. That last property matters more than it first appears, because a downstream consumer that displays or stores chord symbols needs one canonical form rather than a dozen spellings of the same chord.
The API is a single parse call, and the same normalized grammar backs FromStr and Display:
use rust_music_theory::chord::Chord;
use rust_music_theory::note::Notes;
let chord = Chord::parse("Cmaj9#11/G")?;
assert_eq!(chord.canonical_symbol(), "Cmaj9#11/G");The accepted grammar is broad. Families cover C, Cm, Cdim, Caug, C5, C6, Cm6, C6/9 and Cm6/9. Sevenths cover C7, Cmaj7, Cm7, CmMaj7, Cm7b5, Cdim7, Caug7 and CaugMaj7. Extensions cover dominant, major, minor and minor-major forms of 9, 11 and 13. Suspensions and additions cover C7sus4, Cm7sus4, Csus2, Cadd2, Cadd4, Cadd6, Cadd9, Cadd11 and Cadd13. Alterations and omissions cover C7b5, C7#9, Cmaj9#11, C7no5 and C13omit11. Altered and slash chords cover C7alt, C/E, C/F# and C/1, and the alias list runs from CΔ and CΔ9 through C69, C6add9 and C7(b9,#11).
The details are precise where it counts. ASCII and Unicode single and double accidentals are accepted on roots and slash basses, and generated note octaves follow written scientific pitch, so Cb4 plays as MIDI 59 and B#4 as MIDI 72. That is the spelling-sensitive behaviour, not a rounding convenience.
For programmatic construction, Chord::builder(root) exposes the same validated model, and the documentation points at a chord symbol reference for grammar, canonicalization, builder usage, errors and the 0.4 to 0.5 migration.
The minor modes are seven rotations each, with a classical exception
The harmonic minor and melodic minor families are exposed through the same Scale, ScaleType and Mode types as everything else, and all seven rotations of each are available.
The harmonic minor family lists Harmonic Minor, Locrian natural 6, Ionian #5, Dorian #4, Phrygian Dominant, Lydian #2 and Ultralocrian. The melodic minor family lists Melodic Minor, Dorian b2, Lydian Augmented, Lydian Dominant, Mixolydian b6, Locrian #2 and Altered.
The names are case-insensitive and accept ASCII or Unicode accidentals, words such as flat and sharp, snake-case API identifiers, and established aliases including Spanish, Overtone, Hindu, Super Locrian and Diminished Whole Tone. The definitions follow the Tonal scale registry, which matters because it means a mode you type means the same thing in this library as it does in the wider JavaScript music theory ecosystem.
The construction is the same four-argument shape as a diatonic scale:
use rust_music_theory::note::{NoteLetter, Notes, Pitch};
use rust_music_theory::scale::{Direction, Mode, Scale, ScaleType};
let scale = Scale::new(
ScaleType::HarmonicMinor,
Pitch::new(NoteLetter::C, 0),
4,
Some(Mode::PhrygianDominant),
Direction::Ascending,
)?;Two behaviours are worth knowing about before you rely on them. The existing base melodic-minor scale retains classical behaviour, meaning descending it lowers the sixth and the seventh, while the derived melodic-minor modes use the ascending jazz pitch collection in both directions. And Altered mode keeps rotation-derived diatonic spelling, so C altered is written C Db Eb Fb Gb Ab Bb rather than using enharmonic chord tension names. That is a deliberate choice to stay consistent with rotation rather than to be idiomatic.
The practical upshot is that a library that used to model only the diatonic collection now covers the minor modes, which is most of what a generator of progressions and melodies needs.
MIDI export and live playback sit behind optional features
The library supports MIDI file export and real-time MIDI playback to hardware or software synthesizers, and both are opt-in through Cargo features rather than default dependencies.
Export comes with the midi feature:
[dependencies]
rust-music-theory = { version = "0.5", features = ["midi"] }With it enabled you can write a single chord straight to a file, or assemble a multi-track composition with a builder:
use rust_music_theory::chord::{Chord, Quality, Number};
use rust_music_theory::note::{Pitch, PitchSymbol::*};
use rust_music_theory::midi::{MidiBuilder, MidiFile, Duration, Velocity, Channel};
// Quick export
let chord = Chord::new(Pitch::from(C), Quality::Major, Number::Triad);
chord.to_midi(Duration::Quarter, Velocity::new(100).unwrap())
.save("chord.mid")?;Real-time playback uses a separate feature, midi-playback, and the manifest shows that midi-playback depends on midi and pulls in a second crate, midir, alongside midly for file handling. The distinction between the two is deliberate: writing a file needs no audio backend, so a server side tool that only generates MIDI files does not have to link a synthesiser interface.
The examples directory shows the range of things people build with this. There are files for hypnotic techno, techno bass, synth chords, a nocturne, a nocturne duo, a simple MIDI test, and a MIDI CC demo, and every one of them declares required-features of midi-playback in the manifest, so they only build with that feature enabled.
The library also compiles to WebAssembly. The manifest sets the crate-type to both cdylib and rlib, lists wasm-bindgen and serde-wasm-bindgen as dependencies, and pulls in the web-sys crate with a console feature, with wasm-bindgen-test as a dev dependency for testing in a browser. A separate www directory in the repository root points at an interactive playground for that target.
The manifest also carries clap for the executable side, strum for the enum-heavy type vocabulary, serde for serialisation, and regex, which is the dependency doing the chord symbol parsing work.
A 0.5 manifest against a 0.4 release, and where the project is going
The version numbering needs a note, because it is the kind of detail that breaks a dependency in a build. The readme instructs you to depend on rust-music-theory = "0.5", and the Cargo.toml in the repository reads version = "0.5.0". The published release line, however, tops out at v0.4.0, published on 2026-07-12.
So the 0.5 features described in the readme, the normalized chord model and the minor mode families, exist on the branch but the newest tagged release is one version behind. The last push was on 2026-07-13, a day after that v0.4.0 tag, which suggests the release was cut and the 0.5 work continued immediately after. If you depend on the 0.5 line, you are depending on a crates.io version that may or may not have been published from this state, and a lockfile is the only way to be certain what you got.
The project structure is conventional for a Rust library. There is a src directory, a tests directory, an examples directory, a docs directory with the chord symbol reference, a www directory for the web playground, a CHANGELOG.md, a .travis.yml for continuous integration with a build status badge and a separate coverage badge through coveralls, and badges pointing at crates.io and docs.rs. The licence is MIT and the crate is on crates.io under the name rust-music-theory.
The readme also carries a Roadmap section, which is the place to look for whether the chord parser and the scale registry work are finished or still moving.
One more thing the manifest reveals is that the crate is a library and a binary in one, since clap is a dependency and the readme lists usage as an executable alongside usage as a library. The executable is the way to poke at chord symbols from a shell without writing any Rust.
Editorial conclusion
Adopt rust-music-theory if you are writing a generator, sequencer or analysis tool in Rust and want pitch spelling, scale membership and chord voicings to be typed values rather than MIDI numbers you compute by hand, and if you want to hand the result to a hardware or software synthesizer. Do not adopt it if you need a general music information retrieval library, because the scope is procedural music theory rather than a catalogue of recorded work, and expect the chord parser to be a 0.5 feature that may still move. Before you pin a version, check the crates.io release line against the Cargo.toml version, because the manifest reads 0.5.0 while the latest tagged release is v0.4.0.
Frequently asked questions
How do I add rust-music-theory to a Rust project?
Add rust-music-theory to the dependencies in your Cargo.toml, for example rust-music-theory = "0.5", then use the note, scale and chord modules. The library is published on crates.io with API documentation on docs.rs.
Can rust-music-theory parse lead-sheet chord symbols?
Yes, version 0.5 added a normalized lead-sheet chord model and a compact parser. It accepts families, sevenths, extensions, suspensions, additions, alterations, omissions, altered and slash chords, and aliases such as CΔ, C^7, CM7, C°7 and Cø7, and it can output one canonical ASCII symbol for any of them.
Does rust-music-theory support MIDI export and playback?
Yes, through two optional Cargo features. The midi feature enables writing chords and scales to MIDI files with MidiBuilder and MidiFile, and midi-playback adds real-time output to hardware or software synthesizers through the midir crate.
Which minor scale modes does rust-music-theory support?
All seven rotations of the harmonic minor and melodic minor families are available through the same Scale, ScaleType and Mode types, including Phrygian Dominant, Locrian natural 6, Ionian #5, Altered and Locrian #2. The mode definitions follow the Tonal scale registry.
What is the latest published version of rust-music-theory?
The most recent tagged release is v0.4.0 from 2026-07-12, while the readme and the Cargo.toml both refer to 0.5, so check the crates.io release line and lock your dependency rather than assuming the newest feature set is in a published version.
Official sources
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.
[](https://hysenlabs.com/projects/ozankasikci-rust-music-theory)Was this useful?