本作には効果音IDが 15 個存在し、それぞれに nice 値 (値が小さい方が優先度が高い) および使用する APU チャンネルマスクが割り当てられている。一覧を以下に示す:
ID | nice | APU チャンネルマスク | 再生 | 説明 |
---|---|---|---|---|
0 | 30 | (なし) | これは効果音処理の対象にならないダミーである(オーディオドライバ tick ルーチン参照)。 これを「再生」すると効果音 APU チャンネルマスクが 0 になり、オーディオドライバ初期化直後の音楽再生停止状態が解除される。 NOTE: このダミー効果音は終了することがないため、これの「再生」中は nice 値が 30 より大きい効果音の再生要求は受け付けられない。nice 値 30 以下の他の効果音を再生することでこの状態を解除できる。 | |
1 | 30 | 矩形波A, 矩形波B, 三角波, ノイズ | 面開始ジングル。 | |
2 | 30 | 矩形波A, 矩形波B, 三角波, ノイズ | 面クリアジングル。 | |
3 | 30 | 矩形波A, 矩形波B, 三角波, ノイズ | ゲームオーバージングル。 | |
4 | 40 | 矩形波A | (未使用) バイトコードはID 5 と同一だが、nice 値のみが異なる。 | |
5 | 50 | 矩形波A | 通常玉が 50pts に落下 (ランダムに再生される)。 | |
6 | 50 | 矩形波A | 通常玉が 50pts に落下 (ランダムに再生される)。 | |
7 | 50 | 矩形波A | 通常玉が 50pts に落下 (ランダムに再生される)。 | |
8 | 50 | 矩形波A | 通常玉が 50pts に落下 (ランダムに再生される)。 | |
9 | 40 | 矩形波A | カニ警告。 | |
10 | 30 | 矩形波A | 赤玉が 50pts 以外に落下。 | |
11 | 30 | 矩形波A, 矩形波B, 三角波, ノイズ | ミス。 | |
12 | 30 | 矩形波A | swap 操作。 | |
13 | 30 | 矩形波A, 矩形波B, 三角波, ノイズ | ポーズ。 | |
14 | 50 | 矩形波A | 通常玉が 50pts 以外に落下。 実際にはバイトコードのバグにより無音になっている (おそらくノイズ音量を 0 にするつもりで矩形波Aの音量を 0 にしてしまっている)。 |
効果音仮想マシンはバイトコード方式で、以下の状態を持つ:
また、効果音仮想マシンは APU レジスタ $4000-$400F
および APU レジスタ値キャッシュに直接書き込みを行うことができる。
効果音バイトコード命令は 1 バイトのオペコードと 0..=2
バイトのオペランドからなる。つまり、命令長は 1..=3
バイトである。
仮想マシンの 1 ステップ実行はウェイトカウンタ設定命令が実行されるまで続く。
命令セットは以下の通り:
オペコード | オペランド | 概要 |
---|---|---|
0..=0x1F | ウェイトカウンタをオペコードの値に設定する。 1 ステップ実行を完了する。 オペコード 0 は効果音の終了を意味する。 | |
0x20..=0x2F | value: u8 | APU レジスタに value を書く。APU レジスタ値キャッシュにも同じ値を書く。書き込み対象アドレスは 0x4000 + (オペコード下位 4bit) 。 |
0x33 | dst: ptr | アドレス dst へジャンプする。 |
0x34 | func: ptr | サブルーチン func を呼ぶ。 |
0x35 | サブルーチンから呼び出し元へ戻る。 | |
0x36 | n: u8 | n 回のループを開始する。 |
0x37 | ループ継続/終了。 | |
0x38, 0x3A, 0x3C | delta: 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 を書き込むため、プチノイズが発生しうる。