NES on FPGA 14:16 2012/12/23

NSF Player on FPGA

 NSF Player on FPGAは、ノイズが少ない、タイミングずれが起きない、 複数の拡張音源チップを使用できるなどの特徴があります。 そしてなにより自作プレイヤで演奏することは、ただ演奏を聴くだけとはまた異なる醍醐味があります。 自作nsfプレイヤでの演奏は実に贅沢! 何が贅沢かってプレイヤを作るために時間を費やしてるからね…。

 実装のため、NSFフォーマットやアドレスマップなど、まずnsfspec.txtを参照しました。

PCからシリアルポートでNSFを送信

 NSFファイルは、SDフラッシュメモリカードから読み込むか、PC上からシリアルでUserRAMに転送します。 パラメタライザにより、各音源を初期化したのち演奏します。 最大同時発音数は30チャンネル。出力はCODECデバイスからスピーカーをレイジング。

_
▼ pAPU音源

 NES上の矩形波×2、三角波、ノイズ、DMCの5チャンネルですね。 これだけでも作りこみようではすんげえサウンドが展開されます。 FamicompoではClassical部門として開催されています。

  • お気に入りのNSFなど紹介します。
  • aibomb.nsf 「Artificial Intelligence Bomb」
    NARUTO氏。DMCによるドラムパートが音の厚みを作り出しています。 ファミコンサウンドここに極まれりってな感じでノリノリです。
  • da_smile.nsf
  • j219_1.nsf
  • yomayako.nsf 東方紅魔郷より「妖魔夜行」
    原曲はZUN氏。

_
▼ Nintendo MMC5音源

 矩形波チャンネルを2つ持つ。 しばしばAPUの矩形波チャンネルを補う役目として、 音の厚みを増したいとき、パートを増やしたいときなどに使われる。
 mmc5.txtによればそれこそAPUの矩形波とレジスタ並びも同じなので、 "apu/square_ch.h"ファイルをそのままinclude。 ただしスイープ機能は使用されないようだ。 フレームシーケンサについてはデフォルトの4ステップで使用しているが要調査。

  • 840.nsf 「Screw Breaker - gear Lv3」
    高音と低音でそれぞれ使用され、全体的なサウンドにしっかりと厚みが出ている。 GBAサウンドはNSFと相性が良いのか気分はドリアーップ!
  • top_btl.nsf 「TAKE UP THE CROSS」
    それぞれメロディラインとして重ねることで矩形波グルーヴが生まれる。

_
▼ Namcot N106/N163音源

 カスタム波形を8chも鳴らせるということで、多くのNSFで使われている。 エリアシングノイズがあるもののこれは仕様とのこと。
 実装するにあたってnamco106.txtを参照した。 不明点は、8チャンネル分の実装をどうするか? 使用チャンネル数が出力周波数に影響するらしい? 波形長も出力周波数に影響するらしい? などあり、このあたりは実装して聴いてみて決めた。
 結局のところ、8チャンネルフラットに実装(パイプライン化しない)し、 クロックごとに1チャンネルずつ処理する方式をとった。 聴いてみたところ、出力周波数は使用チャンネル数に影響を受けるが、 サンプル長からは影響を受けないようだ。
 周波数カウントはレジスタの値を加算する方式とした。 しかし精度が低いため半音のためにオーバーした分は残す必要がある。 またnsfによっては0x4800をreadしているものがあるので適当な値を返す。
 チャンネルは8個使用した場合はch8,7,6,…、 4個使用した場合はch4,3,2,1というように使用される模様(mckの作法?)。

  • 13_AlkaliEarth.nsf 「Alkali Earth」
    深土を流れる力は時に、地表に現れたときにその牙をむく。 そのとき僕は、瓦礫の上でミルクを飲みながらバナナを食べる。 そんなイメージ。
  • 637.nsf 「Tales of Phantasia - Decisive」
    エコー効果をうまく使ってエイリアシングノイズを感じさせないサウンド。
  • dq3_09cv01.nsf 「DRAGON QUEST III 勇者の挑戦」
    オーケストレイション風にアレンジされて荘厳なイメージ。
  • sol10v02.nsf 「SOL-FEACE No.10」
    シューティングでエキサイトするサウンドといえばこれ。
  • th095_04_n.nsf 「東の国の眠らない夜」
    ティンパニを感じさせるサウンドは、 どこかアジアとブリティッシュの融合を予感させる。

