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 チェック通過 --- src/mml_composemusic_mcp/ast_nodes.py | 159 ++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 9 deletions(-) (limited to 'src/mml_composemusic_mcp/ast_nodes.py') diff --git a/src/mml_composemusic_mcp/ast_nodes.py b/src/mml_composemusic_mcp/ast_nodes.py index bc4fdc4..3341510 100644 --- a/src/mml_composemusic_mcp/ast_nodes.py +++ b/src/mml_composemusic_mcp/ast_nodes.py @@ -117,6 +117,13 @@ class DetuneStmt(ASTNode): value: int +@dataclass +class QuantizeStmt(ASTNode): + """ppmck quantize command (q1-q8).""" + + value: int + + @dataclass class TieStmt(ASTNode): """Tie/slur command (&).""" @@ -124,6 +131,27 @@ class TieStmt(ASTNode): target: NoteStmt | RestStmt | int | None = None +@dataclass +class TieCmdStmt(ASTNode): + """ppmck tie command (^). Extends duration, pitch from previous note.""" + + target: NoteStmt | int | None = None + + +@dataclass +class DetuneCmdStmt(ASTNode): + """ppmck detune command (D).""" + + value: int + + +@dataclass +class RelativeVolumeStmt(ASTNode): + """ppmck relative volume (v+num / v-num).""" + + delta: int # positive=up, negative=down + + @dataclass class RepeatStartStmt(ASTNode): """Start of repeat section ([).""" @@ -154,27 +182,124 @@ class ExtCmdStmt(ASTNode): params: list[int] = field(default_factory=list) -# --- Stage 2 statements (kept in AST but ignored by semantic analyzer) --- +# --- Envelope / LFO / vibrato statements (IR kept, synthesis warning) --- @dataclass -class CountLengthStmt(ASTNode): - """ppmck count length note (c%48).""" +class VolumeEnvelopeUseStmt(ASTNode): + """ppmck volume envelope use (@v).""" - note_name: str - accidental: int - count: int + slot: int + + +@dataclass +class VolumeEnvelopeDefStmt(ASTNode): + """ppmck volume envelope definition (@v = {...|...}).""" + + slot: int + points: list[int] = field(default_factory=list) + loop_points: list[int] = field(default_factory=list) + + +@dataclass +class DutyEnvelopeDefStmt(ASTNode): + """ppmck duty envelope definition (@ = {...|...}).""" + + slot: int + points: list[int] = field(default_factory=list) + loop_points: list[int] = field(default_factory=list) + + +@dataclass +class DutyEnvelopeUseStmt(ASTNode): + """ppmck duty envelope use (@@).""" + + slot: int + + +@dataclass +class LfoDefStmt(ASTNode): + """ppmck LFO definition (@MP = {p1,p2,p3,p4}).""" + + slot: int + delay: int + speed: int + depth: int + transition: int + + +@dataclass +class LfoUseStmt(ASTNode): + """ppmck LFO use (MP).""" + + slot: int + + +@dataclass +class LfoOffStmt(ASTNode): + """ppmck LFO off (MPOF).""" + + pass + + +@dataclass +class PitchEnvDefStmt(ASTNode): + """ppmck pitch envelope definition (@EP = {...|...}).""" + + slot: int + points: list[int] = field(default_factory=list) + loop_points: list[int] = field(default_factory=list) + + +@dataclass +class PitchEnvUseStmt(ASTNode): + """ppmck pitch envelope use (EP).""" + + slot: int + + +@dataclass +class PitchEnvOffStmt(ASTNode): + """ppmck pitch envelope off (EPOF).""" + + pass @dataclass -class EnvelopeDefStmt(ASTNode): - """ppmck envelope definition (@v0 = { ... }).""" +class NoteEnvDefStmt(ASTNode): + """ppmck note envelope definition (@EN = {...|...}).""" slot: int points: list[int] = field(default_factory=list) loop_points: list[int] = field(default_factory=list) +@dataclass +class NoteEnvUseStmt(ASTNode): + """ppmck note envelope use (EN).""" + + slot: int + + +@dataclass +class NoteEnvOffStmt(ASTNode): + """ppmck note envelope off (ENOF).""" + + pass + + +# --- Stage 2 statements (kept in AST but ignored by semantic analyzer) --- + + +@dataclass +class CountLengthStmt(ASTNode): + """ppmck count length note (c%48).""" + + note_name: str + accidental: int + count: int + + @dataclass class SweepStmt(ASTNode): """ppmck sweep command (s1,2).""" @@ -201,13 +326,29 @@ Statement = ( | GateTimeStmt | TransposeStmt | DetuneStmt + | QuantizeStmt | TieStmt + | TieCmdStmt + | DetuneCmdStmt + | RelativeVolumeStmt | RepeatStartStmt | RepeatEndStmt | BarStmt | ExtCmdStmt + | VolumeEnvelopeUseStmt + | VolumeEnvelopeDefStmt + | DutyEnvelopeDefStmt + | DutyEnvelopeUseStmt + | LfoDefStmt + | LfoUseStmt + | LfoOffStmt + | PitchEnvDefStmt + | PitchEnvUseStmt + | PitchEnvOffStmt + | NoteEnvDefStmt + | NoteEnvUseStmt + | NoteEnvOffStmt | CountLengthStmt - | EnvelopeDefStmt | SweepStmt | NoiseModeStmt ) -- cgit v1.2.3