コンソールの音を計画する
N7 の計画。作業の前に書かれた。
N6 のときと同じように、コードより前に書いた (2026-09-06)。スケッチ (docs/nes-end-to-end-v0_2.md、第 3 節、N7) が求めているのは、2A03 の AD1 と AD2 の流れを書き下ろしのミキサーへ入れること、抵抗と RC の定数を回路図から取ること、そのあと 48 kHz へのリサンプラだ。ゲートは、既知のレジスタプログラムに対するスコープの AUDIO_OUT 記録を、コンソールのものと同じリサンプリングを通した波形として比べることで、許容は測る前に述べる。
すでにあるもの
- 2A03 のラングは、CPU の半ステップごとに五つの出力コードを差し出す (
Apu::codes: 矩形二つ、三角、4 ビットのノイズ、7 ビットの DMC の水準)。APU のゲートでラング 0 自身のsq0_out..pcm_outノードに押さえてある。コンソールは CPU の半サイクルごとに一度これを進める。 - DAC の表 (
2a03: v2a03-sim/src/mixer.rs) は nesdev wiki の APU Mixer ページであり、書き下ろしとして札が付いている: pulse と tnd の二群、それぞれ抵抗へ流し込む電流源 DAC で、定数はあのページのもの。A3 の最初の音はこれを通して混ざった。 - NES-001 の回路図 (RetroTechCollection の NES-001.pdf、2026-09-06 に読んだ)、その音声段を図面から読む: AD1 と AD2 はそれぞれ 100 オーム (R4、R3) でプルダウンされている。AD1 は R7 20K を通り、AD2 は R8 12K を通り、カートリッジの AUX_AUDIO_IN は R9 20K を通って、一つのノードへ入る。そのノードから C23 1 uF が U9E へ入る。U9E は 74HC04 のインバータで、出力から入力への R6 47K によって線形に保たれ、そこに C21 220 pF が並列に入る。C20 220 pF は出力から接地へ。出力は AUX_AUDIO_OUT であり、FC1 39 uH と C4 0.01 uF を通って AUDIO_OUT になる。wiki の二つの群の定数はすでに 20/12 の比になっている (159.79/95.88) ので、表の「pulse_out + tnd_out」は基板の加算抵抗で重みを付けた二つのピンであり、どちらにもある「+100」は R3/R4 だ。
- blargg の apu_mixer ROM 群 (square、triangle、noise、dmc: それぞれ一つのチャンネルと DMC の逆波形を鳴らすので、正しいミキサーなら二つの基準ビープの間でほぼ無音まで打ち消す) と、同じ四つの ROM を実機で録った彼の録音 (mp3)。nes-test-roms のチェックアウトの中にある。この録音はこのリポジトリが作ったのではないミキサーの実機測定だ。絶対利得は不明だが、それぞれの中の残差とビープの比は不明ではない。
- AUDIO_OUT のスコープ記録は無い。スケッチの捕捉一覧がこれを抱えている (1 MSa/s で十分)。許容と位相合わせの記録も一緒に。
手順
-
DAC の表を、コンソールから手が届くところへ。 wiki の表は 2A03 リポジトリの依存物なしのクレート (
v2a03-dac) へ移り、v2a03-simが古い名前で再エクスポートするので A3 とその例はそのまま立つ。二度打ち込むものは何も無い。 -
コンソールを通る音。
nes-consoleがsoundを得る:Soundは CPU の半サイクルごとに APU のコードを受け取り (厳密なレート、39,375,000/11 Hz、副搬送波の周波数で半サイクルあたり 1 標本)、DAC の表を通して混ぜ、回路図が与えるままの NES-001 の段を通し、48 kHz へリサンプルする。その段は回路図の値から書き下ろされ、札が付く: 加算ノードのテブナン抵抗 (R7 と R8 の並列。音声のないカートリッジではカートリッジ入力は開放) と C23 が一次のハイパス、R6 と C21 が一次のローパス、インバータの閉ループ利得は表の単位の上で R6/R7 で符号は反転、ジャックの LC は音声より上なので省く。模型にしておらず、そう記録するもの: インバータの有限な開ループ利得、その電源レール、そして表の絶対ボルト (ベンチの記録が供給する一つの倍率)。リサンプラは、出力の厳密な有理時刻での窓付き sinc で、出力のナイキストより下で切る。run-romはWAV=out.wav(48 kHz、16 ビット、モノ) を得る。ゲート (
tests/sound.rs):- 段が回路図の算術を守る: 段を通した階段は R_thevenin と C23 の積で減衰し、R6 と C21 の角周波数より上の音は一次ぶんだけ減衰する。パーセントの精度で。これは実在する何かの測定ではない。上に書いた値にコードを押さえるので、気が変わったら表に出る。
- blargg のミキサー ROM が打ち消す。 四つの ROM をそれぞれ全長にわたってコンソールに通す。48 kHz の出力を、最初のビープ、テスト、二つ目のビープに、ROM 自身のシェルのタイミングで割る (各ビープの周りに無音 300 ms、音 300 ms、無音 300 ms)。許容は、いま述べる: テスト区間にわたって、出力の 100 ms 窓ごとの RMS はビープの RMS の最大 5 パーセント (DMC の水準の一段は、この表の値ではビープの約 2 パーセントなので、打ち消しがそれより良くなることはあり得ない。5 パーセントは非線形性に少しだけ余地を残し、それ以上は残さない)。そしてビープ自身はフルスケールの 20 パーセントより上なので、この比は小さな数字二つの比ではない。noise の ROM は設計上ノイズを出し入れするので、ビープのところと、音が無いこと (その窓ごとのスペクトルのピークが RMS の 5 パーセント未満) だけで押さえる。
MUTATE=1は代わりに wiki の線形近似を通して混ぜ、square か dmc の ROM が赤にならなければならない。 - その横に録音。 同じ比を blargg の各 ROM の mp3 から測り (ffmpeg で復号。無ければ名指しで SKIP)、コンソールのものの横に印字して、記録はするが押さえない: 録音は実物の段と実際の部屋とコーデックを抱えている。
-
報告 (
docs/n7-report.md): 回路図から読んだままの段、ROM ごとのゲートの数値、その横に録音の比、そしてベンチの項目: 同じ四つの ROM と blargg の apu_test の下での実機コンソールの AUDIO_OUT を、1 MSa/s 以上で、同じリサンプリングを通した波形として、倍率を一つだけ合わせて比べ、形をある許容に押さえる。その許容は、記録を取る前に報告が述べる。
N7 に入らないもの
実時間の音声出力と歩調合わせ (N8、シェルと一緒に)。wiki の 90 Hz と 440 Hz のハイパスの角周波数は、ピンと AUDIO_OUT の間の回路図には無い。それを作っているものはジャックより先 (RF モジュレータかテレビ受像機) にあり、ここでの段はジャックで止まる。スコープが入るのもそこだ。
ビルド時に nes/docs/n7-plan.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。