fc2ブログ

ファミコン音源 三角波の鳴らし方・止め方について その2

まずは「ファミコン音源 三角波の鳴らし方・止め方について その1」をご覧下さい。





三角波の鳴らし方の仕組みが分かったところで、ここからは各ドライバがどんな使い方をしているのかを解説します。主に止め方で。

素直に三角波カウンタを使って止める方式
最も素直でマメな方式です。主に初期のゲームでよく使われました。トーセドライバ・マイクロニクスドライバとか、ドラクエ1とか、任天堂のゲームでもマリオ1,2,3,USAらの全部がこれです。
キーオンしとけば、あとは指定した時間にハードウェアが音を止めてくれるので、ドライバを書くプログラマには最も楽な方式です。
しかし、簡単なドライバでは三角波の音長をいちいち変えたりと曲を書く側には大変で曲データも大きくなるし、自動計算など凝ったことをしようとするとプログラムがめんどくさくなります。そのためか、後期のソフトではあまり使われなくなったり、カウンタ0にされて音を止められたりなどソフト制御と併用するパターンになりました。
なお、この方式では、先に$4008を書いてから$400Bを書かないと、後記のカウンタ更新割り込みの罠にはまります。


カウンタ0でキーオンして止める方式
少々荒っぽいが妥当という感じの方式です。
$4008に0を書いてキーオンすることで、三角波を止めるというやり方です。さっきのカウンタを使う方式と併用されたりします。
ただ、これも鳴らすときに$4008を書いてから$400Bを書くように気をつけないと、後記のカウンタ更新割り込みの罠に…。


$81以上/$00方式
まだまだだなぁ…という方式です。ソフトウェアエンベロープを使うドライバの半分くらいはこれです。ドラクエ2,3もこれです。
$4008に$81以上を指定してキーオンし、音を止める場合は$4008に$00を書くだけで止めるやり方です。
ただ、この方式より、すぐ下の$81以上/$80方式の方がより賢く、より扱いやすいです。詳しくはそちらに書きます。
そして、この方式もカウンタ更新割り込みの罠に注意です。


$81以上/$80方式
ちゃんと理解してるなぁという感じの方式です。ソフトウェアエンベロープを使うドライバのもう半分くらいはこれです。ドラクエ4やFFシリーズ全てもこれです。
$4008に$81以上を指定してキーオンし、音を止める場合は$4008に$80を書くだけで止めるやり方です。
すぐ上の$81以上/$00方式よりもこちらが良い理由はいろいろあります。まず、音を止めた時でもカウンタが動かないため、止めた後に$4008に$81以上を再度書くだけで音が再び鳴り始めます。いちいち$400Bにも書いてキーオンさせる必要がないのです。そして、カウンタ更新割り込みの罠もありません。とにかく扱いやすく、安全に制御できるのです。


$4015の三角波ビットを下ろして止める方式
意表を突いた感じの実装方法でかつ安全な方式です。この方法のドライバは少ないです。野球拳のできないやつとかざんねん!!とかその辺。
$4008に音長を指定するか$81以上を書いた状態でキーオンし、任意のタイミングで止めたいときに$4015の三角波ビットを下ろして音を止めます。下ろすのは一瞬だけでも大丈夫です。カウント中だろうがカウンタ無効だろうが簡単に止められて、$400Bを書くだけで再キーオンできますから、案外制御も楽です。


周波数レジスタ$000にして擬似的に止める方式
これ実装したやつ表に出ろと言いたくなる方式です。この実装のドライバもよく見られ、初期HAL研ドライバやロックマン2までの初期カプコンドライバ、りりなどの3流メーカーのドライバがこれです。
周波数の値を$000にして超音波状態にして聞こえないようにすることで、音が止まったように見せかける愚かな方式です。パルス波なら周波数$008未満が指定されるとキーオフするので良いのですが、三角波はそうはいきません。ずーっと音が鳴ったままの状態です。
実際の出力波形は超音波は通らないため、三角波16段階の半分くらいの位置での横線となるのですが、この方式で音を止めるときに波形が急激に変わるので、プチノイズがよく出てしまうのです。


重低音を出力して擬似的に止める方式
漢だなぁ…と感じる方式です。この実装のドライバはあまり見られませんが、あの烈火とかに使われてる後期KIDドライバがこの方式です。
周波数の値を$7FFとかの重低音状態にして聞こえにくくすることで、音が止まったように見せかける方式です。なので、よく聞けば「ビーー」という音が聞こえます。
考えればこれも愚かな実装とはいえ、烈火とかは他のchがそれをカバーできるレベルの音圧や曲構成だったりするので、この方式を使いこなせるかは曲次第。
あ、BPSテトリスとかは「$81以上/$00方式」の方に分類されるもので、休符部分が「ビーー」ってなってるだけだから、この方式には分類されません。



