Skip to content

Commit

Permalink
refactor lexer::read_upper_command
Browse files Browse the repository at this point in the history
  • Loading branch information
kujirahand committed Nov 15, 2022
1 parent aaeda88 commit f318752
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 42 deletions.
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
# テキスト音楽サクラ(Rust版)

「ドレミ」や「cde」のテキストをMIDIファイルに変換するコンパイラです。
手軽に音楽を作成できるツールです
「ドレミ」や「cde」のテキストをMIDIファイルに変換するコンパイラです。手軽に音楽を作成できるツールです。
Rustで作られておりマルチプラットフォーム(macOS/Windows/Linux/WebAssembly)で動作します

## どこまで作ったか

だいぶ、いろいろな楽譜を再生できます。

- 使えるコマンドの一覧が[こちら](src/command.md)にあります。
- ブラウザで手軽に音楽を再生できる[ピコサクラ](https://sakuramml.com/go.php?15)を実装しました。
- サクラv2と比べると機能は少ないですが、使えるコマンドの一覧が[こちら](src/command.md)にあります。
- 内部構造についての説明が[こちら](dev_memo.md)にあります。

## 実装予定だが未実装
### 実装予定だが未実装

- & タイ Slur(type[,value,range]) タイ記号"&"の異音程(スラー)の動作を変更する。type=0:グリッサンド/1:ベンド/2:ゲート/3:アルペジオ

### 未実装で実装予定なし

- onCycle系の連続書き込み命令 (あまり使わない?)
- FOR IF WHILE FUNCTION (別途スクリプト言語からMMLを動的に生成する方が実用的)
- onCycle命令
- FOR IF WHILE FUNCTION (別途スクリプト言語からMMLを動的に生成する方が実用的かと)

# インストールについて

Web版が「[こちら(ピコサクラ)](https://sakuramml.com/go.php?15)」です。
ブラウザ上で手軽にMIDIファイルを再生できます。

ダウンロードして使いたい場合、コマンドライン版が使えます。releaseより各OSのバイナリをダウンロードしてください。

# 使い方

## コマンドライン版の使い方

楽譜情報をテキストに記述します。例えば「test.mml」というファイルに記述します。
それを、"test.mml"を"test.mid"に変換するには、コマンドラインで以下のようにコマンドを実行します。

```
$ sakuramml test.mml
```

## 基本的な使い方

```
音階4 ドレミファソラシ↑ド↓シラソファミレド
o4 cdefgab>c<bagfedc
Expand Down Expand Up @@ -82,7 +98,7 @@ Rhythm{
}
```

## サクラv1/v2との違い
## サクラv1/v2とサクラRust版の違い

サクラv1/v2と敢えて変更した点があります。

Expand All @@ -99,7 +115,7 @@ c4d4e4

### 連符の指定方法

連符のDiv{...}でDivを省略できます
従来、連符は『Div{...}』と記述していましたが、『Div』を省略して、『{ceg}』のように記述できます

```
l4 Div{cde} f Div{gab} >c<
Expand Down Expand Up @@ -132,6 +148,7 @@ v127 c ( c ( c (( c )) c ) c ) c

```
`ceg` `dfa` `egb` `ceg`
「ドミソ」「レファラ」「ミソシ」「ドミソ」
```

### 先行指定とCCやPBの連続書き込み
Expand Down Expand Up @@ -173,5 +190,5 @@ P1
## 参考

- サクラ(Rust版)のコマンド一覧 --- [command.md](src/command.md)
- サクラv2のコマンド一覧 --- https://sakuramml.com/doc/command/index.htm
- サクラ(v2版)のコマンド一覧 --- https://sakuramml.com/doc/command/index.htm

72 changes: 41 additions & 31 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ pub fn lex(song: &mut Song, src: &str, lineno: isize) -> Vec<Token> {
't' => result.push(read_timing(&mut cur, song)), // @ 発音タイミングの指定 (例 t-1) / t.Random=n
'y' => result.push(read_cc(&mut cur, song)), // @ コントロールチェンジの指定 (例 y1,100) 範囲:0-127 / y1.onTime(low,high,len)
// uppwer command
'A'..='Z' | '_' => result.push(read_upper_command(&mut cur, song, ch)),
'#' => result.push(read_upper_command(&mut cur, song, ch)),
'A'..='Z' | '_' => result.push(read_upper_command(&mut cur, song)),
'#' => result.push(read_upper_command(&mut cur, song)),
// flag
'@' => result.push(read_voice(&mut cur, song)), // @ 音色の指定 範囲:1-128
'>' => result.push(Token::new_value(TokenType::OctaveRel, 1)), // @ 音階を1つ上げる
Expand Down Expand Up @@ -87,39 +87,19 @@ pub fn lex(song: &mut Song, src: &str, lineno: isize) -> Vec<Token> {
}

/// read Upper case commands
fn read_upper_command(cur: &mut TokenCursor, song: &mut Song, ch: char) -> Token {
cur.prev(); // back 1char
let cur_pos = cur.index;
let mut cmd = cur.get_word();

// macro define?
if ch == '#' {
cur.skip_space();
if cur.eq_char('=') { // DEFINE MACRO
cur.index = cur_pos;
return read_def_str(cur, song);
}
}

// variables?
match song.variables.get(&cmd) {
Some(sval) => {
cur.skip_space();
// set varable?
if cur.eq_char('=') {
cur.index = cur_pos;
return read_def_str(cur, song);
}
// get variable
return read_variables(cur, song, &cmd, sval.clone());
},
fn read_upper_command(cur: &mut TokenCursor, song: &mut Song) -> Token {
cur.prev(); // back 1char
let tmp_pos = cur.index;
match read_let_variable(cur, song) {
Some(res) => return res,
None => {},
};

}
cur.index = tmp_pos;
let mut cmd = cur.get_word();
// Systemの場合は"."に続く
if cmd == "System" || cmd == "SYSTEM" {
if cur.eq_char('.') { cur.next(); cmd.push('.'); }
cmd = "System".to_string(); // convert "SYSTEM" to "System"
if cur.eq_char('.') { cur.next(); cmd.push('.'); }
cmd.push_str(&cur.get_word());
}

Expand Down Expand Up @@ -255,6 +235,36 @@ fn read_upper_command(cur: &mut TokenCursor, song: &mut Song, ch: char) -> Token
return Token::new_empty(&cmd);
}

fn read_let_variable(cur: &mut TokenCursor, song: &mut Song) -> Option<Token> {
let cur_pos = cur.index;
let ch = cur.peek_n(0);
let cmd = cur.get_word();

// macro define?
if ch == '#' {
cur.skip_space();
if cur.eq_char('=') { // DEFINE MACRO
cur.index = cur_pos;
return Some(read_def_str(cur, song));
}
}

// variables?
match song.variables.get(&cmd) {
Some(sval) => {
cur.skip_space();
// set varable?
if cur.eq_char('=') {
cur.index = cur_pos;
return Some(read_def_str(cur, song));
}
// get variable
return Some(read_variables(cur, song, &cmd, sval.clone()));
},
None => {},
};
None
}

fn read_variables(cur: &mut TokenCursor, song: &mut Song, name: &str, sval: SValue) -> Token {
match sval {
Expand Down

0 comments on commit f318752

Please sign in to comment.