ファミコン音源 三角波の鳴らし方・止め方について その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を書いています。
スポンサーサイト

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

ファミコン音源と言えば、三角波。 その16段階のギザギザした三角波は、ファミコン音源を象徴する音です。

しかし、その三角波をちゃんといじるには、ファミコン音源の仕様を熟知している必要があり、当時のサウンドドライバ制作者も頭を悩ませていたのか、お粗末な止め方をしているドライバもいくつかあります。



三角波のキーオン/キーオフについて

(ここでは、16進数を「$80」のように表記します。)

三角波には、パルス・ノイズchにもあるキーオフカウンタ($4003とかの上位5bitで指定するやつ)の他に、$4008で指定する三角波専用のカウンタがあり、どちらかのカウンタが0になると三角波は止まります。この三角波にしかないカウンタの仕様がやたらとくせ者なのです。

三角波カウンタは240Hz($4017の7bitが1の場合は192Hz)くらいの間隔で更新されます。VSyncやキーオフカウンタよりも細かく指定できます。そのカウント値は下位7bit(0-127)で指定します。カウンタを無効にする場合は7bit目を立たせます。ずっと鳴らしたい場合は$81以上の値を書きます。$80では音は鳴りません。$81以上を指定してキーオンさせた場合は、$80か$00を書くことで音を止められます。

・・・と、ここまでは普通のよくある一般的な解説です。ここからドライバ制作者とエミュレータ制作者が頭を抱える内容になってきますよー…


こっからは図を使います。上から下へと時間が流れていく感じ。キーオフカウンタは考えないものとします。
各部分の意味は、
EVENT: ハード・ソフトウェアによるイベント
FREQ : 周波数レジスタの値
$4008: $4008に書かれた値
COUNT: 三角波カウンタ。「--」はカウントが始まってないことを示す。00でキーオフ。
UPDATE FLAG: $400Bが書かれ、次のカウンタ更新周期に$4008の値をロードするフラグ。
TRI-WAVE PLAYING: 三角波が実際に発声されてるか。

三角波図1
まず、$400Bライトによってキーオンした後、実際に三角波が発声されるのは、240Hz/192Hz位で回っているハードウェアのカウンタ更新処理直後です。もちろん、$4008だけ更新して音を鳴らす場合も同じです。

三角波図2
カウンタ無効フラグを立たせてキーオンした後は、カウンタ部分はまだロード待ちの状態となっており、$00-$7Fの値を今か今かと待っている状態です。そして、$00-$7Fを書いて周期が来た瞬間からその値でカウントが始まります。なお、カウンタが有効の間は、これ以降どんな値を$4008に書いても、キーオンするまで一切無視されます。もちろん、$80や$81以上を書いても無駄です。


三角波 キーオフ波形
ちなみに、三角波がキーオフするとき、波形はこんな感じになります。周波数0Hzのような状態となり、現在の波形値をずーっと維持する形で音を止めるのです。確かにこれなら、簡単な実装でノイズを出すことなく音を止められますね。



さーて、ここまで分かったかな? 理解できたら、次はいよいよ各ドライバでの音の鳴らし方・止め方を見てみます。
次:「ファミコン音源 三角波の鳴らし方・止め方について その2」
プロフィール

おふがお(OffGao)

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

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

この人とブロともになる

QRコード
QR