From bf36a773918959eeb6ffe7dae2fb8b0874438eb4 Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Sun, 12 Jul 2026 17:58:19 +0900 Subject: feat(ppmck): mckc準拠の構文拡張とIR保持コマンド追加 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @をデューティ比、qをクオンタイズに修正(mckc原本準拠) - ^タイ、Dディチューン、sスイープ、v+/v-相対音量を追加 - @v/@@/@MP/@EP/@EN エンベロープ・LFO系を構文解析してIR保持 - 上記IR保持コマンドは合成未対応を SEMANTIC_UNSUPPORTED_FEATURE で警告 - Design.md / MML_BNF.md を更新 - 全200テスト + ruff チェック通過 --- tests/test_lexer.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'tests/test_lexer.py') diff --git a/tests/test_lexer.py b/tests/test_lexer.py index 64fa17c..1d7f8e7 100644 --- a/tests/test_lexer.py +++ b/tests/test_lexer.py @@ -4,12 +4,13 @@ from mml_composemusic_mcp.lexer import TokenType, tokenize def test_ppmck_tokens(): - source = "A t150 l8 o4 v15 q2\nc d e f" + source = "A t150 l8 o4 v15 @2\nc d e f" tokens = tokenize(source, "ppmck") types = [t.type for t in tokens] assert TokenType.TRACK_HEADER in types assert TokenType.TEMPO in types assert TokenType.NOTE in types + assert TokenType.DUTY in types def test_pyxel_tokens(): @@ -35,3 +36,74 @@ def test_ppmck_invalid_token(): def test_pyxel_invalid_token(): tokens = tokenize("0: T120 L4 O4 X C", "pyxel") assert any(t.type == TokenType.INVALID for t in tokens) + + +def test_ppmck_at_duty(): + tokens = tokenize("A @2 c", "ppmck") + assert any(t.type == TokenType.DUTY for t in tokens) + + +def test_ppmck_quantize(): + tokens = tokenize("A q4 c", "ppmck") + assert any(t.type == TokenType.QUANTIZE for t in tokens) + + +def test_ppmck_tie_cmd(): + tokens = tokenize("A c4 ^4", "ppmck") + assert any(t.type == TokenType.TIE_CMD for t in tokens) + + +def test_ppmck_detune(): + tokens = tokenize("A D10 c", "ppmck") + assert any(t.type == TokenType.DETUNE for t in tokens) + + +def test_ppmck_sweep(): + tokens = tokenize("A s1,2 c", "ppmck") + assert any(t.type == TokenType.SWEEP for t in tokens) + + +def test_ppmck_rel_vol(): + tokens = tokenize("A v+5 v-3 c", "ppmck") + assert any(t.type == TokenType.REL_VOL_UP for t in tokens) + assert any(t.type == TokenType.REL_VOL_DOWN for t in tokens) + + +def test_ppmck_vol_env(): + tokens = tokenize("A @v0 c", "ppmck") + assert any(t.type == TokenType.VOL_ENV for t in tokens) + + +def test_ppmck_vol_env_def(): + tokens = tokenize("@v0 = { 15, 10, | 5 }", "ppmck") + assert any(t.type == TokenType.VOL_ENV for t in tokens) + assert any(t.type == TokenType.BRACE_OPEN for t in tokens) + assert any(t.type == TokenType.BRACE_CLOSE for t in tokens) + + +def test_ppmck_lfo_def(): + tokens = tokenize("@MP0 = { 0, 10, 5, 0 }", "ppmck") + assert any(t.type == TokenType.LFO_DEF for t in tokens) + + +def test_ppmck_lfo_use_off(): + tokens = tokenize("A MP1 MPOF c", "ppmck") + assert any(t.type == TokenType.LFO_USE for t in tokens) + assert any(t.type == TokenType.LFO_OFF for t in tokens) + + +def test_ppmck_pitch_env(): + tokens = tokenize("A EP1 EPOF c", "ppmck") + assert any(t.type == TokenType.PITCH_ENV_USE for t in tokens) + assert any(t.type == TokenType.PITCH_ENV_OFF for t in tokens) + + +def test_ppmck_note_env(): + tokens = tokenize("A EN1 ENOF c", "ppmck") + assert any(t.type == TokenType.NOTE_ENV_USE for t in tokens) + assert any(t.type == TokenType.NOTE_ENV_OFF for t in tokens) + + +def test_ppmck_duty_env_use(): + tokens = tokenize("A @@0 c", "ppmck") + assert any(t.type == TokenType.DUTY_ENV_USE for t in tokens) -- cgit v1.2.3