summaryrefslogtreecommitdiff
path: root/src/mml_composemusic_mcp/ir.py
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-12 18:28:50 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-12 18:28:50 +0900
commit3d06bee12a26bc55cd73b1494e4d008a8098f6f5 (patch)
treedd13a8f3fcd9d6dbf74d6406bfaa8894895af0ce /src/mml_composemusic_mcp/ir.py
parentbf36a773918959eeb6ffe7dae2fb8b0874438eb4 (diff)
feat: MML拡張合成とNTSC 2A03準拠のIR v2音源を実装
- エンベロープ、LFO、ビブラート、グライドのグローバル定義表を追加 - ppmckおよびPyxelの拡張コマンドを音声合成へ反映 - 2A03のPulseデューティ列、Triangle DAC、Noise LFSR、Sweepを実装 - APUタイマーに基づく周波数量子化と非線形ミキサを追加 - 途中テンポ変更、拡張コマンドの検証、トラック外定義に対応 - APU規格、拡張合成、IR v2のテストを追加 - プロジェクト独自のppmck拡張仕様と対応範囲を文書化
Diffstat (limited to 'src/mml_composemusic_mcp/ir.py')
-rw-r--r--src/mml_composemusic_mcp/ir.py18
1 files changed, 17 insertions, 1 deletions
diff --git a/src/mml_composemusic_mcp/ir.py b/src/mml_composemusic_mcp/ir.py
index 4dd7978..d9a2f93 100644
--- a/src/mml_composemusic_mcp/ir.py
+++ b/src/mml_composemusic_mcp/ir.py
@@ -44,6 +44,7 @@ class ErrorCode(Enum):
SEMANTIC_EMPTY_TRACK = "SEMANTIC_EMPTY_TRACK"
SEMANTIC_OUTSIDE_TRACK = "SEMANTIC_OUTSIDE_TRACK"
SEMANTIC_UNDEFINED_REFERENCE = "SEMANTIC_UNDEFINED_REFERENCE"
+ SEMANTIC_DUPLICATE_DEFINITION = "SEMANTIC_DUPLICATE_DEFINITION"
SEMANTIC_UNSUPPORTED_FEATURE = "SEMANTIC_UNSUPPORTED_FEATURE"
# --- Runtime errors (Synthesizer phase) ---
@@ -279,9 +280,22 @@ class ChannelSequence:
@dataclass
class NoteSequence:
- version: str = "1.0"
+ version: str = "2.0"
bpm: int = 120
ticks_per_quarter: int = 192
+ mode: str = "ppmck"
+ definitions: dict[str, dict[int, Any]] = field(
+ default_factory=lambda: {
+ "volume_envelopes": {},
+ "duty_envelopes": {},
+ "pitch_envelopes": {},
+ "note_envelopes": {},
+ "lfos": {},
+ "envelopes": {},
+ "vibratos": {},
+ "glides": {},
+ }
+ )
channels: dict[str, ChannelSequence] = field(
default_factory=lambda: {
"Pulse1": ChannelSequence("pulse"),
@@ -296,6 +310,8 @@ class NoteSequence:
"version": self.version,
"bpm": self.bpm,
"ticks_per_quarter": self.ticks_per_quarter,
+ "mode": self.mode,
+ "definitions": self.definitions,
"channels": {k: v.to_dict() for k, v in self.channels.items()},
}