_
▼ Nintendo FDS音源

 ゼルダの笛「ぴろろ〜ぴろ〜」と聞けばお分かりいただけると思う。 短いながらも好みのユーザ波形を発音でき、 さらに音尾を揺らしながら吹きぬけるような効果が可能。 機能としては64サンプルのユーザ波形、 ボリュームエンベロープ、LFO(Low Frequency Osciillllator) によるビブラートの効果となっている。 パートとしては管楽器や人の声(!)として使われる。
 FDSSOUND_v1.1.txtを参考にして実装。 出力波形は、レジスタで指定されるメイン周波数と、 スイープエンベロープとLFOから演算されるサブ周波数の加算によってえられた周期から波形テーブルを参照し、 ボリュームエンベロープを乗算して出力する。 特にサブ周波数を得るための演算は、 有効ビットを維持しながらのクリップ、ラップ、乗算など含むためなにかと面倒。
 最後に2点か3点のLPFをかけるかどうか迷ったが、 実際に聞いたところ、3点だとLPFの効果が強すぎてほかの音源から浮いてしまうので今のところ2点で。

  • mtp.20050901a.nsf 「マリオトロポリス」
    まるで歌っているかのように聞こえますよ。
  • th06_06_fds.nsf 「上海紅茶館 〜 Chinese Tea」
    ビブラートをうまく使って再現されています。
  • xn2_l9m.nsf 「ザナドゥ・シナリオII Level 9 Field」
    ドラムアレンジ ベースラインで使用。
  • 16_DOUKUTSU.nsf 「洞窟物語メドレー」
    こちらもベースラインで使用。 ファミコンに移植したらこんな感じかな。

_
▼ Konami VRC6

 矩形波×2と鋸歯状波の3チャンネル。仕様はvrcvi.txtを参照。 バイオリンや金管楽器に似た音を演奏できるらしい。
 実装に関しては仕様どおりで特に問題ないようだ。

  • 789.nsf 「SFC GOEMON1 STAGE8」
    どこか艶やかしいメロディですね。
  • SALAMANDA.nsf 「SALAMANDER [BGM 01]」
    沙羅曼蛇のサウンドがさらに豪勢になっています。

_
▼ Sunsoft SN5B音源

 方形波かノイズもしくはそれらの組み合わせとして3チャンネルを使用できる。 この音源チップは、 スターアクションがかわいいゆめたろうでおなじみ「ギミック!」に搭載されている。
 AY-3-8910のサブセットらしいとのことで、generalinstrument_ay-3-8910.pdfを参照。 ハードウエアエンベロープは8タイプ。 ボリュームは16段階だけど二次曲線的なのでテーブルとして実装。
 これを使用しているnsfはあまり見かけないが、音色としては使える。

  • 922.nsf 「Ys4 - Celceta, the Sea of Trees」
    全体を補う形で使用され豪華なサウンドが感じられる。

_
▼ Konami VRC7音源

 2オペレータFM音源を6チャンネル、もといNSFでは8チャンネル使用している。
 これはもう8ビット音源じゃないよね。 sin波がつむぎだす滑らかなサウンドは月夜が似合うよ。
 実装については、 FM音源ドライビング!を参照。

  • 329.nsf 「Filsnown - Normal battle」
  • 354.nsf 「V.G. Neo - We Survive」

_
▼ 複数音源使用

  • 23_dq8_vastsky.nsf 「Great Battle on the Vast Sky」
    VRC6、MMC5、N106、SN5B音源を使用。 ここまで音源を重ねると迫力が段違いにすごい。

_
▼ フレームIRQの罠 2012/12/5

 なぜかQD2.nsfが演奏できないことが発覚。 ログを見るとどうやらAPUからフレームIRQが発生している模様で、 まさかIRQが発生するとは思わなかったためその対策は実装していなかった。

 とりあえずIRQが発生した場合にすぐにRTIで返してみたものの、これはだめ。 かといってnsfプログラム内にIRQルーチンがあるのかと考え、 IRQベクタにそのアドレスがwriteされるのかと思ったけどそれもなし。 IRQベクタをNMIベクタと同じにしてもだめ。

 いっそのことフレームIRQを発生させなければ?ということでやってみると演奏できた。 しかしこの方法は、nsfが読み込まれたときにNSFマッパーからAPUのフレームIRQを無効にする信号を接続することになり、 いまいち納得できない。 また、DQ2.nsfのフレームIRQレジスタ設定値を有効にしないようにデータを書き換えることも手としては可能だが、 それはなんだか邪道。

 そこで、APUの使用していないポートに、フレームIRQを無効にするレジスタを追加して、 nsf演奏時のイニシャライズルーチンでこのポートをwriteする。 さらにソフトリセット時のレジスタ値もちゃんと設定することで、 DQ2.nsfも問題なく演奏することができるようになった。

