選曲について
ドライバは割り込み処理が有効になってから以降は、曲の停止に関係なくずっと動き続けています。
いつも演奏しているわけではなく、無音のときも当然ありますがその辺りの処理はどうなっているのか。
何となく想像は付きますが、処理を追ってみました。
※(+00H)のような表記は各チャンネルワークエリアのオフセットとなります。
b0-b7はビット位置、[]で括っているのは動作から推測して勝手に付けた名前です。
チャンネルごとのワークエリアに曲番号を記録している箇所(+00H)[曲番号]があり、そこが00Hだとドライバはそのチャンネルの処理を行いません。
演奏停止ですが音源に対して無音にするとかの処理はせず、ただそのチャンネルの処理をスキップするだけです。
ドライバから見れば各チャンネルの処理は独立していて曲として各チャンネルを管理していませんが、それが曲を演奏中にSEを鳴らす(つまり別の曲を同時に鳴らす)ことに都合が良い構造です。
曲を選択する場合は割込み禁止中に(ドライバはずっと動作しているので禁止にする必要があります)、使用チャンネルの分だけワークエリアを曲に合わせて設定するということになります。
曲番号00Hはそのような特殊な番号なので、下記の選曲処理では曲番号は01H番以上を指定しないと駄目ですが範囲チェックはありません。
選曲(ワークエリアの設定)処理内容
ゲーム処理から曲番号をAレジスタに入れて、バンク00Hの589AHをCALL。
そこでは割り込みを一旦禁止し、6000H-BFFFHをバンク0AH,0BH,0CHに切り替えて6003HをCALLしています。
6000H-6008Hには3つのエントリがあり、
各チャンネルのワークエリアが作成される場所は、E000H-E1FFHで、1チャンネル分のワークエリアのサイズは64バイト、チャンネルの割当は以下の通りです(表はこちら)。
曲番号によって処理は分岐しますが、ワークエリアをセットする段階になると、Cレジスタに曲番号が入って6075Hにやってきます。
ここでCの値を元にテーブル処理され、アドレスを引いてきます。このアドレスは、ワークエリア作成用データの開始アドレスでこのアドレス先のデータを元にしてチャンネルのワークエリアを作成します。
ワークエリア作成用データの開始アドレスからデータを12Hバイト、ワークエリアのバッファ(E282H-)へコピーします。
データは可変長ですが、最大サイズ分をバッファに移します。
データのフォーマットは、
使用チャンネルフラグはb7から処理されていき、このビットが1になっている順に曲データアドレスが並びます。
例えばb5,b4のみが1の場合、E284H-E285H PSG Ch.Cの曲データアドレス、E286H-E287H SCC Ch.Aの曲データアドレスで終了となりますし、フラグが全て1の場合はE284HからPSG Ch.Aの曲データアドレス、PSG Ch.Bの曲データアドレス…と並ぶことになります。
優先処理について
使用チャンネルフラグから1を見つけると、作成予定ワークエリアの(+01H)[優先値]とE283Hの優先値を比較します。
(+01H)には演奏中であれば演奏曲の優先値が、演奏停止中なら00Hが書かれています。
E283Hの値が(+01H)に書かれている値以上であれば、ワークエリアの作成に入ります。
優先値は各チャンネルのワークエリアにありますが、曲単位では同じ値です。
もし曲(あるいはSE)を演奏しようと6003Hの処理へ飛んだ時、その曲の優先値より高い曲が同じチャンネルで演奏中だった場合ワークエリアの設定はされず無視、つまり演奏されないことになります。
曲とSEで使用チャンネルが分けられていることと、曲(SE)単位では同じ値ということで、曲の一部だけが演奏されないということにはなりません。
演奏されない場合、その曲(SE)自体がキャンセルとなりますし、演奏される場合なら無視されるチャンネルはありません。
調べた限り通常の曲ではE0H、SEではそれぞれ細かく優先値が異なり、特殊な用途の場合FEHやFFHといった値が使用されているようです。
優先処理はこの他に、SE限定ですが同じ曲なら演奏中はリプレイできないというタイプもあります。
演奏途中で曲を再設定し、SEの最初から演奏し直すことはできませんが、優先値が低くなければ他のSEで上書きできるものです。
これは曲番号で分岐した時に、SCC Ch.Aのワークエリアの曲番号が同じかどうかで判定しています。
ワークエリアの作成
優先値チェックをパスしてチャンネルのワークエリアを作成する処理では、曲番号と優先値、曲データアドレスをバッファからワークエリアにコピーします。
残り60バイトは先頭に01H、続く59バイトが00Hで埋められているワークエリア設定用の雛形データがあるので、それをワークエリアにブロック転送(LDIR)して設定完了となります。
01Hの場所は(+04H)[音長カウンタ下位]の場所で、次の割り込みでドライバに処理が回った時、この音長カウンタが-1され0となり、曲データを読み込みに行くという動作です。
その他のワークエリアは全て0で初期値となるように設計されているようです。
この時曲番号によって、(E2BEH)[曲データのバンク種別]にA000H-BFFFHのバンク番号を表すバンク値が書き込まれることがあります。
曲番号が、SEやドライバに対するコントロール番号の場合は何も書かれませんが、バンクを指定する必要のあるデータならばバンク値が書き込まれます。
ドライバの処理の最初で、そのバンク値を参照してA000H-BFFFHのバンクを変更します。
SEはバンク切り替えをせず、曲の演奏は同時に1系統しか演奏しない仕様なので、バンク変更用の値も1つ設定するだけで事足りることになります。
曲番号でコントロール
曲番号は曲を演奏する以外にも使えます。
例えば曲番号01Hは演奏停止です。この曲番号をセットすると今まで曲を演奏していてもピタッと演奏を止めることができます。
ドライバが曲番号00Hのチャンネル処理をスキップするのとは違い、演奏を止めて消音します。
カラクリは、この曲の優先値はFFH、全チャンネル使用しその曲データアドレスの先にはFFH(曲終了)のみです。
そうすると次の割り込みで、ドライバはデータを読みに行き、曲終了データを取得、ワークエリアの終了処理を行いそれに基づき音源にデータを書き込む=消音。という流れです。
優先値は最高のFFHなのでどんな場合でも全チャンネル演奏終了となるわけです。
即終了する曲を設定するということですね。
また02Hも演奏停止ですが、こちらの優先値はE0H。
この曲より高い優先値の曲はポーズ音なので、ポーズ音以外は演奏停止ということができます。
曲番号は81H以上がドライバに対しての操作に割り当てられ、81Hがポーズ解除、82Hがポーズ設定、83Hがフェードアウト解除、84H,85Hはフェードアウト設定、となっていました。
これらは曲を設定するのではなく、曲番号で分岐し専用処理にジャンプしてワークエリアやフラグを直接操作します(ポーズ設定は専用処理後に曲も設定します)。
ポーズ音は普通の演奏に思えますが、その時に鳴らしている音をすべて止め、ポーズ解除時に復帰させる特殊処理があるので単に曲を選択するのとは異なる処理が必要になっているようです。