Windows / Visual Studio 2022 / C++17。NESの映像から作ったRF受信ノイズ風の信号を、エミュレータ音声へリアルタイムに合成する実験アプリです。
アイコン画面を砂嵐にし、日本版ファミコン本体がうっすら見える絵へ変更しました。 接触時定数は走査線ごとに計算されるため、1フレーム未満でも有効です。許容範囲は0.1〜100msです。 接触状態の減衰で極小の非正規化数が残ることによる演算負荷を対策しました。RF計算の間だけx64/SSE2のFTZ/DAZを有効にし、終了時に元の設定へ戻します。接触状態が1e-20未満へ減衰した場合もゼロへ収束させます。 実際に処理が間に合わない場合にエミュレーション速度を落とす従来の動作は残ります。Windows実機の改善効果は未確認です。
Alt+Enterで現在のモニターを使うボーダーレス全画面と通常表示を切り替えます。テレビ本体の操作部も表示します。通常表示の位置・サイズを復元し、全画面で終了しても次回は通常表示で起動します。 テレビ電源は前回OFFでも必ずONで起動します。暖機演出は継続します。 放電のサー音は従来の約10倍の振幅へ増幅しました。短い破裂音は満充電直後で平均約4回/秒、放電につれて発生が少なくなるよう調整しました。ステレオの広がりと音量設定は維持します。
CRTシェーダーのexp式に閉じ括弧が不足していたため、X3000/X3013でコンパイルに失敗していました。式を修正しました。 VS2022/CMakeのReleaseリンクに/DEBUG:NONEを指定し、実行ファイルのCodeView情報にPDBのビルド環境パスが残らないようにしました。Debugビルドのデバッグ情報は維持します。 シェーダー適用確認時はSettingsの手動CPU切替をOFFにしてください。
Settings →「ブラウン管演出をCPU処理に切り替え」で実行中に変更できます。初期値はGPU、選択はINIへ保存します。 状態欄にGPU/WARPとCRT処理方式を表示します。「描画情報」にはアダプター名、Feature Level、シェーダーの成否と自動退避理由を表示します。 CPU切替はブラウン管演出の計算部分のみです。RF合成は常にCPU、画面転送はD3D11の基本シェーダーを使用します。 対応範囲は従来と同じFeature Level 10.0以上・Shader Model 4.0です。GT 710の公表仕様(FL11.0)はこの範囲内です。 通常の描画待機を5ms周期の待機可能タイマーへ変更し、通常メッセージ処理と併用します。タイマー精度を要求し、終了時に解除します。タイマー生成失敗時は従来方式に戻ります。 シェーダーを最適化付きでコンパイルし、ガラス形状の8乗計算を乗算へ変更しました。
途切れが残る場合は、従来設定(RF4・音声4・定期表示)でCPU切替のON/OFFを比較してください。GPU負荷はウインドウ縮小、動画側負荷は隣接動画を停止して切り分けできます。 WARP表示ならGPUではなくソフトウェア描画です。startup.logと描画情報を確認してください。 RF処理時間が約16.6msを継続して超える場合、約60fpsの処理に間に合っていません。CPU切替やバッファ増加のみで解決するとは限りません。 GT 710実機の速度、途切れ解消、Windows上でのCPU切替は未検証です。
マウス操作したノブの破線枠を表示せず、キーボードでのフォーカス表示は維持します。 両ウインドウの状態文字列をダブルバッファ化し、同じ文字列での再描画を抑制しました。 隣接チャンネルの調整ラベル・ノブ・状態欄を、動画と左右端が揃った暗色パネルに統合しました。
Settings →「処理速度 / 表示遅延」でいつでも変更できます。
| 選択 | RF最大待機数 | 音声バッファ | 表示タイミング |
|---|---|---|---|
| 従来設定(初期値) | 4 | 4 | 定期更新 |
| 低遅延設定(v0.7.1相当) | 1 | 2 | 完成後即時 |
各値も個別に変更可能です。RF待機数は1〜4、音声バッファは2〜4、即時表示はON/OFFから選べます。 設定はEXE横のINIのPerformance節に保存・復元します。旧版のINIにこの節がなければ従来設定になります。 切替時は古い処理結果と音声キューを破棄するため、一時的に音が途切れる場合があります。ROMはリセットしません。 待機数を増やすと処理の重なりや実行時間の揺らぎに余裕を持たせられますが、表示遅延は増えます。RF合成自体の計算量・画質は変更しません。 Windows実機での速度・遅延は未測定です。
右側RF調整部の列幅を縮め、右端のラベルをパネル内に収めました。 キャビネットと項目名をメモリDCで描いてから一括転送し、既存のノブ描画と合わせてダブルバッファ化しました。値が変わっていないラベルの再描画も抑制しています。 RF処理の未消費フレームは最大1、ゲーム音声のキューは最大2に削減しました。完成した映像は次の定期描画を待たず表示します。追加操作は不要です。 処理性能が不足する環境では音切れや速度低下が起きる可能性があります。Windows実機での入力から表示までの遅延は未測定です。 1フレームのランアヘッドは試験実装しましたが、先読み後の状態復元が通常実行と一致しない回帰テスト結果のため、今回の配布には含めていません。
赤いキャビネット、暗色ベゼル、4:3の丸みを持つ画面、スピーカーグリルを持つ1980年代の家庭用テレビをイメージした外観です。特定メーカーの製品複製ではありません。
| 操作部 | 操作 / 効果 |
|---|---|
| 画面下「映像」 | コントラスト。円盤の下1/4程度が露出した調整器 |
| 画面下「明るさ」 | 黒レベルの加減 |
| 画面下「色合い」 | 色位相の回転 |
| 画面下「色の濃さ」 | 彩度 |
| 各調整器・RFノブ | 左右ドラッグ、またはホイールで増減 |
| 右上「電源 / 音量」 | 左右ドラッグ/ホイールで音量。下へドラッグでON、上へドラッグでOFF |
電源操作は縦方向へ約18ピクセル以上ドラッグしてください。操作開始時の移動方向で音量/電源を判別します。 RFの調整ノブはRF出力時のみ有効です。隣接動画の混信量も回転ノブになっています。 映像調整と音量は設定へ保存します。テレビ電源は常にONで起動し、冷えた状態から始まります。
テレビ電源はエミュレーターの停止とは独立しています。OFF中もゲームは進み、音声/映像の入力処理は継続します。 Spaceの一時停止やアプリ非アクティブ時の停止は従来どおりです。 ON時は温度に応じて数秒かけて映像が現れ、OFF時は縦方向が先に縮まり、中央へ収束しながら明るい残光が消えます。 途中でON/OFFを切り替えても温度・偏向・発光の状態をリセットしません。音声も電源に合わせてフェードします。 これらは連続状態による視覚・聴覚的な近似であり、特定のブラウン管回路の厳密な電気シミュレーションではありません。 ブラウン管演出はD3D11ピクセルシェーダーで処理します。
混信用動画の候補と利用条件は docs/VIDEO_SOURCES.md を参照してください。
従来の簡易NES実装を、FCEUmm(libretro版)に置き換えました。CPU、PPU、APU、マッパー、拡張音源は同梱コアが処理します。Mapper 0限定を解除し、MMC1、UxROM、CNROM、MMC3、AxROM、VRC系など、FCEUmmが扱う多数のカートリッジに対応する構成です。個別ソフトの動作保証や全ROM対応を意味するものではありません。
.nes(iNES / NES 2.0)、.unf/.unif、.fdsの読み込み- PAL / NTSC等、コアが返すフレームレートで実行
- 2人分の標準NESコントローラー入力
- XInput / DirectInput、キーボードの割り当て変更・保存
- バッテリーRAMとFDSデータの保存・再読み込み
- ROMのドラッグ&ドロップ
- デジタル/RF切り替え、映像・音声連動の受信劣化モデルとリアルタイム調整
RF部分はNTSC型受信機の動作を近似するモデルです。RGBから合成映像を再構成し、FM音声の等価ベースバンド復調を行います。実機PPUの電圧やVHF搬送波、RF回路全体を再現するものではありません。
右パネル上部で「デジタル出力」または「RF出力」を選びます。 初回はデジタル出力です。映像と音声が同時に切り替わります。 デジタルではRF加工をバイパスします。テレビ側の映像調整・ブラウン管演出・音量/電源フェードは共通です。 RFでは下記項目をリアルタイム調整できます。
| 項目 | 主な効果 |
|---|---|
| 映像→音声の混入 | 画面内容・同期に応じた音声バズ |
| 音声ローパス | RF音声全体の高域減衰、雑音の角を丸める |
| 受信信号強度 / 同調ずれ | 映像の受信状態、音声復調のS/Nの変化 |
| 受信ノイズ | 映像の砂嵐、音声のヒス |
| 接触不良の頻度 | 映像・音声で共通する断続的な信号低下 |
| 接触変化の時定数 | 接触状態の変化を0.1~100msで緩やかにする |
| 反射・ゴースト / 反射遅延 | 遅延波による映像の二重像、混入音の変化 |
| 映像帯域 | 輪郭や色の帯域制限 |
| 水平ジッター | 走査線ごとの左右の揺れ |
| 水平ホールドずれ | 横方向の引き込みずれ・同期外れ |
| 垂直ホールドずれ | 上下方向のロール |
| 色位相の不安定さ | 色相の揺れ、受信不良時の色落ち |
| 同期回路→音声の漏れ | 同期状態・ホールドずれに応じた追加バズ |
「安定したRF」「映像由来のバズが強い」「接触不良」「同期不安定」のプリセットもあります。
プリセットを選ぶとRF出力へ切り替わります。これは効果を確認するための例で、特定の実機を測定した設定ではありません。
設定は実行ファイル横のNesRfAudioEmulator.iniに保存します。
一時停止中はゲームフレームの処理を止めるため、新しい映像効果は再開時に反映されます。
単に水平・垂直ホールドを変えて音声ピッチを変化させる処理はしていません。 同期回路からの漏れを0にした場合、受信機側のホールドずれだけでは音声を変えません。 接触不良・受信強度低下・同調ずれ等は共通経路のため、映像と音声の両方に影響します。
実装の詳細、不足していた点、近似範囲はRF_MODEL.mdを参照してください。 テストパターンによる見え方の例はRF_COMPARISON.pngです。
RF映像・音声合成を専用スレッドに移しました。UIスレッドはNES実行、入力、画面への転送、音声送出を担当します。 RFの処理待ちは最大4フレーム、XAudio2側の送出待ちは最大4ブロックです。 音声・映像の遅延を数フレーム程度許容して操作の引っ掛かりを減らします。 待ちが一杯になったらNESの実行を待たせ、遅延を無制限に蓄積したり音声を無作為に捨てたりしません。 CPU全体の処理能力が不足すれば実行速度は低下します。別スレッド化だけで総負荷がなくなるわけではありません。
色変換の重複を除き、Y/C分離の移動平均を更新式へ変更し、音声FIRは間引き後に必要なサンプルだけ計算します。 右パネルにはRFワーカーの処理時間と待機フレーム数を表示します。 通常利用はReleaseビルドを使用してください。
- メニュー
Settings > 隣接チャンネルの動画...、またはF4で別ウインドウを開きます。 - 「動画を開く / 再読込」でローカル動画ファイルを選択します。
- メイン側をRF出力へ切り替え、「混信を有効」をオンにします。
- 映像・音声の混信量と「上隣接 +6MHz / 下隣接 -6MHz」を調整します。
MP4/H.264/AAC、WMV等、Windows Media Foundationでデコードできる形式が対象です。 拡張子だけで対応が決まるわけではなく、OSに利用可能なデコーダーが必要です。 互換性を優先する場合は MP4 / H.264(8-bit YUV 4:2:0)/ AAC-LC を使用してください。 HEVC/H.265、AV1などはWindows側のデコーダー環境に依存し、MP4でも再生保証はありません。 0.4.0の「途中で形式が変わる動画には未対応です (0xC00D36B4)」は、アプリが形式更新通知を 一律拒否していたことによる表示でした。動画自体が非対応とは限りません。 0.4.1では開始時/途中の形式更新で解像度、行ストライド、音声レート/チャンネル数を再取得し、 必要に応じRGB32/PCM16への出力変換を再設定します。デコーダー自体が対応しない切り替えはエラーになります。 参考: https://learn.microsoft.com/en-us/windows/win32/medfound/supported-media-formats-in-media-foundation
「映像→音声」はRF出力時に有効です。0.4.1では検波後の映像漏れも加え、明るい画面と暗い画面で 垂直帰線期間とのレベル差に由来する低いバズ音が変わるようにしました。 確認時は隣接動画を停止し、RF出力でノイズ・接触不良を下げ、混入量を0から増やしてください。 YouTubeページやURLの直接取り込み、ブラウザー埋め込みは未実装です。
動画デコードも別スレッドです。デコード済み映像は256×240の放送フレームへアスペクト比を保持して縮小します。 動画の音声は48kHzへ補間し、RF側の音声漏話モデルへ送ります。 元音声の単独モニター再生は行いません。デジタルモードでは動画を開いていても混信しません。
NES再生中はゲームの進行に合わせて動画も進めます。NES未読込時もプレビュー映像は再生しますが、混信音声は出力しません。 一時停止中・入力設定中・アプリ全体が非アクティブな間は動画も停止します。 動画ウインドウの操作中はゲーム実行を継続しますが、ゲームへの入力はメインウインドウに戻して行ってください。 終端では自動的に先頭へ戻ってループ再生します。映像と音声の時刻を次の周回へつなぎます。 デコーダーのシーク速度によって境界に一瞬の静止や無音が生じることがあり、完全なギャップレス再生は保証しません。 手動シーク、再生リストは未実装です。動画ファイルと混信量は設定に保存します。
映像の混信は隣接AM映像搬送波の漏れを含む近似です。音声は選択度不足による漏話の近似で、 隣接チャンネルのFM搬送波まで高周波で完全に計算するものではありません。 上/下隣接の抑圧率も簡略化した値で、特定のチューナーを実測した特性ではありません。 高解像度動画のデコードは追加負荷になるので、処理が厳しい場合は低解像度版を使ってください。
必要なもの: Visual Studio 2022の「C++によるデスクトップ開発」、MSVC v143、Windows 10/11 SDK。
NesRfAudioEmulator.slnを開き、x64 / ReleaseまたはDebugでビルドします。
アプリと静的ライブラリfceummの2プロジェクト構成です。アプリ側が起動プロジェクトです。
第三者ソースは同梱しているため、ビルド時のダウンロードは不要です。
通常のコマンドプロンプトで、展開先に移動して実行できます。
build_cmake_vs2022.batPATH上のCMake、VS2022付属CMake、通常のインストール先にあるCMakeを検出します。 CMakeがなければ、同梱ソリューションをMSBuildでビルドします。 CMakeを使う場合の必要バージョンは3.21以上です。 VS Installerの登録情報も参照するため、別ドライブへのVS2022インストールも検出対象です。 vswhere.exeは使用しません。
自動検出できない場合は、VS2022のインストール先を第2引数で指定してください。
build_cmake_vs2022.bat Release "D:\Microsoft Visual Studio\2022\Community"上記パスは例です。Common7、VC、MSBuildが入っている実際のフォルダーを指定します。
環境変数VS2022_ROOTでも指定できます。CMAKE_EXEにはcmake.exeのフルパスを指定できます。
CMake構成後にVSの場所を変更した場合、既存キャッシュとの不一致が出たら
build-cmakeを別名に退避してから再実行してください。
CMakeを使わず、MSBuildを直接使うバッチも同梱しています。
build_vs2022.batどちらもDebug版は第1引数をDebugにします。
生成先は共通でbuild-cmake\Release\NesRfAudioEmulator.exeです。
バッチはWindows標準のPowerShellで検出処理を行います。PowerShellの実行を組織ポリシーで
禁止している環境では、VSでソリューションを開いてビルドしてください。
CMakeを直接使う場合:
cmake -S . -B build-cmake -G "Visual Studio 17 2022" -A x64
cmake --build build-cmake --config Release --parallelFile > Open ROM...またはドラッグ&ドロップで読み込みます。ZIP内のROMは展開してから読み込んでください。
ROMとBIOSは同梱していません。
FDSには、利用者が用意したBIOSを次の場所にdisksys.romとして配置してください:
実行ファイルと同じフォルダーの disksys.rom
バッテリーRAM/FDSのデータはROMと同じ場所の元のファイル名.nes.sav等に保存します。
約30秒ごと、ROM切り替え時、終了時に保存します。直前の保存は.sav.bakに残します。
ROMフォルダーには書き込み権限が必要です。セーブ形式は本アプリでの利用を想定しています。
Settings > Controllers / Keys...(F3)を開いてください。
- Player 1 / Player 2を選ぶ。
- 使用する機器、Auto、またはKeyboard onlyを選ぶ。
- Keyboard列またはGamepad列の変更したいボタンをクリック。
- キー・ボタンを押すか、十字キー・スティックを操作する。
- Saveで両プレイヤーの設定を保存する。
Escは割り当て待ちのキャンセル、Deleteは選択中の割り当て解除です。 Cancelやウインドウを閉じた場合は、未保存の編集を破棄します。 Refresh devicesで再検出できます。通常動作中も約2秒ごとに接続を再確認します。
設定保存先: 実行ファイル横のNesRfAudioEmulator.ini
- XInput: Xbox系およびWindowsでXInputとして認識される機器。4スロットから選択可能。
- DirectInput: Windowsでゲームコントローラーとして列挙されるUSB/Bluetoothパッド、レトロパッド変換器など。
- DirectInputの最大128ボタン、8軸の正負方向、4組のPOVを割り当て可能。
- XInputのボタン、左右トリガー、左右スティック方向を割り当て可能。
- キーボードは選択機器と併用可能。1P・2Pを別々に設定。
PlayStation系・Switch系などは、接続方式やドライバーによってDirectInput/XInputとして認識される範囲で利用できます。独自HIDプロトコルを直接扱う実装ではないため、すべての製品・接続方式を保証するものではありません。
AutoはXInput接続時にXInputを優先し、その中では最後に操作した機器を使います。XInputがない場合はDirectInput側の最後に操作した機器を使います。XInput機器がDirectInputにも重複表示される場合があります。2人プレイ時はそれぞれに機器を明示指定してください。
DirectInputは製品ごとにボタン番号や軸が異なるため、初回に割り当ててください。設定はプレイヤー単位で、機種ごとの複数プロファイルではありません。
| NES操作 | 1Pキーボード | 2Pキーボード | XInput |
|---|---|---|---|
| A | Z | G | A / Button 1 |
| B | X | H | B / Button 2 |
| SELECT | 右Shift | R | Back / Button 5 |
| START | Enter | T | Start / Button 6 |
| 方向 | 矢印キー | WASD | 十字キー+左スティック |
| FDS面選択 | F6 | 未設定 | LB / Button 7 |
| FDS挿入・排出 | F7 | 未設定 | RB / Button 8 |
| VSコイン | F8 | 未設定 | 右トリガー / Button 16 |
FDSは必要に応じて排出→面選択→挿入を行います。FDS/VS操作は1P側を使ってください。 F2:リセット、F3:設定、Space:一時停止、Ctrl+O:ROMを開く。 ゲーム操作に割り当てたキーは同じキーのショートカットより優先します。メニューからは常に操作できます。 非アクティブ時、設定中、ROM選択中はゲーム実行を停止します。
- FCEUmmが未対応のマッパーやタイミング依存ソフトは動作しない可能性があります。
- PC側パッドをNESの標準2コントローラーに割り当てます。光線銃、ファミリーベーシックキーボード、マット、4人アダプター等の特殊周辺機器UIは未実装です。
- FCEUmm側のHDパック・NTSC映像フィルターは無効です。RF処理はアプリ側の独立モジュールで行います。
- RFはNTSC型の近似です。PAL/Dendyではコアのフレームレート・走査線数に追従しますが、PALの色位相交替や50µsディエンファシスは未実装です。
- Linux上で同梱コアとC++接続部をコンパイルし、自作ROMによる統合テストを実施しています。詳細は
VALIDATION.md参照。 - 実際のWindows/MSVC実行と、物理コントローラーの動作確認はこの環境ではできていません。
本版はFCEUmmを静的リンクするため、GPL-2.0-or-laterとして配布します。
LICENSE.txtとTHIRD_PARTY_NOTICES.mdを参照してください。
第三者ファイルの著作権・ライセンス表記は各ファイルに保持しています。
描画と音声のエラーを分け、失敗したAPI/段階とHRESULTを表示します。
シェーダーのコンパイル失敗時はコンパイラーのメッセージを記録します。
ログ: 実行ファイル横のstartup.log(UTF-8、追記)。
ブラウン管シェーダーが使えない場合は基本シェーダーとCPUブラウン管演出へ自動切り替えます。
色調整・暖機・収束は維持しますが、CPU負荷が増え、演出の解像度は256×240になります。
GPUデバイスが生成できない場合はD3D11 WARPを試します。WARPもCPU処理なので負荷が増えます。
音声デバイスの初期化失敗時は、失敗段階を表示して終了します。
0.5.0の一括メッセージからは原因を特定できないため、今回の報告の実機原因は未確定です。
右上の「本体動作音」と「放電音」で個別に調整できます。0で無効。設定は保存されます。 本体動作音は安定時に約15.734kHzとなる小さな高音です。初期値15%。放電音は初期値25%。 スピーカー音量・ゲーム音声とは別経路なので、音量0・ゲーム一時停止・ROM未読込でも電源に従って鳴ります。 消灯すると動作音が止まり、通電時間に応じた放電音が減衰します。再点灯すると放電音は早く収まります。 放電音はノイズと不規則な短いパルスによる演出で、特定機種の実測音や厳密な静電放電計算ではありません。 高音の聞こえ方は再生機器や聴力に依存します。
本体動作音はON時に約8.5kHzから15.734kHzへ上昇し、OFF時は下降しながら消えます。 映像の水平偏向幅と同じ連続状態を使い、ONは時定数0.22秒、OFFは0.32秒で追従します。 音程は偏向幅の平方根に対応させ、音量も偏向幅とともに減衰します。約1秒程度でほぼ変化を終えます。 電源を途中反転しても音程/位相をリセットしません。描画タイマー間の段差は音声サンプル単位で平滑化します。 これは映像と聴感の整合を狙った演出であり、8.5kHzという下限や変化曲線は実機測定値ではありません。 安定動作中は15.734kHz付近へ収束します。
- 調整項目名は小さいフォントで1行中央揃え。数値はノブの上部に小さく重ねて表示します。
- リサイズ時に背景・ラベル・ノブを再描画し、右側のノブ行間も高さに応じて調整します。
- 放電音は左右の位相特性を変えるオールパス処理でステレオ化。本体の高周波音は中央です。
NesRfAudioEmulator.iniを実行ファイルと同じ場所へ保存します。bin内のEXEを使う場合はbin内です。- RF/画質/音量/電源/一時停止、キーとコントローラー割当、メインと動画ウインドウの位置・サイズ・最大化、ROMと動画のパス、動画窓の開閉、混信量と隣接チャンネルを保存・復元します。
- ROMは起動し直し、動画は先頭から再生します。ゲームの途中状態や動画再生位置の保存ではありません。
- 設定ファイルが初めて作成されるときは、旧AppData内のRF/入力設定があれば引き継ぎます。
- 移動・削除されたファイルは自動では開きません。通常の終了操作でウインドウ状態を保存します。
- FDS BIOSは実行ファイルと同じフォルダーへ置いてください。ROMのセーブデータは従来どおりROM横です。
bin/NesRfAudioEmulator.exe は今回のソースをZig/Clang 0.13.0でWindows x64向けにビルドしたものです。
Windows実機での実行確認済みという意味ではありません。詳細は bin/BUILD_INFO.txt を参照してください。
VS2022で自分でビルドする従来の方法も引き続き利用できます。