WARNING: The documentation is very incomplete and different from the latest implementation.
memol is a music description language which features:
"[...]"
and chord "(...)"
.
"with"
syntax enables (some of) them in a unified form. Expressions (note
velocity, control change, ...) are also described separately.
memol does not aim to have:
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.
Note that macOS binaries are never tested since I don't have a Mac...
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.
$ 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.
score $out.0() = { c c G G | A A g _ | f f e e | d d c _ }
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
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"
.
/* This is a comment */
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 _ }
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- }
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]] }
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) }
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) }
"/"
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) }
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 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()
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 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) }
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.
XXX
value $out.begin() = 0 value $out.end() = 24
import "other_file.mol"Yasuhiro Fujii <y-fujii at mimosa-pudica.net>