Skip to content

ozankasikci/rust-music-theory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

328 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust Music Theory

Build Status Coverage Status Crates.io Documentation

A library and executable that provides programmatic implementation of the basis of the music theory.

Table of Contents

Overview

Rust Music Theory is used to procedurally utilize music theory notions like Note, Chord, Scale, Interval and more. The main purpose of this library is to let music theory be used in other programs and produce music/audio in a programmatic way.

Usage as a Library

Add rust-music-theory as a dependency in your Cargo.toml.

[dependencies]
rust-music-theory = "0.5"

After installing the dependencies, you can use the library as follows.

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();

// Chord Example;
let chord = Chord::new(Pitch::from(C), ChordQuality::Major, ChordNumber::Triad);

// returns a Vector of the Notes of the chord
let chord_notes = chord.notes();

This is the simplest form of the usage. For detailed examples, please see the tests folder.

Lead-Sheet Chord Symbols

Version 0.5 adds a normalized lead-sheet chord model and a compact parser. Parsing preserves generic note spelling, resolves modifiers in musical order, and formats every accepted alias as portable ASCII.

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");
assert_eq!(
    chord.notes().iter().map(|note| note.pitch.to_string()).collect::<Vec<_>>(),
    ["G", "B", "D", "F#", "C", "E"]
);

// FromStr and Display use the same normalized grammar.
let half_diminished: Chord = "Cø7".parse()?;
assert_eq!(half_diminished.to_string(), "Cm7b5");
# Ok::<(), rust_music_theory::chord::ChordError>(())

Common supported forms include:

  • Families: C, Cm, Cdim, Caug, C5, C6, Cm6, C6/9, Cm6/9
  • Sevenths: C7, Cmaj7, Cm7, CmMaj7, Cm7b5, Cdim7, Caug7, CaugMaj7
  • Extensions: dominant, major, minor, and minor-major 9, 11, and 13
  • Suspensions and additions: C7sus4, Cm7sus4, Csus2, Cadd2, Cadd4, Cadd6, Cadd9, Cadd11, Cadd13
  • Alterations and omissions: C7b5, C7#9, Cmaj9#11, C7no5, C13omit11
  • Altered and slash chords: C7alt, C/E, C/F#, C/1
  • Aliases and groups: , CΔ9, CmΔ, C^7, CM7, Cma7, C-7, Cmi7, Cm/M7, C°7, Cø7, Ch7, C+7, C69, C6add9, C7(b9,#11)

ASCII and Unicode single/double accidentals are accepted on roots and slash basses. Generated note octaves follow written scientific pitch, so Cb4 plays as MIDI 59 and B#4 as MIDI 72.

Chord::builder(root) exposes the same validated model for programmatic construction. See the chord-symbol reference for grammar, canonicalization, builder usage, errors, and the 0.4 to 0.5 migration.

Harmonic and Melodic Minor Modes

All seven rotations of the harmonic-minor and melodic-minor families are available through the same Scale, ScaleType, and Mode APIs:

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,
)?;

assert_eq!(
    scale.notes().iter().map(|note| note.pitch.to_string()).collect::<Vec<_>>(),
    ["C", "Db", "E", "F", "G", "Ab", "Bb", "C"]
);
# Ok::<(), rust_music_theory::scale::ScaleError>(())
  • Harmonic minor: Harmonic Minor, Locrian natural 6, Ionian #5, Dorian #4, Phrygian Dominant, Lydian #2, and Ultralocrian.
  • Melodic minor: Melodic Minor, Dorian b2, Lydian Augmented, Lydian Dominant, Mixolydian b6, Locrian #2, and Altered.

Names are case-insensitive and accept ASCII or Unicode accidentals, words such as flat and sharp, snake-case API identifiers, and established aliases such as Spanish, Overtone, Hindu, Super Locrian, and Diminished Whole Tone. The definitions follow the Tonal scale registry.

The existing base melodic-minor scale retains classical behavior: descending it lowers the sixth and seventh. Derived melodic-minor modes use the ascending/jazz pitch collection in both directions. Altered mode retains rotation-derived diatonic spelling, so C altered is written C Db Eb Fb Gb Ab Bb rather than using enharmonic chord-tension names.

MIDI Support

The library supports MIDI file export and real-time MIDI playback to hardware/software synthesizers.

MIDI File Export

Enable the midi feature to export chords and scales to MIDI files:

[dependencies]
rust-music-theory = { version = "0.5", features = ["midi"] }
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")?;

// Multi-track composition
let mut builder = MidiBuilder::new();
builder
    .tempo(120)
    .add(&chord, Duration::Whole, Velocity::new(90).unwrap());

