memol language overview

WARNING: The documentation is very incomplete and different from the latest implementation.

memol is a music description language which features:

Well-structured
Essentially, a score is described as recursive compositions of two constructs: group "[...]" and chord "(...)".
Orthogonal
Some musical elements like scale, chord and backing pattern can be described independently and composite them each other. "with" syntax enables (some of) them in a unified form. Expressions (note velocity, control change, ...) are also described separately.
Focused on musical composition
Language design and implementation help trial-and-error of musical composition well (in the future). Unlike score typesetting languages, memol also focused on describing time-dependent value used for MIDI control changes, etc.
Extendable with arbitrary programming languages
(Planned. Not implemented yet.)

memol does not aim to have:

Complete ability to describe music typesetting
Staff notation generation may be implemented in the future, but memol never will be a complete score typesetting language. Lilypond is awesome for this purpose (In fact, the sheet musics in this page are rendered by Lilypond!).

Here is a example written in (current) memol language.

/* Gymnopedie No. 1, Erik Satie */

score $melody_common() = {
    _  | _    | _    | _  < | _FA | gfc  | bCD  | a    |
    f^ | f^   | f^   | f  < | _FA | gfc  | bCD  | a    |
    C  | F >  | e^   | e^   | e   | ABC- | Edb  | Dc-b |
    D^ | D:2D | EF-G | Ac-D | Edb | D^   | D:2D | G
}

score $melody() = [
    $melody_common() { < F  | baB   | CDE  | cDE  | f:2G  | C- | D }
    $melody_common() { < F- | bC-F- | edc- | Edc- | f-:2G | C- | D }
]

score $chord_common() = [
    repeat 8 { (gBDF_)  | (dACF_) } {
    (fACF_)  | (b<BDF_) | (EGB__)   | (EBDG_)  | (dF-AD_) | (a<AC-E_) | (DGBE_)  | (DDGBE) |
    (Dc-EAD) | (Dc-FAD) | (DAC-F-_) | (DAC-E_) | (DGBE_)  | (DDGBE)   | (Dc-EAD) | (EBEG_) }
]

score $chord() = [
    $chord_common()
    { (fACF_)  | (b<BDF_)  | (ECEA_)  | (EACFA)   | E (EbAD) (EEBD) | (AgC-EA_) | (daD<DFA)  }
    $chord_common()
    { (eADF-A) | (EAC-F-_) | (EC-EA_) | (EAC-F-A) | E (EbAD) (EEBD) | (AgC-EA_) | (daD<DF-A) }
]

score $pattern() = [
    repeat 36 { @q0 > q0 ^ (/ @q1 Q1 Q2 Q3 Q4):2 }
    { (@q0 > q0 [_ (@q1 Q1 Q2 Q3) /]) | (@q0 > q0 @q1 Q1 Q2 @q3 Q3 Q4 Q5) | / }
]

score $out.0() = [
    _ ( $melody() repeat 2 $pattern() with q = $chord() ) with * = repeat 78 { (ABC+DEF+G) } _
]

value $out.0.offset()   = $gauss() / 512
value $out.0.velocity() = $gauss() / 64 + (if $note.nth() == 0 then 4/8 else 3/8)
value $out.0.cc64()     = [ repeat 79 { 0 1:23 } { 0 } ]
value $out.tempo()      = 2/5

Although the core idea of the language is considered for many years, the development begun recently so both the language specification and the implementation are still in a very early stage. Currently they lack many features for practical use.

Current status

Download pre-built binaries

See GitHub Release page.

Note that macOS binaries are never tested since I don't have a Mac...

Build and install

This section is only necessary for users who want to build memol themselves.

Although memol can run potentially on any platforms which support Rust and JACK, I develop it primary on Linux and sometimes test it on Windows (x86_64-pc-windows-gnu target). Please make sure that following programs are installed and configured properly.

Building and installing memol are quite simple thanks to Cargo; Just type

$ cargo install --git https://github.com/y-fujii/memol-rs/ memol_cli

and everything should be done.

Recent version of memol has experimental GUI program. Clang must be installed to build one.

$ cargo install --git https://github.com/y-fujii/memol-rs/ memol_gui

Building memol_gui on Windows requires a workaround due to issue #47048" for now. I recommended to use prebuild binaries above.

Run

$ memol_cli
Usage: memol_cli [options] FILE
Options:
    -v, --verbose
    -b, --batch         Generate a MIDI file.
    -c, --connect PORT  Connect to a JACK port.
    -a, --address ADDR:PORT
                        WebSocket address.

$ memol_gui
Usage: memol_gui [options] [FILE]
Options:
    -s, --scale VALUE   Set DPI scaling.
    -w, --wallpaper FILE
                        Set background image.
    -c, --connect PORT  Connect to JACK port.
    -a, --address ADDR:PORT
                        WebSocket address.

There are three way to interact with other applications.

XXX

XXX

PORT can be specified multiple times and then the memol output port is being connected to them.

memol keeps watching the change of the file and reflects it immediately. If $out.begin, $out.end (see below) are specified, memol automatically seeks and starts playing each time the file has changed.

Since memol supports JACK transport, start/stop/seek operations are synced with other JACK clients. Personally I use Carla to manage JACK connections, plugins, etc. Many JACK supported DAW like Ardour can be used, of course.

Hello, twinkle little star

score $out.0() = { c c G G | A A g _ | f f e e | d d c _ }

