シーケンスデータの構造
スーパードンキーコング および、Donkey Kong Country で使用されているRareWare Sound Driver のシーケンスデータの構造について説明します。
APU RAM上の各変数のアドレスについては APU RAMマップ を参照してください。
表記
このマニュアルでは、コマンドの構文を次のように表記します。
0x02, sbyte left, sbyte right
先頭がコマンドのバイト値、続いてパラメータの型と名前をデータ中の順に並べています。型は byte(符号なし8ビット)、sbyte(符号付き8ビット)、ushort(符号なし16ビット、リトルエンディアン)です。ただし、ノートの長さを16ビットで指定する場合のみビッグエンディアンになります。
アドレスはすべてAPU RAM上の絶対アドレスで、シーケンスデータ内のオフセットではありません。
シーケンスデータの配置
シーケンスデータは APU RAM の $12A0 から配置されます。ROMに格納されているシーケンスファイルは、先頭の4バイトのヘッダに従ってAPU RAMへ転送されます。前半2バイトは転送先(エントリポイント)で常に $12A0、後半2バイトはデータのサイズです。
ヘッダ
シーケンスデータの先頭には、曲のヘッダが置かれています。
| オフセット | 型 | 内容 |
|---|---|---|
| +$00 | ushort[8] | 各BGMチャネル(0~7)のシーケンスの開始アドレス |
| +$10 | byte | テンポの初期値 |
| +$11 | byte | SEテンポの初期値 |
曲の初期化時には8チャネルすべてが動作を開始します。使用しないチャネルも、コマンド 0x00 だけのシーケンスなど、有効なシーケンスを指している必要があります。
SE
SEデータ領域の先頭($2380)には、各SEのシーケンスの開始アドレス(ushort)がSE番号順に並んでいます。テーブルに登録数は格納されていません。
SE番号は2倍した値の下位8ビットで表を引くため、有効なSE番号は $00~$7F です。
SEは、CPUからの指示で指定したBGMチャネル n に対応するSEチャネル n+8 で再生されます。SEのシーケンスはBGMと同じ形式で、同じコマンドを使用できます。
SEの開始時、SEチャネルの音量は左右とも $7F、ADSRは ADSR1 = ADSR2 = 0に初期化されます。SEの再生中、BGMチャネル n はシーケンスの処理だけを続け、DSPへの書き込みを行いません。
イベント
シーケンスはイベントの並びです。イベントの1バイト目で種類が決まります。
| 1バイト目 | 種類 |
|---|---|
| 0x00~0x30 | コマンド。パラメータの数はコマンドごとに決まっている |
| 0x80 | 休符 |
| 0x81~0xFF | ノート |
コマンドは処理に時間がかからず、続くイベントが同じティックのうちに読み込まれます。時間が進むのはノートイベントと休符イベントだけです。そのため、ノートや休符を含まない無限ループを作るとドライバが停止します。
0x31~0x7Fを実行すると、コマンド処理テーブルの範囲外または不正なアドレスへジャンプし、ドライバが暴走します。
ノートの長さ
ノートイベントと休符イベントの長さはティック単位で指定します。長さの指定方法には次の3つのモードがあり、チャネルごとに切り替えます。
| モード | 長さの指定 | 切り替えコマンド |
|---|---|---|
| 通常 | 各イベントに1バイト | - |
| デフォルト・デュレーション | 各イベントでは指定せず、コマンド 0x06 で設定した長さを使用 | 0x06, 0x07 |
| 16ビット・デュレーション | 各イベントに2バイト(ビッグエンディアン) | 0x2B, 0x2C |
デフォルト・デュレーション・モードと16ビット・デュレーション・モードを同時に有効にした場合は、コマンド 0x06 の引数が2バイトになり、各イベントでは長さを指定しません。
以下は、同じ内容を3つのモードで記述した例です。
// 通常
A5 10 A7 08 A9 08 AA 08 B1 10 00
// デフォルト・デュレーション
A5 10 06 08 A7 A9 AA 07 B1 10 00
// 16ビット・デュレーション
2B A5 00 10 A7 00 08 A9 00 08 AA 00 08 B1 00 10 00
テンポとティック
ドライバはタイマー0の周期で動作します。タイマー0の分周値は初期値 60(約133.3Hz、約7.5ms周期)で、コマンド 0x2A で変更できます。
タイマー周期ごとにBGMとSEのテンポ加算器にそれぞれのテンポを8ビットで加算し、桁あふれが起きた側のシーケンスを1ティック進めます。
したがって、1秒あたりのティック数は (8000 ÷ タイマー0の分周値) × テンポ ÷ 256 です。たとえば四分音符を16ティックとした場合、テンポ(BPM)は 約 1.95 × テンポ になります。
エフェクトの時間単位
ピッチベンド、ビブラート、トレモロの時間(ディレイや間隔)は、テンポではなくタイマー周期を単位として数えられます。そのため、テンポを変えてもエフェクトの速さは変わりません(コマンド 0x2A でタイマー周期を変えると変わります)。
サブルーチン
コマンド 0x04 でサブルーチンを呼び出し、コマンド 0x05 で戻ります。コール・スタックはチャネルごとに8段で、深さの確認は行われません。
曲のループには コマンド 0x03 を使用します。ゲームの状況による分岐には コマンド 0x2D を使用します。
処理の流れ
タイマー周期ごとに、BGMチャネル0~7について次の処理を行います。
- BGMのティックが発生した場合は、残りティック数を1減らし、0になればイベントを読み込む。コマンドは続けて読み込み、ノートイベントか休符イベントで止まる。
- エフェクト(ピッチベンド、ビブラート、トレモロ)を処理する。
- 対応するSEチャネルでSEが再生中であれば、SEのティックについて同じ処理を行う。
BGMのティックが発生した場合は、チャネルの処理の前にフェードアウトの処理(コマンド 0x29)も行います。