summaryrefslogtreecommitdiff
path: root/src/mml_composemusic_mcp/semantic_base.py
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-12 17:58:19 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-12 17:59:16 +0900
commitbf36a773918959eeb6ffe7dae2fb8b0874438eb4 (patch)
treeda7ff0037ea923fea255d2ed69ed2fb51395d9b9 /src/mml_composemusic_mcp/semantic_base.py
parentf1cd4d7d16f6e75a50bb0c587c0f759f7cf710cd (diff)
feat(ppmck): mckc準拠の構文拡張とIR保持コマンド追加
- @をデューティ比、qをクオンタイズに修正(mckc原本準拠) - ^タイ、Dディチューン、sスイープ、v+/v-相対音量を追加 - @v/@@/@MP/@EP/@EN エンベロープ・LFO系を構文解析してIR保持 - 上記IR保持コマンドは合成未対応を SEMANTIC_UNSUPPORTED_FEATURE で警告 - Design.md / MML_BNF.md を更新 - 全200テスト + ruff チェック通過
Diffstat (limited to 'src/mml_composemusic_mcp/semantic_base.py')
-rw-r--r--src/mml_composemusic_mcp/semantic_base.py111
1 files changed, 108 insertions, 3 deletions
diff --git a/src/mml_composemusic_mcp/semantic_base.py b/src/mml_composemusic_mcp/semantic_base.py
index 0318a84..8b27e89 100644
--- a/src/mml_composemusic_mcp/semantic_base.py
+++ b/src/mml_composemusic_mcp/semantic_base.py
@@ -5,23 +5,40 @@ from dataclasses import dataclass, field
from .ast_nodes import (
ASTNode,
BarStmt,
+ DetuneCmdStmt,
DetuneStmt,
+ DutyEnvelopeDefStmt,
+ DutyEnvelopeUseStmt,
DutyStmt,
- EnvelopeDefStmt,
ExtCmdStmt,
GateTimeStmt,
LengthStmt,
+ LfoDefStmt,
+ LfoOffStmt,
+ LfoUseStmt,
+ NoteEnvDefStmt,
+ NoteEnvOffStmt,
+ NoteEnvUseStmt,
NoteStmt,
OctaveStmt,
+ PitchEnvDefStmt,
+ PitchEnvOffStmt,
+ PitchEnvUseStmt,
Program,
+ QuantizeStmt,
+ RelativeVolumeStmt,
RepeatEndStmt,
RepeatStartStmt,
RestStmt,
Statement,
+ SweepStmt,
TempoStmt,
+ TieCmdStmt,
TieStmt,
Track,
TransposeStmt,
+ VolumeEnvelopeDefStmt,
+ VolumeEnvelopeUseStmt,
VolumeStmt,
)
from .ir import (
@@ -134,8 +151,16 @@ class SemanticAnalyzer:
self._analyze_transpose(stmt)
elif isinstance(stmt, DetuneStmt):
self._analyze_detune(stmt)
+ elif isinstance(stmt, QuantizeStmt):
+ self._analyze_quantize(stmt)
elif isinstance(stmt, TieStmt):
self._analyze_tie(stmt)
+ elif isinstance(stmt, TieCmdStmt):
+ self._analyze_tie_cmd(stmt)
+ elif isinstance(stmt, DetuneCmdStmt):
+ self._analyze_detune_cmd(stmt)
+ elif isinstance(stmt, RelativeVolumeStmt):
+ self._analyze_relative_volume(stmt)
elif isinstance(stmt, RepeatStartStmt):
self._analyze_repeat_start(stmt)
elif isinstance(stmt, RepeatEndStmt):
@@ -144,8 +169,34 @@ class SemanticAnalyzer:
pass
elif isinstance(stmt, ExtCmdStmt):
self._analyze_ext_cmd(stmt)
- elif isinstance(stmt, EnvelopeDefStmt):
- self._analyze_stage2(stmt)
+ elif isinstance(stmt, VolumeEnvelopeUseStmt):
+ self._analyze_vol_env_use(stmt)
+ elif isinstance(stmt, VolumeEnvelopeDefStmt):
+ self._analyze_vol_env_def(stmt)
+ elif isinstance(stmt, DutyEnvelopeDefStmt):
+ self._analyze_duty_env_def(stmt)
+ elif isinstance(stmt, DutyEnvelopeUseStmt):
+ self._analyze_duty_env_use(stmt)
+ elif isinstance(stmt, LfoDefStmt):
+ self._analyze_lfo_def(stmt)
+ elif isinstance(stmt, LfoUseStmt):
+ self._analyze_lfo_use(stmt)
+ elif isinstance(stmt, LfoOffStmt):
+ self._analyze_lfo_off(stmt)
+ elif isinstance(stmt, PitchEnvDefStmt):
+ self._analyze_pitch_env_def(stmt)
+ elif isinstance(stmt, PitchEnvUseStmt):
+ self._analyze_pitch_env_use(stmt)
+ elif isinstance(stmt, PitchEnvOffStmt):
+ self._analyze_pitch_env_off(stmt)
+ elif isinstance(stmt, NoteEnvDefStmt):
+ self._analyze_note_env_def(stmt)
+ elif isinstance(stmt, NoteEnvUseStmt):
+ self._analyze_note_env_use(stmt)
+ elif isinstance(stmt, NoteEnvOffStmt):
+ self._analyze_note_env_off(stmt)
+ elif isinstance(stmt, SweepStmt):
+ self._analyze_sweep(stmt)
else:
self._analyze_stage2(stmt)
@@ -177,9 +228,21 @@ class SemanticAnalyzer:
def _analyze_gate_time(self, stmt: GateTimeStmt) -> None:
raise NotImplementedError
+ def _analyze_quantize(self, stmt: QuantizeStmt) -> None:
+ raise NotImplementedError
+
def _analyze_tie(self, stmt: TieStmt) -> None:
raise NotImplementedError
+ def _analyze_tie_cmd(self, stmt: TieCmdStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_detune_cmd(self, stmt: DetuneCmdStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_relative_volume(self, stmt: RelativeVolumeStmt) -> None:
+ raise NotImplementedError
+
def _analyze_repeat_start(self, stmt: RepeatStartStmt) -> None:
raise NotImplementedError
@@ -189,6 +252,48 @@ class SemanticAnalyzer:
def _analyze_ext_cmd(self, stmt: ExtCmdStmt) -> None:
raise NotImplementedError
+ def _analyze_vol_env_use(self, stmt: VolumeEnvelopeUseStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_vol_env_def(self, stmt: VolumeEnvelopeDefStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_duty_env_def(self, stmt: DutyEnvelopeDefStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_duty_env_use(self, stmt: DutyEnvelopeUseStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_lfo_def(self, stmt: LfoDefStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_lfo_use(self, stmt: LfoUseStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_lfo_off(self, stmt: LfoOffStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_pitch_env_def(self, stmt: PitchEnvDefStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_pitch_env_use(self, stmt: PitchEnvUseStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_pitch_env_off(self, stmt: PitchEnvOffStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_note_env_def(self, stmt: NoteEnvDefStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_note_env_use(self, stmt: NoteEnvUseStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_note_env_off(self, stmt: NoteEnvOffStmt) -> None:
+ raise NotImplementedError
+
+ def _analyze_sweep(self, stmt: SweepStmt) -> None:
+ raise NotImplementedError
+
def _analyze_stage2(self, stmt: ASTNode) -> None:
self.ctx.add_error(
code=ErrorCode.SEMANTIC_UNSUPPORTED_FEATURE,