MidiFile::new()
    .tempo(120)
    .track(builder, Channel::new(0).unwrap())
    .save("song.mid")?;

Real-Time MIDI Playback

Enable the midi-playback feature to play notes on connected MIDI devices (hardware synths, DAWs like Ableton):

[dependencies]
rust-music-theory = { version = "0.5", features = ["midi-playback"] }
use rust_music_theory::chord::{Chord, Quality, Number};
use rust_music_theory::note::{Pitch, PitchSymbol::*};
use rust_music_theory::midi::playback::{MidiPorts, MidiPlayer};
use rust_music_theory::midi::{Duration, Velocity};

// List available MIDI ports
let ports = MidiPorts::list()?;
for (i, name) in ports.iter().enumerate() {
    println!("{}: {}", i, name);
}

// Connect and play
let mut player = MidiPlayer::connect_index(0)?;
player.set_tempo(120);

let chord = Chord::new(Pitch::from(C), Quality::Major, Number::Triad);
player.play(&chord, Duration::Quarter, Velocity::new(100).unwrap());

// Control Change (filter, modulation, etc.)
player.control_change(1, 64);   // Modulation wheel
player.control_change(74, 100); // Filter cutoff

// Program Change (switch instruments)
player.program_change(0);                    // Piano
player.program_change_with_bank(5, 0, 1);   // Bank 1, program 5

// MIDI Clock (sync with DAW)
player.start_clock();  // Sends clock at 24 PPQ
// ... play notes ...
player.stop_clock();

Using with Ableton Live

  1. macOS: Enable IAC Driver in Audio MIDI Setup
  2. In Ableton: Preferences → Link, Tempo & MIDI → Enable Track for IAC Driver
  3. Create a MIDI track, set input to IAC Driver
  4. Run your Rust code - notes play through Ableton's instruments!

For MIDI clock sync, enable "Ext" sync in Ableton's transport.

Usage as an Executable

cargo install --git https://github.com/ozankasikci/rust-music-theory

This lets cargo install the library as an executable called rustmt. Some usage examples;

rustmt scale D Locrian

Notes:
  1: D
  2: D#
  3: F
  4: G
  5: G#
  6: A#
  7: C
  8: D

rustmt chord C# Dominant Eleventh

Notes:
  1: C#
  2: E#
  3: G#
  4: B
  5: D#
  6: F#

Compact symbols and canonical normalization are also available:

$ rustmt chord C7sus4
Notes:
  1: C
  2: F
  3: G
  4: Bb

$ rustmt chord normalize 'C7(b9,#11)'
C7b9#11

rustmt scale list

Available Scales:
 - Ionian
 - Dorian
 - Phrygian
 - Lydian
 - Mixolydian
 - Aeolian
 - Locrian
 - Harmonic Minor
 - Locrian natural 6
 - Ionian #5
 - Dorian #4
 - Phrygian Dominant
 - Lydian #2
 - Ultralocrian
 - Melodic Minor
 - Dorian b2
 - Lydian Augmented
 - Lydian Dominant
 - Mixolydian b6
 - Locrian #2
 - Altered
 - Pentatonic Major
 - Pentatonic Minor
 - Blues
 - Chromatic
 - Whole Tone

rustmt chord list

Supported chord syntax:
 - Major Triad: C
 - Sevenths: C7, Cmaj7, Cm7, CmMaj7, Cm7b5, Cdim7, Caug7, CaugMaj7
 - Altered dominant: C7alt
 - Slash basses and inversions: C/E, C/F#, C/1
 ...

Interactive Playground

Try the library in your browser with the interactive WASM playground:

https://ozankasikci.github.io/rust-music-theory/

Playground Screenshot

Building From Source

The binary returns the notes of the requested scale or chord. Chords use the normalized Unicode-aware tokenizer; the older regex-named chord entry point is retained only as a deprecated compatibility wrapper. To quickly build and run the executable locally;

git clone http://github.com/ozankasikci/rust-music-theory && cd rust-music-theory

Then you can directly compile using cargo. An example;

cargo run scale D Locrian

Notes:
  1: D
  2: D#
  3: F
  4: G
  5: G#
  6: A#
  7: C
  8: D

Roadmap

  • MIDI file export
  • Real-time MIDI playback
  • MIDI Control Change & Program Change
  • MIDI Clock (master mode)
  • Properly display enharmonic spelling
  • Add inversion support for chords
  • Add missing modes for Melodic & Harmonic minor scales
  • Add support for arbitrary accidentals
  • Add a mechanism to find the chord from the given notes
  • MIDI input (receive from external devices)

About

A music theory guide written in Rust.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages