diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-07-12 17:58:19 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-07-12 17:59:16 +0900 |
| commit | bf36a773918959eeb6ffe7dae2fb8b0874438eb4 (patch) | |
| tree | da7ff0037ea923fea255d2ed69ed2fb51395d9b9 /src/mml_composemusic_mcp/semantic_base.py | |
| parent | f1cd4d7d16f6e75a50bb0c587c0f759f7cf710cd (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.py | 111 |
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, |
