8 个版本 (5 个重大更改)
0.5.1 | 2024年5月12日 |
---|---|
0.5.0 | 2023年11月17日 |
0.4.1 | 2023年11月17日 |
0.3.0 | 2023年11月17日 |
0.0.0 | 2023年11月8日 |
#399 in 音频
每月 78 次下载
75KB
972 行
LMML
LMML(LMML Music Macro Language)是MML的方言。
演奏示例
https://github.com/yuma140902/lmml/assets/23431077/dfad8777-ade5-4591-8804-a3968a2e14ea
; Bad Apple!! feat. nomico
t320 l4
@0 v15
<ab>cd e.r8ag e.r8<a.r8> edc<b>
<ab>cd e.r8dc <bab>c <bagb>
<ab>cd e.r8ag e.r8<a.r8> edc<b>
<ab>cd e.r8dc <b.r8>c.r8 d.r8e.r8
@1 v10
<ab>cd e.r8ag e.r8<a.r8> edc<b>
<ab>cd e.r8dc <bab>c <bagb>
<ab>cd e.r8ag e.r8<a.r8> edc<b>
<ab>cd e.r8dc <b.r8>c.r8 d.r8e.r8
@3 v25
gaed e.r8de gaed e.r8
dedc <bga.r8 gab>c de<a.r8>
egga ede.r8 dega ede.r8
dedc <bga.r8 gab>c de<a.r8>
@4 v30
egga ede.r8 dega ede.r8
dedc <bga.r8 gab>c de<a.r8>
egga ede.r8 dega ede.r8
ab>c<b age.r8 dedc <bga.r8>
@0 v15
egga ede.r8 dega ede.r8
dedc <bga.r8 gab>c de<a.r8>
egga ede.r8 dega ede.r8
dedc <bga.r8 gab>c de<a.r8>
egga ede.r8 dega ede.r8
dedc <bga.r8 gab>c de<a.r8>
egga ede.r8 dega ede.r8
ab>c<b age.r8 dedc <bga.r8
LMML教程
演奏方法
使用lmml-cli的对话模式是演奏LMML代码最简单的方法。
cargo install lmml-cli
安装lmml-cli,
lmml repl
启动对话模式。
语法
LMML有几个命令。这些命令的组合构成了LMML程序。
如果您想了解严格的语法,请参阅下面的“LMML语言语法”。
音符命令
C
~B
的字符分别代表C到B的音符。+
表示升高半音,-
表示降低半音。
音符命令之后可以跟一个表示音长数字。例如,四分音符是4,八分音符是8。注意,数字越大,音长越短。
如果省略数字,则使用最后执行的L
命令的值。如果不存在L
命令,则使用4。
此外,可以在数字后面加上.
。.
表示附点音符。
示例
c4
- C的4分音符c+8
- C#的8分音符d4.
- D的附点4分音符d+4.
- D#的附点4分音符
休止符命令
R
表示休止符。与音符命令相同,可以跟一个表示音长的数字和.
。
和弦
通过使用[
和]
括号包围音符来表示和弦。音符应该以根音开头,然后按低到高的顺序书写。
示例
[ceg]
- C Maj[ace]
- Am[ga+df]
- Gm7
; カノン進行 C/G - G - Am/E - Em - F/C - C - F/C - G/D
@4t40 [gce][gbd][eac][egb][cfa][ceg][cfa][dgb]
https://github.com/yuma140902/lmml/assets/23431077/9f5b72ed-5317-4cdf-bf3a-d028d05c7cd5
L
命令
设置音符的长度。如果没有在音符命令后面跟数字,则使用此命令的值。有关详细信息,请参阅下面的“LMML语言详细规格”。
O
命令
设置八度值。初始值为4,值越大,音越高。八度4的A是440Hz。
>
命令
将八度值增加1。
<
命令
将八度值减少1。
N
命令
使用MIDI的音符编号(0~127)来指定音符。
※LMML不依赖于MIDI,但内部以MIDI兼容的格式处理音符。
V
命令
设置音量。初始值为20,值越大音量越大。100对应0dB,0对应-∞ dB。
T
命令
设置节奏。值表示每分钟四分音符响起的次数。初始值为120。
@
命令
使用0~4的数字设置波形。默认值为0。
数字 | 波形 |
---|---|
0 | 锯齿波 |
1 | 矩形波 |
2 | 脉冲波 |
3 | 三角波 |
4 | 正弦波 |
:
命令
LMML有16个通道,可以同时演奏。
如:0
所示,后面的命令将作用于通道0。
示例
https://github.com/yuma140902/lmml/assets/23431077/6f76011c-c638-4741-a067-14986da3178d
; 少女さとり ~ 3rd eye (東方地霊殿より)
; (最初の2小節のみ)
:0 @3 v20 t60 o4
:1 @3 v20 t60 o3
:2 @3 v30 t60 o2
:3 @4 v50 t60 o2
:4 @4 v20 t60 o4
:5 @4 v40 t60 o1
:0 l8
<b4.>c+16d16f+ <b>df+g<b>c+gf+2
:1 l2
f+1 gf+
:2 l2
f+1 gf+
:3 l32
crrrrrrr rrrrrrrr [d+g]rrrrr[d+g]r rrrr[d+g]rrr
<<[bg+f]rrrrrrr rrrr[bg+f]rrr >[g+f]<rrrrrrr rrrrrrrr>>
:4 l2
[bf+]1[bg][bf+]
:5 l2
[bf+]1[bg][bf+]
LMML语言语法
<lmml> := <command>*
<command> := <note-cmd>
| <chord>
| <n-cmd>
| <rest-cmd>
| <set-octave>
| <set-length>
| <set-volume>
| <set-tempo>
| <set-wave>
| <set-channel>
| <inc-octave>
| <dec-octave>
<note-cmd> := <note-char> <modifier>? <number>? <dot>?
<note-char> := 'C' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B'
| 'c' | 'd' | 'e' | 'f' | 'g' | 'a' | 'b'
<modifier> := '+' | '-'
<rest-cmd> := 'R' <number>? <dot>? | 'r' <number>? <dot>?
<chord> := '[' (<note-char> <modifier>?)+ ']' <number>? <dot>?
<dot> := '.'
<n-cmd> := 'N' <number> | 'n' <number>
<set-ocatve> := 'O' <number> | 'o' <number>
<set-length> := 'L' <number> <dot>? | 'l' <number> <dot>?
<set-volume> := 'V' <number> | 'v' <number>
<set-tempo> := 'T' <number> | 't' <number>
<set-wave> := '@' <number>
<set-channel> := ':' <number>
<inc-octave> := '>'
<dec-octave> := '<'
<number> := <digit>+
<digit> := '0' | '1' | '2' | '3' | '4'
| '5' | '6' | '7' | '8' | '9'
基本不区分大小写。空白或换行被忽略。
以;
开始的行被视为注释并忽略。
LMML语言详细规格
长度指定
音符命令、休止符命令、L
命令中省略数字或.
时的行为如下表所示。认为行为可能因人而异的部分用粗体表示。
最后一个L 命令的数字 |
. 是否存在 |
音符·休止符命令的数字 | . 是否存在 |
长度 |
---|---|---|---|---|
L 命令无 |
N/A | 省略 | 无 | 四分音符 |
L 命令无 |
N/A | 省略 | 有 | 附点四分音符 |
L 命令无 |
N/A | n | 无 | n分音符 |
L 命令无 |
N/A | n | 有 | 附点n分音符 |
m | 无 | 省略 | 无 | m分音符 |
m | 无 | 省略 | 有 | 附点m分音符 |
m | 无 | n | 无 | n分音符 |
m | 无 | n | 有 | 附点n分音符 |
m | 有 | 省略 | 无 | 附点m分音符 |
m | 有 | 省略 | 有 | 附点m分音符 |
m | 有 | n | 无 | n分音符 |
m | 有 | n | 有 | 附点n分音符 |
音符高度
音符命令转换为频率的过程分为两步。
首先将以下称为音符编号的内部形式进行转换。$n
$是音符命令的类型,$m
$是升号、降号等指定,$o
是当前的八度。
base = if n == C then 0
if n == D then 2
if n == E then 4
if n == F then 5
if n == G then 7
if n == A then 9
if n == B then 11
modifier = if m == '+' then 1
if m == '-' then -1
else 0
N = base + modifier + ((o + 1) * 12)
然后将音符编号$N
转换为频率$f
[Hz]。
f = 440 \times 2 ^ { \frac{N - 69}{12} }
音的衰减
一个音符在响起的瞬间音量最大,然后逐渐减小。具体来说,如果音量由V
命令指定为$v_0
、音长为$T
、从响起到经过的时间为$t
,则在$t
处的音量$v(t)
$是
v(t) = \frac{v_0 (T-t)}{T}
。
目前无法更改衰减方式。
数值限制
八度的值
上下限均无,但预计在-1到9的范围内使用。另外,由于O
命令只能指定非负值,因此如果想要指定负的八度,请使用<
命令。
音量的值
下限是0,上限无。但是,由于100对应0dB,因此指定比100更大的值可能会导致音量失真。0时音完全不出。
N
命令的值
下限是0,上限无。但预计在0到127的范围内使用。
节奏
下限是1,上限无。
通道编号
下限是0,上限是15。
LMML实现的详细规格
精度
波形合成以44.1kHz、32位浮点进行。
各个crate
lmml
crate
包含LMML的AST或时间线数据结构和波形合成处理的crate。
lmml-parser
crate
LMML的解析器。
use lmml::{LmmlAst, LmmlCommand, NoteChar, NoteModifier};
use lmml_parser::parse_lmml;
pub fn main() {
let ast = parse_lmml("t80 c+ d e8. r8").unwrap();
assert_eq!(ast, LmmlAst(vec![
LmmlCommand::SetTempo(80),
LmmlCommand::Note {
note: NoteChar::C,
modifier: NoteModifier::Sharp,
length: None,
is_tied: false,
},
LmmlCommand::Note {
note: NoteChar::D,
modifier: NoteModifier::Natural,
length: None,
is_tied: false,
},
LmmlCommand::Note {
note: NoteChar::E,
modifier: NoteModifier::Natural,
length: Some(8),
is_tied: true,
},
Lmmlcommand::Rest {
length: Some(8)
is_tied: false,
},
]));
}
lmml-cli
crate
用于以交互方式演奏LMML或将其转换为其他格式命令行工具。
安装方法
cargo install lmml-cli
使用方法
播放文件。
lmml load ファイル
启动交互模式。
lmml repl
依赖项
~3–32MB
~479K SLoC