ロットロット (FC) 攻略/解析 - オーディオドライバ

効果音

効果音リスト

本作には効果音IDが 15 個存在し、それぞれに nice 値 (値が小さい方が優先度が高い) および使用する APU チャンネルマスクが割り当てられている。一覧を以下に示す:

IDniceAPU チャンネルマスク再生説明
030(なし)これは効果音処理の対象にならないダミーである(オーディオドライバ tick ルーチン参照)。
これを「再生」すると効果音 APU チャンネルマスクが 0 になり、オーディオドライバ初期化直後の音楽再生停止状態が解除される。
NOTE: このダミー効果音は終了することがないため、これの「再生」中は nice 値が 30 より大きい効果音の再生要求は受け付けられない。nice 値 30 以下の他の効果音を再生することでこの状態を解除できる。
130矩形波A, 矩形波B, 三角波, ノイズ面開始ジングル。
230矩形波A, 矩形波B, 三角波, ノイズ面クリアジングル。
330矩形波A, 矩形波B, 三角波, ノイズゲームオーバージングル。
440矩形波A(未使用) バイトコードはID 5 と同一だが、nice 値のみが異なる。
550矩形波A通常玉が 50pts に落下 (ランダムに再生される)。
650矩形波A通常玉が 50pts に落下 (ランダムに再生される)。
750矩形波A通常玉が 50pts に落下 (ランダムに再生される)。
850矩形波A通常玉が 50pts に落下 (ランダムに再生される)。
940矩形波Aカニ警告。
1030矩形波A赤玉が 50pts 以外に落下。
1130矩形波A, 矩形波B, 三角波, ノイズミス。
1230矩形波Aswap 操作。
1330矩形波A, 矩形波B, 三角波, ノイズポーズ。
1450矩形波A通常玉が 50pts 以外に落下。
実際にはバイトコードのバグにより無音になっている (おそらくノイズ音量を 0 にするつもりで矩形波Aの音量を 0 にしてしまっている)。

効果音仮想マシン

効果音仮想マシンはバイトコード方式で、以下の状態を持つ:

また、効果音仮想マシンは APU レジスタ $4000-$400F および APU レジスタ値キャッシュに直接書き込みを行うことができる。

効果音バイトコード命令セット

効果音バイトコード命令は 1 バイトのオペコードと 0..=2 バイトのオペランドからなる。つまり、命令長は 1..=3 バイトである。

仮想マシンの 1 ステップ実行はウェイトカウンタ設定命令が実行されるまで続く。

命令セットは以下の通り:

オペコードオペランド概要
0..=0x1Fウェイトカウンタをオペコードの値に設定する。
1 ステップ実行を完了する。
オペコード 0 は効果音の終了を意味する。
0x20..=0x2Fvalue: u8APU レジスタに value を書く。APU レジスタ値キャッシュにも同じ値を書く。
書き込み対象アドレスは 0x4000 + (オペコード下位 4bit)
0x33dst: ptrアドレス dst へジャンプする。
0x34func: ptrサブルーチン func を呼ぶ。
0x35サブルーチンから呼び出し元へ戻る。
0x36n: u8n 回のループを開始する。
0x37ループ継続/終了。
0x38, 0x3A, 0x3Cdelta: i8矩形波/三角波の周波数変化。
0x3F全ての矩形波/三角波チャンネルを消音する。
0x40..=0x7B, 0x80..=0xBB, 0xC0..=0xFB矩形波/三角波の発音/消音。

オペコード 0x30..=0x32, 0x38..=0x3E は全て矩形波/三角波の周波数変化命令として扱われるが、「正規」のオペコードは 0x38 (矩形波A), 0x3A (矩形波B), 0x3C (三角波) だと思われる (原作のバイトコード内にはオペコード 0x38 のみ存在する)。

オペコード 0x7C..=0x7F, 0xBC..=0xBF, 0xFC..=0xFF は不正である。実装上は矩形波/三角波の発音/消音として扱われるが、実行すると周波数タイマー値テーブルの範囲外を参照してしまう。

効果音バイトコード命令詳細

オペコード 0x34 <func:ptr>: サブルーチン呼び出し

次の命令のアドレスを戻りアドレスとしてスタックに push し、アドレス func へジャンプする。

オペコード 0x35: サブルーチンからの復帰

スタックから戻りアドレスを pop し、そのアドレスへジャンプする。

オペコード 0x36 <n:count>: n 回のループを開始

スタックに n をループカウンタとして push し、さらに次の命令のアドレスをループ開始アドレスとして push し、実行を継続する。

なお、n == 0 の場合は 256 回のループと解釈される (が、実際にはそのようなケースは現れない)。

オペコード 0x37: ループ継続/終了

スタックトップにあるループカウンタをデクリメントし、

オペコード 0x38, 0x3A, 0x3C <delta:i8>: 矩形波/三角波の周波数変化

まず対象 APU チャンネルを決める。オペコード 0x38 は矩形波A, 0x3A は矩形波B, 0x3C は三角波が対象となる (オペコードの bit1-2 を見ている)。

そして、オペランドの変化量をAPU レジスタ値キャッシュ内の値に加算し、結果を対応する APU レジスタおよび APU レジスタ値キャッシュに書き込む。このとき、周波数下位バイトは必ず書き込むが、上位バイトについては変化があった場合のみ書き込む (矩形波は発音時に位相がリセットされるため、プチノイズの発生を極力抑えるための措置と思われる)。

オペコード 0x3F: 全ての矩形波/三角波チャンネルを消音

全ての矩形波/三角波チャンネルについて、対応する周波数レジスタに 0 を書いて消音する (NOTE: 三角波についてはプチノイズが発生しうる)。

NOTE: このとき、対応する APU レジスタ値キャッシュに対しては 0 でなく 0xFF00 を書く。これの意図はよくわかっていない。

オペコード 0x40..=0x7B, 0x80..=0xBB, 0xC0..=0xFB: 矩形波/三角波の発音/消音

まず対象 APU チャンネルを決める。オペコード 0x40..=0x7B は矩形波A, 0x80..=0xBB は矩形波B, 0xC0..=0xFB は三角波が対象となる (オペコードの bit6-7 を見ている)。

そして、オペコードの bit0-5 が発音/消音指示となる。値 59 は消音を意味し、値 0..=58 は発音すべき音名を意味する。これは 12 平均律の F2 から半音ずつ高くなる構成であり、値 0, 1, 2, ... は音名 F2, F#2, G2, ... に対応する (ただし APU の特性上、高音域になるほど精度は悪くなる)。

消音指示の場合、対応する APU チャンネルの周波数レジスタに 0 を書く。発音指示の場合は音名に対応する周波数タイマー値を書く。いずれの場合も APU レジスタ値キャッシュに同じ値を書く。

NOTE: 三角波を消音する際も周波数タイマー値 0 を書き込むため、プチノイズが発生しうる。