[image of music]

memol language structure is roughly divided into two layers: inside of {...} and outside of. Both layers have similar syntax and similar semantics, but different. Inside {...}, sequence is splitted by "|" and each part gets the unit time length regardless of the number of the elements.

XXX

Outside {...}, on the other hand, all the elements have the specific length.

XXX

Token

Unlike common programming languages, newline and whitespace characters have no meanings at most locations. The exception is the one before or after the registerd words ("score", "value", etc.), symbol names ("$name") and numbers. For example, "(cEGB)" and "( c E G B )" have the same meaning, "scoreabc" is different from "score abc".

Comments

/* This is a comment */

Octave

memol has a mechanism to avoid annoying octave changing. If you write a note in upper case, it has higher pitch than previous one within a octave. If in lower case, it has lower pitch within a octave. "<" and ">" can be used to make the current octave +1 and -1 respectively.

score $out.0() = { c D E d | > D E < c _ }

[image of music]

Accidental

Sharp and flat pitches are represented as "+", "-" respectively. they must specified every time. A key signature can be specified with "with" syntax explained later.

score $out.0() = { c D+ E++ F- }

[image of music]

Group

Grouping is one of the unique features of memol. Unlike other language, absolute duration values are never specified in memol. Grouping is noted as "[...]" and it divides the duration equally into child notes and serializes them. Group notation can be nested oneself and other notation. Each child note have an optional number prefix, which represents a relative ratio. For example, "[e:3 c:2]" gives the duration 3/5 to "e" and 2/5 to "c".

score $out.0() = { c | c c | c c c | c [c c c c] [c:3 c] [c:2 c:3 [c c]] }

[image of music]

Chord

Chord is noted as "(...)" and child notes are located in parallel. Chord can be nested oneself and other notation. The note pitch used to determine the octave of next note is the first child of the chord, not the last child.

score $out.0() = { (c E G) | (c E G [B C b]) (c E F A) }

[image of music]

Tie

Recently, tie related specification is fundamentally changed. It might be buggy for now.

Tie is noted by adding "^" after the note which the tie begins. Composite notes such as group and chord also can be tied. A tied chord means all child notes are tied. A tied group means the last note is tied.

score $out.0() = { [c:3 c]^c [c:3 c^] c | (c E G)^(c E G) | (c^ E^ G) (c E G) }

[image of music]

Repeat

"/" is semantically equivalent to the previous note, the most recent simple note or chord in postordered depth-first traversal. The ties of child notes are inherited if a target is composite (the tie attached to itself is not inherited).

score $out.0() = { (c E G) / | (c [E /]) | ([c:3 E]) / | c^(/ E)^(/ G) }

[image of music]

Score level composition

Score elements can be composited by "[...]" and "(...)", which looks similar to group and chord syntax; "[...]" serializes its child elements and "(...)" locates its child elements in parallel. Additionally, repeat N element syntax is used for repeating, stretch N/M element for stretching time.

score $out.0() = [ repeat 2 { c D E d } ( { E F G A | c c c c } stretch 3/4 { D E F } ) ]

Score symbols

Score symbols is similar to constant variables in common programming languages and probably works as you expected. It is possible to use symbols defined after their location. Defining the same name symbol more than once causes error.

score $part_a() = { e F G A }
score $part_b() = { c D E F }
score $out.0()  = ( $part_a() $part_b() )

"with" syntax

"with" syntax is one of the unique feature of memol that enables high level music description.

XXX

XXX

score $chord()   = { (c E G B) (D F G B) | (c E G B) }
score $pattern() = { [@q0 Q1 Q2 q1] (@q0 Q1 Q2 Q3) }
score $out.0()   = repeat 2 $pattern() with q = $chord()

[image of music]

The special symbol "_" corresponds to the note symbols "abcdefg". It can be used to change a key signature.

score $a_major() = { (c+DEF+G+AB) }
score $out.0()   = { ... } with * = $a_major()

Value track

Value track has the similar syntax to score track and it describes the time-dependent value.

XXX

Outside "{...}", arithmetic operators (+, -, *, /), comparison operators (==, !=, <=, >=), logical operators (||, &&, !) and a branch syntax ("if A then B else C") can be applied.

XXX

value $out.tempo()      = 1 / 2
value $out.0.velocity() = { [3:3 4] 3 2 | 2..4 3 } / 8 + { 0..1 | 1..2 } / 4
value $out.0.offset()   = $note.nth() / 32 + $gauss() / 256
value $out.0.duration() = $note.len() * 6 / 8 + 1 / 8
value $out.0.cc11()     = { 3..* | 4..* | *..* | *..1 } / 4

There are some special symbols: $note.len(), $note.cnt(), $note.nth().

XXX

XXX

score $top_notes()  = filter $note.nth() == 0 { (cEGB) | (cEFA) }
score $transposed() = transpose 3 { (cEGB) | (cEFA) }
score $sliced()     = slice 0 3/2 { (cEGB) | (cEFA) }

MIDI channels

WARNING: This specification will be changed.

Although this is out of the language specification, current implementation maps the score to MIDI outputs by variable names: $out.0 .. $out.15 are mapped to MIDI channel 1 .. 16.

Begin/end position

XXX

value $out.begin() =  0
value $out.end()   = 24

Import

import "other_file.mol"
Yasuhiro Fujii <y-fujii at mimosa-pudica.net>