・・・と主なモノだけでもこんな感じでしょうか。結構いろいろやり方があります。そして、ドライバ制作者の苦労も見えてくるかもしれません。





カウンタ更新割り込みの罠


先ほどから何度も出てきた「カウンタ更新割り込みの罠」ですが、これはカウンタ有効中に$400Bでキーオンさせてから$4008を更新する処理において、処理中にカウンタ更新がかかったときに$4008の値が正常に反映されない現象のことです。
以下の図は、$81以上/$00方式でこの現象が起こってしまうまでの流れを図にしたモノです。
三角波図3
上部分が正常な例、下部分がカウンタ更新割り込みの罠発動時の例です。説明すると、
 0:$4008に$00を書いて音を止める。
 1:周波数レジスタを更新するために、$400A,$400Bを書く。ここでキーオンされる。
 2:<ここでハードウェアのカウンタ更新処理が走る!>
   このときの$4008の値($00)がカウンタにロードされる。
   カウンタ有効・カウンタ0のため音は鳴らない。
 3:カウンタ更新処理が走ったとも知らず、$4008に$81以上の値を書く。
   しかし、カウンタ有効なため、この値は無視される。
 4:音を鳴らすべきところで音が鳴らない!
という事が起こっているのです。

これは、先に$4008を書くというかんたんな事で回避できますが、これをやらずに愚かな実装をしてしまったドライバはいくつかあります。どろぴ~とかのアイコムドライバとか、ジョイメカファイトとか…
そして、実はドラクエ2,3もこの実装なのです!
…でも、ドラクエ2,3は三角波が途切れたりたまに鳴らなかったりはしません。その理由は、ドライバを回すのにサウンドのカウンタ更新時に出るIRQを使っているからです。よく互換機で正常に曲が鳴らない原因の理由にされているアレです。このおかげで、ドライバが回るのが必ずカウンタ更新直後であるために、重たい処理をしない限りカウンタ更新が割り込むことはないのです。



ppmckは「$81以上/$00方式」、nsd.libは「$81以上/$80方式」、FamiTrackerは「$81以上/$00方式と見せかけてカウンタ0でキーオンして止める方式」かな。ふむふむ。





















おまけ:OFGSでの三角波の止め方


自作のサウンドドライバであるOFGSでは、上記のいかなる方式にも該当しないへそ曲がりな実装方法で三角波を鳴らしたり止めたりしています。ファミコン音源を熟知してないと理解できない、エミュレータ作者泣かせな方式です。(もちろんエミュレータ作者とは自分も含むので自滅となる場合も…)
なお、制御方法は旧型と新型とで2タイプあります。

(以下、$4017の7bit目の仕様を理解してなければ理解できない内容です。)


カウンタ4方式
OFGS Ver1はこの方式です。$4008に$04を書いて以降一切触らず、鳴らすときは毎フレームキーオンして、鳴らさないときはほったらかすやり方です。三角波はどんなにキーオンしても波形が乱れないからこそ使える方法です。
カウンタ4というのはVSync割り込みの間隔とほぼ同じで、1F待てば音が止まる間隔です。そこで毎フレームドライバ処理終了後$4017に$C0を書くことでカウンタ処理の同期を取ると同時に、音を止める場合はそのタイミングでぴったり止まるようになります。
ただ、この方式ではドライバに重い処理がかかったときに三角波が一瞬止まってしまうため、Ver2では次の方式に切り替えたのです。


オフ・アップデート・オン方式
OFGS Ver2はこの方式です。$4008に$81以上をあらかじめ書いておき、キーオン時は$400Bに書くだけ、音を止めるときは$4008に$00を書く(ゼロ)→$4017に$C0を書いてカウンタ即時更新(アップデート)→$4008に$81以上を書く(オン)と処理していくやり方です。
実際の実装では、$4017への書き込みもあるために、処理の簡略化で$4008には$C0を書いています。
スポンサーサイト



コメントの投稿

非公開コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

No title

うおー、昔の遊びで作ったドライバをでは上位、下位に00を入れてとめていました。
だって、そんな使用があるなんて知らなかったんだもの(英語読めない)
それにしてもどうやってドライバ製作者はファミコンの仕様を学んでいたんでしょうか?
マイコンとかで音源ドライバを作っていた経験者が多かったのだろーか?
プロフィール

おふがお(OffGao)

Author:おふがお(OffGao)
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QR