0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

以前書いたシステムROMの関数の呼び出され方の記事でも触れたように、ゲームボーイアドバンスにはシステムROM(「BIOS」とも呼ばれる)が搭載され、システムROMには様々な機能(以下「システム関数」)が存在します。
その中にはサウンド関連のシステム関数もありますが、サウンド関連についてはGBATEKですらそこまで情報がありません。

今回取り上げるSoundGetJumpListについてもGBATEKの説明は少なく、引数の説明を除くと

Receives pointers to 36 additional sound-related BIOS functions.

とのみ記載されています。
この説明は正しく、引数1(レジスタr0)に指定されたアドレスを先頭にサウンド関連のシステムROMの関数ポインタが36個書き込まれます。

やや蛇足ではありますが、GBATEKのこの関数の引数の説明は一部間違っており、正しくは「144(90h)バイトのバッファ」となります。

ですが、その関数ポインタが指す処理や、この関数の意図などはGBATEKには記載されていません。
今回は、その辺りについて説明していきます。

受け取った関数ポインタの意味するところ

36個の関数ポインタを利用目的で分けると、最初の30個と最後の6個に分けられます。

最初の30個

最初の30個はシーケンスプレイヤーのイベント処理用関数となります。
イベント番号0xb10xceまでの各イベントひとつにつき1個、イベント番号から0xb1を減じた値の要素番号の関数ポインタが対応しています。
これらの30個については、その処理のポインタを知ることとは別の利用方法があります(後述)。

関数ポインタとシーケンスのイベントの対応表(長いので折り畳み)
要素番号 イベント番号 説明 備考
[0] 0xb1 トラック終了イベント
[1] 0xb2 ジャンプイベント
[2] 0xb3 関数イベント 次のイベントのアドレスをトラックのコールスタックに積んで指定されたアドレスを読み取りアドレスに設定する。
関数は1トラックにつき最大3回までネストできる
[3] 0xb4 関数復帰イベント トラックのコールスタックからアドレスを取り出し、そのアドレスを読み取りアドレスに設定する。
コールスタックが空の場合は無視される。
[4] 0xb5 ループ終了イベント 到達時にトラックのループカウンターとループ回数を比較し、
  • ループカウンターがループ回数未満であれば指定されたアドレスを読み取りアドレスに設定する
  • ループカウンターがループ回数以上であれば次のイベントに進む
ループカウンタはトラックにつき1個なので、ループはネストできない
[5] 0xb6 未定義イベント 初期状態ではトラック終了イベント(0xb1)と同じポインタが設定されている
[6] 0xb7
[7] 0xb8
[8] 0xb9 変数操作/条件分岐イベント
(システムROMでは未定義イベントと同等)
初期状態ではトラック終了イベント(0xb1)と同じポインタが設定されている
また、市販ソフトで広く使用されているサウンドシステムであるMP2kでは、この番号のイベントと関数ポインタに変数操作と変数による条件分岐用のイベントが実装されている。
[9] 0xba トラック優先度イベント
[10] 0xbb テンポイベント 設定したいテンポの半分の値を指定する
[11] 0xbc ノートシフトイベント
[12] 0xbd プログラムチェンジイベント
[13] 0xbe トラック音量イベント
[14] 0xbf パン位置イベント
[15] 0xc0 ピッチベンドイベント
[16] 0xc1 ピッチベンド幅イベント
[17] 0xc2 LFO速度イベント LFOの実際の速さはテンポに依存する
[18] 0xc3 LFO遅延Tickイベント
[19] 0xc4 LFO深度イベント
[20] 0xc5 LFO適用先イベント
設定値 適用先
0 ピッチ(ビブラート)
1 音量(トレモロ)
2 パン位置(オートパン)
[21] 0xc6 未定義イベント 初期状態ではトラック終了イベント(0xb1)と同じポインタが設定されている
[22] 0xc7
[23] 0xc8 半音未満のチューニングイベント
[24] 0xc9 未定義イベント 初期状態ではトラック終了イベント(0xb1)と同じポインタが設定されている
[25] 0xca
[26] 0xcb
[27] 0xcc サウンドI/O設定イベント *(volatile unsigned char*)(0x04000060 + [パラメーター1]) = [パラメーター2];と同等の処理を行う。
[28] 0xcd チャンネル設定イベント
(システムROMでは未定義イベントと同等)
初期状態ではトラック終了イベント(0xb1)と同じポインタが設定されている
また、市販ソフトで広く使用されているサウンドシステムであるMP2kでは、この番号のイベントと関数ポインタにチャンネルに関する設定を行う処理が実装されている。
[29] 0xce ノートオフイベント ノートオンイベント(0xcf)と一組で使用し、ノートオンイベントで発音した音を消音する。

最後の6個

最後の6個はシステムサウンドやシーケンスプレイヤーの処理の内部処理の関数ポインタとなります。
シーケンスの処理を自前で実装する際に利用できる便利な関数のポインタが提供されます。
これらの関数はシステム関数やシステムROMのサウンド機能から直接的に呼び出されているものなので、使用方法さえ合っていれば同等の処理が見込めます。

要素番号 シグネチャ 説明
[30] void Func30(u32 mode); システムサウンドの再生周波数を設定する(SoundDriverModeの再生周波数設定部分のみ)
[31] void Func31(SystemSoundPlayerArea* player, SystemSoundPlayerTrack* track); 指定されたトラックに紐づいたチャンネルの発音を停止させる
[32] void Func32(SystemSoundPlayerArea* player); 指定されたシーケンスプレイヤーのフェードアウトを処理する(1回の呼び出しにつき1フレームぶん)
[33] void Func33(SystemSoundPlayerArea* player, SystemSoundPlayerTrack* track); 指定されたトラックの音量、パン、ピッチをトラックの設定や状態に応じて更新する(1回の呼び出しにつき1フレームぶん)
[34] void Func34(SystemSoundChannel* channel); 指定されたチャンネルをチャンネルの連結リストから取り除く(トラックによって再生されたチャンネルの使用解除)
[35] void Func35(SystemSoundChannel* channel); 指定されたチャンネルをゼロクリアする

システム関数SoundGetJumpListの使いどころ

この関数はシステムROM領域の特定の場所にある関数ポインタ配列を指定されたアドレスに転写する処理を行います。
実は、システムサウンドの制御データ(詳細は別記事参照)には、SoundDriverInitで初期化した直後にこのシステムROM領域の特定の場所のポインタが52(0x34)バイト目に書き込まれています。
シーケンスプレイヤーの再生処理は、イベントを処理する際にこの領域の最初の30個を使用します。言い換えるとコールバックとして利用されています(休符、ノートオン系イベントは例外)。
つまり、制御データの52バイト目にSoundGetJumpListの引数に設定した領域のポインタを設定し、その領域の希望する位置の関数ポインタを置き換えることによって、シーケンスのイベントの処理を差し替えることができます
未定義イベントを差し替えて独自の挙動を追加することも可能です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?