From 9837002c245306b6d15366172cd7fed0f7ebe6dd Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Wed, 15 Jul 2026 20:24:56 +0900 Subject: test: MML音階と2A02波形出力の適合テストを追加 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C4〜C5のMIDI音番号とtimer値を検証 - Pulse、TriangleのPCM・WAV周波数測定を追加 - Noise periodとLFSRの適合テストを追加 - 2A02 timerのclamp・mute境界を検証 - Noise計算をテスト可能な純粋関数へ分離 - 音階テスト資料を実装クロックへ同期 --- src/mml_composemusic_mcp/synthesizer.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src/mml_composemusic_mcp') diff --git a/src/mml_composemusic_mcp/synthesizer.py b/src/mml_composemusic_mcp/synthesizer.py index ae98267..a289a1e 100644 --- a/src/mml_composemusic_mcp/synthesizer.py +++ b/src/mml_composemusic_mcp/synthesizer.py @@ -115,6 +115,18 @@ def noise_period_to_rate( return CPU_CLOCK / NOISE_PERIODS[period & 0x0F] +def _noise_period_index(note_number: int) -> int: + """Map the semantic note representation to the 2A03 noise period index.""" + return 8 if note_number == 0 else max(0, min(15, 15 - note_number // 8)) + + +def _clock_noise_lfsr(lfsr: int, short_mode: bool) -> int: + """Advance the 15-bit 2A03 noise shift register by one timer clock.""" + tap = 6 if short_mode else 1 + feedback = (lfsr & 1) ^ ((lfsr >> tap) & 1) + return (lfsr >> 1) | (feedback << 14) + + def apu_mix( pulse1: np.ndarray, pulse2: np.ndarray, triangle: np.ndarray, noise: np.ndarray ) -> np.ndarray: @@ -469,18 +481,14 @@ class ChannelSynthesizer: self.wave[indices[gate_index:]] = self.wave[indices[gate_index - 1]] def _render_noise(self, indices, volumes, note): - period_index = ( - 8 if note.note_number == 0 else max(0, min(15, 15 - note.note_number // 8)) - ) + period_index = _noise_period_index(note.note_number) cycles_per_sample = CPU_CLOCK / (NOISE_PERIODS[period_index] * self.sample_rate) accumulator = self._noise_accumulator lfsr = self._noise_lfsr for j, output_index in enumerate(indices): accumulator += cycles_per_sample for _ in range(int(accumulator)): - tap = 6 if self.noise_mode else 1 - feedback = (lfsr & 1) ^ ((lfsr >> tap) & 1) - lfsr = (lfsr >> 1) | (feedback << 14) + lfsr = _clock_noise_lfsr(lfsr, bool(self.noise_mode)) accumulator %= 1.0 self.wave[output_index] = 0 if lfsr & 1 else max(0, min(15, volumes[j])) self._noise_accumulator = accumulator -- cgit v1.2.3