#music #notation #language #midi

bin+lib melo

A music notation language and compiler to MIDI

1 unstable release

Uses old Rust 2015

0.1.0 Feb 3, 2018

#183 in Audio

MIT license



Melo is a music notation language and a compiler to MIDI. The goal is for it to be simple, readable, and expressive. The language is in its very early stages and at the moment only has a minimal set of features.

title: Simple Chords and Drums
tempo: 144

voice Piano { program: 4 }
voice Drums { drums }

play Piano
    :| G  a | a  b | c |
    :| E  E | F  G | G |
    :| C  C | C  D | E |

play Drums
    c#: | - | - | x |
    F#: | xx xx xx xx | xx xx xx xx | - |
    D:  | -- x- -- x- | -- x- -- x- | x |
    C:  | x- -- x- -- | x- -- x- -- | x |


Currently, this project requires cargo:

cargo install melo

You could also clone the repo and build it. (Tested on Rust 1.23.0.)

It's also worth noting that I've only currently tested it on macOS.


Easiest way to get started is to play one of the examples. If you cloned the repo, you can just run:

melo mid pieces/rondo_alla_turca.melo --output rondo_alla_turca.mid

This will generate a MIDI file from this example.

If you have timidity installed, or if you set the MELO_MIDI_PLAYER environment variable to a command that can play MIDI files, then you can simply run:

melo play pieces/rondo_alla_turca.melo

The language

Top-level attributes

There are several top-level attributes that apply to an entire piece. You can set them as follows.

// Lines beginning with `//` are comments.

title: The Title of the Piece       // Spaces are allowed.
composer: Your Name                 // Same as above.
beats: 3                            // The number of beats per bar.
tempo: 120                          // The tempo of the piece in beats-per-minute.

Commas are optional when splitting attributes across multiple lines, but you can also do this:

title: A, composer: B, beats: 3


Before you can play any notes, you need instruments to play them with. A voice is declared like this:

voice Piano         // An identifier for the voice.
    program: 4      // The MIDI program number for the instrument.
                    // Run `melo ref instruments` to see them all.

    channel: 1      // The MIDI channel this voice should play on. Defaults to `1`.
    octave: -1      // This can be used to offset notes by a number of octaves.
    volume: 127     // The volume of the voice, between 0 and 127.

There is also a special drums attribute which sets up some sensible defaults for a percussion voice:

voice Drums { drums }       // This is equivalent to the following voice:

voice Drums2 { program: 0, channel: 10, octave: -2 }

Playing notes

In order to play notes with a given voice, you need to write a play block for that instrument. If you have multiple play blocks for different instruments, they will play simultaneously.

play Piano
    // The two staves below will play simultaneously.
    :| C D E F G a b c |        // There are 8 notes in this bar, so the notes are half as long...
    :| C,, E,, G,, C,  |        // As the 4 notes in this bar.

    // You can leave a blank line to continue on from the previous staves.
    :| b a G F E D C . | . |
    :| G,, E,, C,, .   | . |    // A `.` extends the length of the previous note.

The two staves used above began with :, meaning they had no prefix. If you are writing a drum part however, the prefix determines what note will be played on that stave.

play Drums
    // The `x` means hit the note, the `-` is a rest.
    F#: | xxx xxx xxx xxx |     // F# = Hi-hat
    D:  | --- x-- --- x-- |     // D = Snare drum
    C:  | x-x --x x-x --- |     // C = Kick drum, see `melo ref notes` for more information.

There may be other stave types added in future to support other properties of the music. For example, note velocity, accents, etc.


The note C is middle C, as defined by the MIDI standard. The note below that is B and the (diatonic) note above that is D.

The note an octave higher is c and the note an octave above that is c', then c'' and so on.

The note an octave lower is C, then C,, and so on.

You can sharpen and flatten a note by using C# and C_ respectively. However, bear in mind that - unlike traditional music notation, and ABC notation - these accidentals do not last for the entire bar. If you write: :| C# C |, then the first note is C sharp, and the second is C natural.

Another potential gotcha if you are used to ABC notation is that the octave boundaries are at the A notes:

Melo:   A  B  C D E F G a b c
ABC:    A, B, C D E F G A B c

Use with vim

If you copy the files in this directory into your .vim directory - or vim runtime directory - you can get syntax highlighting and filetype detection for melo.


Future features

  1. Repeats of bars/sections
  2. Key signatures
  3. Dynamics
  4. Support pitch bends / panning / other MIDI features
  5. Explicit tuplets
  6. Changing attributes (tempo, volume, ...) during piece

Future fixes

  1. Warnings/errors about missed bars/staves


~141K SLoC