はじめに
自作ゲームエンジン(VGS-Zero)では VGS; Video Game Sound という独自形式の波形メモリ音源を搭載していますが、以前 NSF; NES Sound Format というファミコン音源ファイルの再生にも対応しました。
しかし、この NSF というのが若干厄介です。
NSF を再生するにはファミコンの CPU (RP2A03 という 6502 互換 CPU)のエミュレーションも必要なのため オーバーヘッドがかなり高い です。具体的には、裏でファミコンエミュレータを動かしているのと概ね等価 (PPUエミュレーションが無い分だけ軽い程度) のオーバーヘッドです。昨今のPCなら全く気にならないレベルではありますが...
そこで、NSF 再生機能を廃止して VGM; Video Game Music と呼ばれるチップチューン業界ではスタンダードな音源フォーマット形式へ移行することにしました。
VGMとは
VGM; Video Game Music は、対応するチップセット毎のレジスタ更新に必要な値(ポート、アドレス、数値など)とウェイト間隔などのシーケンス制御データのみで構成されるシンプルなデータ形式です。
Furnace や FamiStudio などのチップチューン業界ではデファクトスタンダード(※私見)なトラッカーや DAW でもエクスポート可能です。
VGS-Zero が対応するチップセット
VGS-Zero が初期段階で対応するチップセットは以下に絞りました。
- NES APU
- K052539 (SCC; KONAMI Sound Creative Chip)
- AY-3-8910 (PSG; Programmable Sound Generator)
- SN76489 (DCSG; Digital Complex Sound Generator)
従来の VGS-Zero では現状 RP2A03 標準音源(NES APU)と VRC6 の NSF の再生をサポートしていたのですが、VGM での VRC6 の扱いがドキュメント記載内容から今ひとつよく分からなかったので、代替として SCC をサポートすることにしました。(VRC6 と SCC は細かい違いがあるかもしれませんがだいたい同じという認識)
そして、SCC は一般的に PSG (AY-3-8910) と組み合わせて再生するものらしい(Furnace の examples がそうなっていた)ので、PSG にも対応しておくことにしました。
ついでに SG-1000, SEGA Master System, GameGear などで採用されている SN76489 (DCSG) にも対応しておきました。
将来的にはFM音源やGB音源などにも対応しようと思っています。
チップセットのエミュレーション実装
NES APU については、NSF 再生をした時に使った NSFPlayer の実装から CPU エミュレーションなどを削除するだけで対応できました。
他のエミュレータについては Digital Sound Antiques さんが GitHub で良い感じのエミュレータを公開されているので、それらを使わせて頂くことにしました。
- K052539: https://github.com/digital-sound-antiques/emu2212
- AY-3-8910: https://github.com/digital-sound-antiques/emu2149
- SN76489: https://github.com/digital-sound-antiques/emu76489
ちなみに NSFPlayer のソース流用部分は同じく Digital Sound Antiques さんが配布元なので、現状音源エミュレーションに関しては Digital Sound Antiques さんに頼り切りです。
リポジトリの分離独立
VGS-Zero は GPLv3 の OSS の関係で自作ゲームへソース流用したい方々にとって扱いにくいかと思われるので、NESとSCCのVGMドライバをより扱い易い MIT ライセンスのリポジトリに分離して公開しておきました。
上記を使うメリットは wav や ogg 形式にした場合と比較してゲームのデータサイズをかなり小さくすることができます。
参考までに sccvgm の example で公開している約1分の曲データをwav形式に変換した時のデータサイズは次の通り(およそ 65倍 の差)です。
Plain data size
vgm: 76,606 bytes
wav: 5,036,264 bytes (44100Hz 16bits 1chの場合)
VGM はデータ構成の仕組み上圧縮アルゴリズムとの相性がかなり良いため、GZIP で圧縮した場合は更に大きな差(およそ 538倍 の差)が生まれます。
GZIP compressed data size
vgm: 6,369 bytes
wav: 3,430,496 bytes (44100Hz 16bits 1chの場合)
デメリットとしてはデコードにそれなりのオーバーヘッドが掛かる点です。