instruct write_io par{
	any{
		adrs==0b10111 : par{ // $4017
			f_frame_sequencer_mode := din<7>;
			if(^f_nsf_IRQ_disable) f_frame_IRQ_disable := din<6>;
		}
		adrs==0b11010 : par{ // $401A 拡張ポート
			// $80をwriteするとフレームIRQを無効にする。
			f_nsf_IRQ_disable := din<7>;
		}
	}
}

 実機ではこのポートが無いためフレームIRQが発生し、 DQ2.nsfはうまく演奏できないと思われるが…どうなんでしょう?

_
▼ NSD.Libで作られたnsfのサポート 2016/01/03

 NSF Player on FPGAのFPGAデータを公開してからユーザさんに使っていただいたところ、 NSD.Libで作成したnsfが演奏できない、との連絡あり。 動作確認は主にppmckで作られたnsfを使用していたため、安心していたところでこれだよ。 ついでにFamiTrackerで作られたnsfを再生してみようとするがこれも再生できない。 どうやらシリアルポートから転送する場合は問題ないが、SDカードからロードした場合に演奏できない模様。

 ロード時のチェックサムを取っても問題ないので、 SDカードからのロードでの初期レジスタ設定がまずいみたい、というところまで切り分けした。 これ以上は分からなかったので、仕方なくVerilatorでC++に変換してシミュレーションし、 エミュとのログを比較する。ふと、A(アキュームレータ)レジスタの値が異なる箇所で違和感を覚える。

 で、Aレジスタにはnsfファイルオフセット0x07の「最初の曲番号」をセットしていたが、 これが0x01をそのままセットしていたのが再生できなかった原因らしい。 1曲目を再生したい場合は、マイナス1して0x00をセットする必要があるようだ。 実はこれ、nsfspec.txtにちゃんと書いてあるんだけど、 ppmckで作成されたnsfだとAレジスタにどんな値を設定しても再生されるもんだから、 問題ないだろうとほったらかしにしていた次第。

 結局、マイナス1した値を設定するようにしてNSD.LibやFamiTrackerで作成したnsfが演奏できるようになった。 仕様は大事ですね。 あと最近のnsfはNSD.LibやFamiTrackerで作られることも多くなってるので対応できてよかった。 最新版はトップページからダウンロードしてください。

_
▼ LCDあるなら活用せねば 2017/06/24

 NSF Player for DE0をリリースしてから色々と要望頂いています。 その一つが、DE0にLCDモジュールを付けているのでこれに何か表示できないか、というものでした。 そして、nsfファイルには「曲名」や「作成者」の情報があるので、 これを表示できればプレイヤとしての見栄えもちょっとは良くなりそうです。

 ということで、DE0のデータCDに入ってるLCDモジュールのデータシートを参照しながら、 LCDコントローラを実装して、曲名は32文字、作成者は16文字まで表示するようにしました。 一行に表示できるのは16文字までなので、曲名のみスクロールします。 ちなみにnsfファイルでは2バイト文字の日本語で書かれてるものもありますが、 LCDモジュールがサポートしてるのはASCII文字と半角カナなので2バイト文字は表示できません。 あしからず。

 イベントで展示されていたようす↓
 ちなみに私のDE0にはLCDが実装されていないので、 こちらで実装して実際の動作確認はユーザさん側で確認してもらいました。 2日後にイベントで展示するということで、トッカンでしたがなんとか考えた通りに動いたようです。 また今回は、曲名32文字分を格納するのに8×32=256bitのレジスタを確保しましたが、 内蔵メモリを使ったほうがいいのかな?という感じの微妙なサイズですね。


Copyright(C) pgate1 All Rights Reserved.