Sakura is a compiler that converts MML (Music Macro Language) into MIDI files.
It converts musical text such as Japanese solfège (ドレミ) or cde into MIDI files.
Written in Rust, it runs on multiple platforms: macOS, Windows, Linux, and WebAssembly.
Sakura is a long-standing music-production tool originally developed before 2000.
MML is a notation for representing music as text, such as cde.
It makes it easy to create music. Written in Rust, it runs on macOS, Windows, Linux, and WebAssembly.
It received an award in Japan's Online Software Grand Prize 2001 and was featured in Japanese high-school information-technology textbooks.
- mmlbbs6 --- Many songs have been posted to the Sakura MML Bulletin Board 6.
An online tutorial is available. You can learn the commands while listening to the music in your browser.
The web version, PicoSakura, lets you easily play MIDI files in your browser.
For local use, the command-line edition is also available. Download binaries for each operating system below.
First, install Rust.
$ git clone https://github.com/kujirahand/sakuramml-rust.git
$ cd sakuramml-rust
$ cargo build --release
This creates target/release/sakuramml.
Write the musical score as text, for example in a file named test.mml.
To convert test.mml to test.mid, run the following command from the command line:
$ sakuramml test.mmlFor safety, generated MIDI event data is limited to 3 MiB by default. The command-line edition can change this limit when compiling trusted MML:
$ sakuramml --max-event-bytes 10485760 test.mmlThe WebAssembly limit is fixed at 3 MiB. See the MIDI event data limit for details. When the limit is exceeded, the compiler records an error and returns the partial MIDI generated up to that point.
音階4 ドレミファソラシ↑ド↓シラソファミレド
o4 cdefgab>c<bagfedc
トラック1 チャンネル1 音符1 ドミソー
TR=1 CH=1 l1 ceg^
音符1「ドミソ」
l4 'ceg' 'dfa'8 'egb'8 'ceg'
Enclose chords in single quotes. After the closing quote, you can specify the note length, gate time, and velocity, as in 'ceg'4,90,120.
Use TIME(measure:beat:step) to move to any position in the score.
// Move to the beginning
TIME(1:1:0) cdef
TIME(1:1:0) efga
// Move to the second measure
TIME(2:1:0) cdef
Use SUB{...} to return the time pointer to just before the SUB. This lets you play chords easily.
SUB{ cdef c }
SUB{ efga e }
rrrr g
In a rhythm macro, each character is treated as one instruction, regardless of case.
Define a rhythm macro in the form $character{definition}.
// Define rhythm macros (the following are defined by default, but can be redefined)
$b{n36,}
$h{n42,}
$o{n46,}
// Define a new rhythm macro
$S{n37,}
CH(10)
// Rhythm sample
Rhythm{
[4 l8
brSr bbsr r-1
hoho hoho
]
}
This edition intentionally differs from Sakura v1/v2 in several respects.
This version uses a different method for specifying step mode. In v1/v2, specifying a note length such as l%96 caused all subsequent notes to use step mode.
However, since notes are rarely specified in step mode, this version allows a step specification only temporarily; it does not continue to affect subsequent notes.
// The following two lines have the same meaning
l%96 cde
c4d4e4
Previously, tuplets were written as Div{...}. You can now omit Div and write them as {ceg}.
l4 Div{cde} f Div{gab} >c<
l4 {cde} f {gab} >c<
The sustain mark ^ also counts as one note, which is convenient.
l4 {cde}c {gfe}d {c^d} e {d^e} f
Tuplets can be nested.
l1 { c d {efe} d } c
( decreases velocity by 8, and ) increases velocity by 8.
v127 c ( c ( c (( c )) c ) c ) c
Chords using zero-valued notes, such as c0e0g, are not supported. Use ordinary chord notation instead.
'ceg' 'dfa' 'egb' 'ceg'
「ドミソ」「レファラ」「ミソシ」「ドミソ」
Advance specifications are available for note parameters (v q t o l) and for
control changes / pitch bend.
.onNote(v1, v2, ...)/ abbreviated form:.N(...)— switch the value on every note.onTime(low, high, len, ...)/ abbreviated form:.T(...)— move the value over time.onCycle(step, v1, v2, ...)/ abbreviated form:.C(...)— switch the value everystepsteps.Random(n)/.Range(low, high)/.Delay(n)/.Repeat(on/off)v.Max(n)/q.Max(n)— change the upper limit of the value (a range setting, not an advance specification)- CC / PB only:
.onNoteWave/.onNoteWaveEx/.onNoteWaveR/.Sine/.onNoteSine/.Frequency(.Frequencysets the write interval; CC and pitch bend are configured separately) v__n.onTime/onNote/onCycle/Random(...)/ per-layer advance specification added to the base velocity
v.onTime(0,127,!1)l8cccccccc
Array m=(10,10,!16); Array A=(100,100,!16); q.onTime(m,A) // Array arguments in advance specifications
v70 v__1.onCycle(!4,10,-10) cdef // velocities: 80,60,80,60
BR(2) PB.onTime(-8192,0,!4) l4c PB(0) efg^
v__n(value) (n is 0 or greater) defines an independent adjustment layer added to the
base velocity. Multiple layers are summed, and the final value is clamped to 0–127. See the
MML syntax reference for completion and reset behavior.
Define macros as follows:
// Define macros
STR P1 = {cdefg}
#P1 = {cdefg}
// Expand macros
P1
#P1
You can provide arguments to a macro and substitute them into its contents. Define #?1, #?2, #?3, and so on inside the macro; each placeholder is replaced with the corresponding argument written immediately after the macro.
// Define a macro
#Unison = { Key=#?2 Sub{ #?1 } Key=0 #?1 }
// Expand the macro
#Unison{cde},7
- MML syntax reference --- docs/syntax.md
- Sakura (Rust Edition) command list --- command.md
- Sakura (v2 Edition) command list --- https://sakuramml.com/doc/command/index.htm
- Instrument list --- voice.md