このアーカイブは下に記載する動作検証用のプログラムをまとめたものです。
同じソースを使い回しているので無意味な部分もありますが、気にしないでください。
・GB音源テスト用プログラム(ソース付き)soundtest.zip
1)出力周波数レジスタに連続して書き込む。
ch.1 を例に取ると、出力周波数 11bit のうち、NR13(bit0-7)で下位 8bit,NR14(bit0-2)で上位 3bit を表し、
NR14(bit7)を 1 にすることでキーオンする訳ですが、一旦キーオンした後にキーオンフラグを降ろしたまま
周波数を更新し続けるとどうなるかというテストです。
→ Test1-1
実行すると、ch.1 で発声を始めます。周波数+キーオンフラグで NR13,NR14 に $860a を最初に出力しています。
ここで B ボタンを押すと、$060a / $06ff を交互に出力します。最上位bitが降りているのでキーオンはせずに
周波数のみが高速で切り替わりますが、GB で実行した場合、数秒で発声そのものが終わってしまいます。
GBA で実行すると、発声が止まる現象は起きません。
分かりやすくするために2つの異なる値を書き込んでいますが、同じ値でも当然この現象が起きます。
他のチャンネルではどうなるのかもテストしてみました。
→ Test1-2 (Ch.3 波形メモリ音源)
こちらも同様に発声が途切れます。GBAでは途切れなし。
→ Test1-3 (Ch.4 ノイズ音源)
こちらは NR43 のみの更新です。途切れません。GBAでも途切れなし。
さて、ch.1に戻って今度は NR13 のみを更新してみることにします。
Test1-1 では NR13,NR14 に $060a / $06ff を出力していましたが、$0a / $ff のみを NR13 に書き込みます。
→ Test1-4
これは途切れません。
ついでに NR14 に $06 /$05 を書き込むテスト。
→ Test1-5
これは途切れます。
ということで、「周波数レジスタの上位を key on しないまま更新しつづけると発声が途中で終了する」ようです。
実はノイズ音源(ch.4)も NR44 に $00 を出力しつづけると止まります。
どうやら、暗黙の Length Counter が存在するような気がします。
「だったら周波数を変えるときにはキーオンフラグを常に立てておけばいいじゃないか」となりそうなのですが、
キーオンフラグはエンベロープやスイープのスタートも兼ねていたりと、ちょっと具合が悪いのです。
さて、この問題を解決する鍵は長さレジスタにあります。
各チャンネルの NRx1 のレジスタで、ch.1/2 では波形デューティー比設定も兼ねています。
次のテストは Test1-1 と同じですが、$060a / $06ff を書いた直後に NR11 に $c0 を書いています。
これで途切れなくなったことが分かると思います。
→ Test1-6
追記:長さレジスタ NRx1 に書き込むデューティー比を除いた音長部分は 0 でなければならないようです。
つまり以下のようなコードで音切れ対策を行っても、やはり音が途切れます。
LDH a,[rNR11]
LDH [rNR11],a
これは音長部分が読み出し不可のため、すべて 1 になっているためで(Test4-1参照)、
正しくは以下のようにすべきです。
LDH a,[rNR11]
AND %11000000
LDH [rNR11],a
NR31,NR41 に関してはデューティー比部分がないので、そのものずばり 0 だけ書き込めば良いです。
2)クリックノイズいろいろ
まず、Ch.3 を ON/OFF するとプチノイズが出ることを検証します。
プチノイズをリズム的に使用しているゲームもあります。
このノイズは GBA では出ないようです。
→ Test2-1
ボタンA で NR30 に $80 を、ボタンB で $0 を書き込みます。
このプチノイズはCh.3だけでなく、Ch.1/2/4にも影響します。
NR30 に $80 を書き込んだ状態で、Ch.1/2/4の音量レジスタを操作すると、やはりプチノイズが出ます。
NR30 に $00 で OFF にした状態では ノイズは出ません。
→ Test2-2
各ボタンの機能は以下の通り。
・↑↓ 音量を±1します。NR12 の上位 4bit(bit4-7) で、範囲は 0-F です。
・←→ エンベロープ時間を±1します。NR12 の下位 3bit(bit0-2)で、範囲は 0-7 です。
・Aボタン エンベロープ方向を上向き、下向きに切り替えます NR12の bit3 です。
・Bボタン キーオンします。NR14 に $80 を出力。
・START 現時点で NR12 に出力されているのと同じ値を出力します。
・SELECT NR12 に 0 を出力します。無音になります。
このテストでプチノイズの発生を調べてみると、大体次のような条件のようです。
・音量が 0 ←→ それ以外になった時
・音量が 0 で、かつエンベロープ方向の上下を切り替える時。エンベロープ量には無関係。
・音量を 0 ←→ それ以外と変更する時でも、エンベロープ方向が上向き(1)の時はノイズが鳴らない。
<追記> エンベロープ上向き、下向きに関わらず、NRx4のbit7=キーオンがクリックノイズの原因のようです->Test8-1
ch.1/2 を用いて PCM 音声再生をするゲームがありますが、エンベロープを上向き設定にして
PCM データを流し込んでいます。これもプチノイズ対策と考えられます。
備考:GBSOUND.txt には、Ch.1/2/4 にも Ch.3と同じように Master Channel Control Switch が
あると書いてあります。エンベロープユニットがそれであるということです。
併せて読むと良いかもしれません(プチノイズ以外の事も書いてあります)。
次に NR50,NR51 の操作でそれぞれクリックノイズが出ることを確認します。
→ Test2-3
・↑ チャンネルをスリープ状態にします。セクション6:マスターチャンネルコントロール参照
・↓ チャンネルをアクティブにします。NR12=$10を書き込みます
・←→ NR50にマスターボリュームを書き込みます。← が $00, →が $77 です。
・SELECT/START NR51 に パン情報を書き込みます。SELECT が $00, START が $FF です。
・A/Bボタン NR52 マスターコントロールを OFF(A)/ON(B) します。
起動直後、←→ または SELECT/START でクリックノイズが出ることが分かります。
NR51 パン情報のノイズ音がマスターボリュームの大きさに比例するところも面白いです。
逆にパンを 0 にすると、マスターボリュームのクリックノイズは完全に消えます。
マスターコントロールの NR52 を一旦 OFF/ON とリセットすると一切クリックノイズは出なくなります。
しかし、チャンネルを一旦アクティブにすると、以後はクリックノイズが出るようになります。
GBA では明示的にアクティブにしなくてもクリックノイズが出るという違いがあります。
3)音量とキーオンの関係/ゾンビモード
上記のテストと少し関わってきますが、ハードウェアエンベロープとソフトエンベロープの違いを
聞き比べてみることにします。
→ Test3-1
A/B ボタンでソフトエンベロープで発声します。1/60秒毎に NR12 に音量を書き込み NR14 でキーオンします。
Bボタンはキーオンした後、NR11 の長さレジスタにも書き込みます(違いがないことの検証です)。
パッドの右を押すと、ハードウェアエンベロープで発声します。
これらを聞き比べると、ソフトエンベロープが汚く聞こえるのが分かると思います。
GBA でも GB ほどではないですが、濁って聞こえます。
このノイズの原因は毎回キーオンを行うことにあります。
しかし音量レジスタに書き込んだ値が反映されるのはキーオン時点なので、キーオンしないわけにはいきません。
綺麗なソフトエンベロープの実現はとても難しいです。
上記の事実を確認するために、音量レジスタの操作のみを行ってみることにします。
→ Test3-2 (Aボタンでエンベロープの向きを変えた時 NR12 に即時に書き込まない。他は Test2-2と同じ)
パッドの上下を操作してみると、意図した音量になっていないことが分かります。
上下のどちらを押しても増え続け、ある程度増えると0に戻ることになります。
スタートボタンを押してキーオンした時点でようやく正しい音量・エンベロープで発声されます。
この現象を GBSOUND.txt 等では通称 Zombie Mode と呼んでいます。
以下、適当に和訳した説明を載せておきます。
チャンネルの音量は、何がセットされていても、エンベロープで音量が0または15になっていても
長さカウンタがチャンネルを停止しない限り音量を無期限に維持し続ける。
音量ビットのどれかが変更されると、チャンネルの音量は1または2増え、適宜0へとループする。
(キーオン時エンベロープ量ビットが0の時は1、そうでないときは2。
また、エンベロープ量ビットがキーオン以降、一度でも0以外に変更されていた場合は、
現在のエンベロープ量ビットが0であっても音量変化は2。)
エンベロープ方向ビットが変更されると、その書き込みに限り、音量は2でなく4増える。
このエンベロープ方向の向き(0→1,1→0)は全く関係ない。
ゾンビモード中、エンベロープ量ビットが0にセットされると、音量が2(または4…方向ビットが変更されたら)ずつ増える以外の
即時的エフェクトは起こらない。(ただし、再びキーオンされると増加量は1に変更される。)
初期音量を0にセットするとチャンネルのマスターコントロールスイッチがオフになり、無音となる。
チャンネルを再びキーオンすると、ゾンビモードを脱してエンベロープが復活する。
これはボリューム0つまりマスターコントロールスイッチがオフになるまでである。
|
ちょっとこれでも良く分かりませんね。原文でもあいまいな記述や用語がやや混乱気味に思えます。
この現象を実際に使ったゲームがあるのかもよく分かりません。実装されているエミュレータもあるにはあるのですが。
そこで、PC 上で録音して音量の差を実際に計ってみることにします。
0〜15の基準音量を個別に録音し、レベルを記録した上で、テストした値と比較して音量を測ります。
まず、NR12=$10 でキーオンし、以後 $F0 まで、エンベロープなしエンベロープ量0で変化させた場合
(初期音量0 NR12=$00 だとゾンビモードに入らないので $10 からです)
|
$10 | $10 | $20 | $30 | $40 | $50 | $60 | $70 | $80 |
$90 | $A0 | $B0 | $C0 | $D0 | $E0 | $F0 | $00 | $10 |
音量 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 0 | 0 | 0 |
最初に $10 を 2回書き込んでも変化していることからも分かるように、このパターンでは
レジスタに書き込む度に音量が1ずつ変化します。上の GBSOUND.txt の記述通りです。
そして 音量が 0 にループすると、以後の変化は受け付けなくなります。
また、音量を明示的に0にする(NR12=$00)場合でも、それ以後の音量変化はなくなります。
次に NR12=$11 でキーオンし、以後 $F1 まで、エンベロープ下向き、エンベロープ量1で変化させた場合
(こちらも初期音量0 NR12=$01 だとゾンビモードには入りません)
|
$11 | $11 | $21 | $31 | $41 | $51 | $61 | $71 | $81 |
$91 | $A1 | $B1 | $C1 | $D1 | $E1 | $F1 | $01 | $11 |
音量 |
0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 |
0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 0 | 0 |
まず、最初の書き込み NR12=$11 の時点で音量が1ではなく0という点ですが、エンベロープが実際に起こった
後に音量変化が起こっている(下向きエンベロープなので最終的な音量は0になる)と考えられます。
GBSOUND.txt の通りレジスタの内容が上記条件であれば、同じ値を書き込んでも2ずつの変化が起こります。
音量が0にループしても以後の変化が継続するという点が上のテストとは違います。
明示的に音量0(NR12=$01)にした場合は、それ以後の音量変化がなくなります。
なお、エンベロープ量1〜7まで全て同じ結果になりました。
上記のテスト2つはエンベロープ方向が下向き(bit3=0)の場合ですが、上向き(bit3=1)の場合はどうなるかテストします。
|
$18 | $18 | $28 | $38 | $48 | $58 | $68 | $78 | $88 |
$98 | $A8 | $B8 | $C8 | $D8 | $E8 | $F8 | $08 | $18 |
$28 | $38 | $48 |
音量 |
1 | 14 | 15 | 0 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 0 | 1 |
良く分からなくなってきました。何を書き込んでも音量変化するところは同じですが、音量0をまたいでも変化し続けます。
最初にいきなり音量14になるところが謎です。
さらに、方向下向きとは 初期音量0 (NR12=$08) でもゾンビモードに入る点で違います。この入り方も特殊です。
|
$08 | $08 | key | $08 | $08 | $08 | $18 |
音量 |
0 | 0 | on | 1 | 2 | 3 | 4 |
最初の $08(灰色の部分)はキーオン、次は NR12 に書き込みのみ、そしてキーオンとすると
以後ゾンビモードに入ります。この手順を踏まないとダメなようです。
次に エンベロープ上向き、エンベロープ量1で変化させた場合
|
$09 | $19 | $19 | $09 | $F9 |
音量 |
15 | 15 | 15 | 15 | 15 |
ワンショットの上向きエンベロープがキーオンで起こった後は、音量変化なし。
エンベロープ量1〜7でも結果は同じです。
GBSOUND.txt にはエンベロープ量が0とそれ以外の間で変化した場合のことも書いてあります。
次のテストではこれを検証します。
これも GBSOUND.txt 通り、一度0以外の値になると、以後は2ずつの変化となるようです。
$11 の書き込みの時に下向きエンベロープが起きて音量は0になります。
では、上向きエンベロープ (bit3=1) を混ぜてみた場合はどうでしょうか。
|
$10 | $1F | $10 | $20 | $21 | $29 | $29 | $21 |
$20 | $30 | $40 |
音量 |
1 | 15 | 1 | 3 | 5 | 9 | 9 | 7 | 9 | 11 | 13 |
$1F を書き込んだとき、上向きのエンベロープは発生せず、即音量15になりました。
ちょっと分かりづらいですが、$10 に戻ってきて以後の変化量が2であることが分かります。
また、$29 を書き込んだときに音量15になるかと思いきや、9のままです。
再び $29 を書き込んでも変化無しなのは2つ上のテストと同様です。
bit3 を立てたままの数値は何を書き込んでも変化ありません。
bit3 を降ろすと2ずつ変化を継続するように(5→7)戻ってきます。
bit3 を 0 ←→ 1 で変化させた場合は別のパターンがあると考えた方がよさそうです。
というわけでエンベロープ方向変更(bit3=0/1)の影響を次にテストします。
|
10→18 | 20→28 | 30→38 | 40→48 | 50→58 | 60→68 | 70→78 |
80→88 | 90→98 | A0→A8 | B0→B8 | C0→C8 | D0→D8 | E0→E8 | F0→F8 |
音量 |
1→14 | 2→13 | 3→12 | 4→11 | 5→10 | 6→9 | 7→8 |
8→7 | 9→6 | 10→5 | 11→4 | 12→3 | 13→2 | 14→1 | 15→0 |
差 |
13 | 11 | 9 | 7 | 5 | 3 | 1 |
-1 | -3 | -5 | -7 | -9 | -11 | -13 | -15 |
これはある意味分かりやすいです。$10→$18→$10→…とすると音量が1と14を繰り返します。
GBSOUND.txt に4つ上昇とあるのは、この変化を指しているのであれば、おそらく間違いと思われます。
これを $18→$10 と bit3=1 の状態でスタートすると次のようになります。
|
$18 | $10 | $10 | $18 | $10 | $18 | $10 |
音量 |
1 | 2 | 3 | 12 | 3 | 12 | 3 |
$10 を書きこんだ最初の2回の変化1→2→3は音量変化1のルールに則っています。
その後の変化は上と同じく、音量3の時12に、12の時に3になります。
最後に、エンベロープ量が0以外の時に bit3 を操作した場合をテストしてみます。
まず、bit3=0 の $11 からキーオンした場合
|
$11 | $19 | $11 | $19 | $11 | $19 | $11 | $19 |
$11 | $19 | $11 | $19 | $11 | $19 | $11 | $19 |
以下最初に ループ |
音量 |
0 | 14 | 2 | 12 | 4 | 10 | 9 | 8 |
8 | 9 | 10 | 4 | 12 | 2 | 14 | 0 |
続いてbit3=1 でキーオンした場合
|
$F9 | $F1 | $F9 | $F1 | $F9 | $F1 | $F9 | $F1 |
$F9 | $F1 | $F9 | $F1 | $F9 | $F1 | $F9 | $F1 |
以下最初に ループ |
音量 |
15 | 1 | 13 | 3 | 11 | 8 | 9 | 7 |
7 | 9 | 8 | 11 | 3 | 13 | 1 | 15 |
明らかに規則性があるのですが、その規則がよく分かりません。
ここまでテストしてきたルールの組み合わせだと思われるのですが・・・。
なお、初期ボリューム(bit4-7)やエンベロープ量(bit0-2)が何であっても、上記と同じ結果になります。
(初期ボリューム0は除く)
以上を踏まえて、まとめのようなものを。
・音量変化のトリガーは2種ある。音量変更とエンベロープ方向変更で、それぞれエンベロープ量の影響を受ける。
・キーオン時エンベロープ量(bit0-2)が0の時は音量が1ずつ上昇
・キーオン時エンベロープ量(bit0-2)が0以外の時は音量が2ずつ上昇
・キーオン時エンベロープ量(bit0-2)が0の時でキーオンされた場合でも、その後0→その他、または0→その他→0の場合、音量は2ずつ上昇
・エンベロープ方向を上向き(bit3=1)にしてキーオンすると方向変更(bit3操作)するまでは音量変化は受付ない。
・エンベロープ方向を下向き(bit3=0)にしてキーオンすると、方向変更に加え2ずつ上昇のルールも受け付ける。
(エンベロープ量が0の時はエンベロープ自体が無いので1ずつ上昇は出来ない)
・上向き下向き共にエンベロープ自体は遂行される。
・エンベロープ方向ビット(bit3)が変化した時、規則的な音量変化をする。
最初のテストで示した通り、ソフトエンベロープを綺麗に鳴らすことは難しいのですが、
ゾンビモードを利用したソフトエンベロープのテストを一応作ってみました。
→ Test3-3
B ボタンでゾンビモードでのソフトエンベロープを行います。パッドの→ボタンで比較用のハードエンベロープです。
濁りはなくなったような気がしますが、エンベロープ後半はプチノイズが派手に乗ります。GBAでも同様。
結論:良く分かりませんでした。
音量も、エンベロープが絡むと微妙にレベルが変わっているときがあり、
基準音量と照らし合わせても不明な時がありました。
なお、筆者は GBA に接続できるイヤホンは持っているのですが、マイク端子に繋げないため
上記の録音してのレベルテストは GBC でしか出来ませんでした。
GBAでは違う結果が出るかもしれないことに留意してください。
注:“エンベロープ量”ではなく“エンベロープ時間”と表記すべきかもしれませんが、
「一度に変化するエンベロープ量が多い=速いエンベロープ」という意味なので、そのままにしておきます。
4)Readable なレジスタは?
GBSOUND.txt 他、各種資料には音源レジスタの Readable/Writable が記されているのですが
資料によって曖昧だったりするので、実際の所をテストするプログラムを書いてみました。
エミュレータの実装と比較してみると面白いかもしれません。
→ Test4-1
・↑↓ テストするレジスタを選択します。即時にテストした結果が画面に表示されます。
・SELECT NR50 に $77 を書き込みます。もう一度押すと $00 を書き込みます。
・START NR51 に $FF を書き込みます。もう一度押すと $00 を書き込みます。
・Bボタン NR52 に $8F を書き込みます。もう一度押すと $00 を書き込みます。
・Aボタン NR30 に $80 を書き込みます。もう一度押すと $00 を書き込みます。
画面に出てくる2進数8桁がテストした結果です。0が読み込み不可、1が読み込み可です。
SELECT〜A ボタンを押すと画面に表示が出ているときは値が書きこまれた状態、消えていたら $00 です。
調査方法は以下の通り。
1)調べたいビットに0を書き込み、それを読み込む。
2)調べたいビットに1を書き込み、それを読み込む。
3)以上2点の読み込みが両方とも正当であれば、読み込み可とする。
4)テスト終了時にはレジスタに0を出力する。
5)チャンネルによってはマスターコントロールスイッチがあるので、その ON/OFF も考慮する。
初期状態では NR30,NR50-NR52 は全てOFFにしてあります。
通常は NR52<-$8F,NR50<-$77,NR51<-FF,NR30<-$80 の順番で音源を起動します。
コントロールレジスタが ON/OFF の時に読み込みの挙動が違うかどうかテストできます。
当然ですが、例えばコントロールレジスタである NR30 のテストを行うと、NR30 は0でクリアされ画面表示も消えます。
プログラムが雑すぎ・・・。
以下に調査結果をまとめてみました。「o」=読込可「x」=読込不可 です。
Addr | REG |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 備考 |
$FF10 | rNR10 |
x | o | o | o | o | o | o | o |
スイープ部分のみ可 |
$FF11 | rNR11 |
o | o | x | x | x | x | x | x |
デューティ比のみ可 |
$FF12 | rNR12 |
o | o | o | o | o | o | o | o |
全て可 |
$FF13 | rNR13 |
x | x | x | x | x | x | x | x |
全て不可 |
$FF14 | rNR14 |
x | o | x | x | x | x | x | x |
長さカウンタ使用フラグのみ可 |
Addr | REG |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 備考 |
$FF16 | rNR21 |
o | o | x | x | x | x | x | x |
ch.1と同じ |
$FF17 | rNR22 |
o | o | o | o | o | o | o | o |
ch.1と同じ |
$FF18 | rNR23 |
x | x | x | x | x | x | x | x |
ch.1と同じ |
$FF19 | rNR24 |
x | o | x | x | x | x | x | x |
ch.1と同じ |
Addr | REG |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 備考 |
$FF1A | rNR30 |
o | x | x | x | x | x | x | x |
チャンネルコントロールのみ可 |
$FF1B | rNR31 |
x | x | x | x | x | x | x | x |
全て不可 |
$FF1C | rNR32 |
x | o | o | x | x | x | x | x |
音量部分のみ可 |
$FF1D | rNR33 |
x | x | x | x | x | x | x | x |
全て不可 |
$FF1E | rNR34 |
x | o | x | x | x | x | x | x |
長さカウンタ使用フラグのみ可 |
Addr | REG |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 備考 |
$FF20 | rNR41 |
x | x | x | x | x | x | x | x |
全て不可 |
$FF21 | rNR42 |
o | o | o | o | o | o | o | o |
全て可 |
$FF22 | rNR43 |
o | o | o | o | o | o | o | o |
全て可。周波数読込可はch.4のみ |
$FF23 | rNR44 |
x | o | x | x | x | x | x | x |
長さカウンタ使用フラグのみ可 |
Addr | REG |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 備考 |
$FF24 | rNR50 |
o | o | o | o | o | o | o | o |
全て可 |
$FF25 | rNR51 |
o | o | o | o | o | o | o | o |
全て可 |
$FF26 | rNR52 |
o | x | x | x | x | x | x | x |
マスターコントロールのみ可。
ただし bit0-3 は各チャンネルの再生ステータスフラグなので読込のみ可 |
$FF30 to $FF3F | Wave Pattern |
o | o | o | o | o | o | o | o |
|
・
コントロールレジスタの NR52が OFF の時は NR52 自身と $FF30-$FF3F 以外は読み書き不可になる。
・
GBSOUND.txt には、「未使用ビットへの書き込みは音源コントロールがOFFになるまで保持される」とあるが
上記のテストを見る限り誤りと思われる。
なお、「読み込み」については、以下のコード
ld hl,rNR14 ldh a,[rNR14]
set 7,[hl] set 7,a
ldh [rNR14],a
|
|
左右は同じ結果になります。NR14 の 下位 6bit=1 に最上位bit=1を加えて書き込まれます。
キーオンフラグだけ立てようとしても意図しない音が鳴ってしまうということです。
set 命令で直接書き込んだつもりでも暗黙の読み込み動作が入っているということに注意が必要です。
読込不可のビットは0で返すか1で返すか、という点も調査してみます。
→ Test4-2
パッド上下でレジスタを選択し、ボタンAで $00,ボタンBで $FF を書き込み、
それを読み込んだ結果を2進数8桁で表示します。
マスターコントロールスイッチの NR52 は常に ON にしてあります。
・
読込不可のビットは常に1で返される。
・
NR52の下位4ビット(再生中ステータスビット)は再生中でない限り0を返す。
以上2テストは GB/GBA 共に同じ結果になりました。
次に、キーオンすると波形メモリ音源のメモリ内容が壊れる現象をテストしてみます。
→ Test4-3
・パッド← NR30 に $00 を書き込みます。ch.3 停止
・パッド→ NR30 に $80 を書き込みます。ch.3 起動
・STARTボタン 波形メモリにデータを書き込みます。$01,$23,$45 ・・・ $54,$32,$10 の三角波です。
・Bボタン キーオンした後に波形メモリを読み込み、画面に内容を表示します。
・Aボタン なにもせずに波形メモリを読み込み、画面に内容を表示します。
通常は ch.3 を停止して波形メモリに書き込み、ch.3を起動(操作で言うとパッド左・スタート・パッド右の順)
という手順を取ります。イレギュラーな手順もこのプログラムでテストできます。
以下に、判明した事をまとめてみます。
・
ch.3 が OFF(NR30=$00) の時はキーオンを受け付けない。ch.3 を OFF(NR30=$00)にすると音は止まる。
・
ch.3 が ON(NR30=$80) でも OFF(NR30=$00) でも、キーオンされていなければ、波形メモリの読み書きは正確に行われる。
・
再生中に波形メモリに書き込むと、書き込む度に音色が変わる。→期待通りの(三角波)波形にはならない。
・
再生中の波形メモリの読み出しは、読み出す度に変わる。が、ランダムではなく書き込んだ値に関連したもの。
・
再生を NR30=$00 で停止させると、波形メモリは正確に読み出せる。
・
再生中に波形メモリに不正確に書き込まれた波形は、NR30=$00 で停止させた後、読み出すことができる。
GBA では 以下の部分が GB(上記)と違います。
・
再生中に波形メモリを読み出すと、常に $FF(全16byte)を返す。
・
再生中に波形メモリに書き込むことが出来ない。ゆえに書き込む度に音色が変わる現象はおきない。
レジスタの読み込みが制限されている以上、現在のレジスタの値を正確に知ることはできません。
次のテストは、NR52 を OFF/ON にすることで、レジスタがクリアされるかを調査します。
読み出し不可のレジスタが多数あることを考えて、出音の違いで検証してみることにします。
→ Test4-4
起動直後、または STARTボタンを押すと各チャンネルのレジスタに値を設定します。
パッドの上右下左で、それぞれ ch.1234 をキーオンします。設定を確認してみてください。
Bボタンを押すと、NR52 を一旦 OFF → ON にします。
Aボタンで音量のみを回復します。
SELECTボタンでパン設定とマスターボリューム、ch.3コントロールのみを回復します。
注:キーオン毎に音長カウンタがリセットされるため初回と2回目で音長が違います。
スイープが実行される度に開始音程が変わる点も同様。これは別件として下記に取り上げています。
このテストはSTART→B→上右下左で書き込んだ値がリセットされることを確認するものです。
音量とパンを両方とも回復しないと全く鳴らず、回復後も音が設定値と違うのが分かります。
NR52 をリセットするとレジスタは初期化・音源全体がリセットされるということのようです。
本当は個別のレジスタ(の個別の機能)について細かく調査しなければならないのですが、
回復させないと確認できないものが多く推測の域は出ません。が、ほぼ確実ではないかと。
(エンベロープ・音量・パン・マスターボリュームを回復しないと出音が確認できない)
GB と GBA では同じ結果になりました。
では、NR52 の OFF,ON でレジスタの値はどう変わるのか、読み出せる部分しか分かりませんが
調査してみます。
→ Test4-5
・パッド↑↓ レジスタを選択します。
・Aボタン $00をレジスタに書き込みます。
・Bボタン $FFをレジスタに書き込みます。
・SELECTボタン NR52 を OFF,ON とし、音源を再起動します。
・STARTボタン レジスタの値を読み出して表示します。
A/Bボタンで値を書き込んだ後、SELECT でリセットし、START で読み込むと、NR52 リセット後の
レジスタ値の変化が読み取れます。
このテストにより、以下の事が分かりました。
$FF30-$FF3F の波形メモリを除く全ての音源レジスタは NR52リセットで 0 クリアされる
なお、レジスタの読み出しではクリックノイズ等は発生しません。
5)各機能が反映されるタイミング
ここでは、各レジスタがエフェクト動作中に書き換えられるとどのような挙動を示すかをテストします。
周波数レジスタ(NRx3,NRx4)の挙動については1)でテストしたため省略します。
(キーオン後に周波数レジスタを操作することで出音に正常に反映されることが確認できた)
→ Test5-1
・パッド↑ 下降エンベロープ設定を NR12 に書き込みます
・パッド↓ 上昇エンベロープ設定を NR12 に書き込みます
・パッド→ 上昇スイープ設定を NR10 に書き込みます
・パッド← 下降スイープ設定を NR10 に書き込みます
・Bボタン キーオンします NR13,NR14
・Aボタン キーオンせずに周波数を書き込みます NR13,NR14
・SELECT エンベロープ無し、音量 15をNR12に書き込みます。スイープオフ
・START 押す度に波形デューティ比を変更します
音量レジスタに関してはゾンビモードに関しても考慮してテストします。
上書きエンベロープは“エンベロープ実行中に限り”受け付けるようです。
上昇あるいは下降エンベロープ中に上書きでエンベロープを書き込むと、上書きの初期音量を
無視して、その時点の音量から上書きエンベロープが有効になります。
通常のエンベロープ無しキーオンからのエンベロープ上書きは、上昇のみ有効のようです。
ゾンビモードに入るタイミングはエンベロープが終了した時点と思われます。
エンベロープ無しの音量15(SELECTボタン)をエンベロープ中に書き込むと、
発動中のエンベロープがエンベロープ無しで即座に上書きされて終了→その時点でゾンビモード発動
という流れになります。このとき音量15は反映されません。
波形デューティ比は随時受け付けるようです。
エンベロープが終わって無音になっていても変更が反映されます。
スイープは複雑です。
・スイープ無しでキーオンし、その後スイープを設定するとスイープ無しで低音が鳴りっぱなし。
・上昇スイープ中スイープオフ(NR10=$00)するとその時点の周波数が鳴りっぱなしになる ※1
・下降スイープ中スイープオフ(NR10=$00)すると消音
・上昇スイープ中下降スイープを設定すると、その時点での音程から下降スイープで上書き。
・下降スイープ中上昇スイープを設定すると、消音
・上昇・下降スイープ共に、動作中にキーオン無しで周波数設定すると、一瞬その音程が鳴るが
スイープ動作が優先して継続する。
※1 GBAの場合は以下のことがすぐに分かると思います。
・上昇スイープ中スイープオフ(NR10=$00)すると書き込んだ時点の周波数が鳴りっぱなしになる。(一時停止?)
・さらにその鳴りっぱなしから上昇/下降スイープ設定をすると、設定を受け付ける。
・鳴りっぱなし状態でキーオン無し周波数のみ書き込みで音程を変え、上昇/下降スイープを
設定すると、音程を変える前(鳴りっぱなしの時の音程)からスイープが始まる。
実は GB でも同じ事が起こるのですが、GBはゾンビモードに入ってしまうため、消音になってしまいます。
何度か SELECTボタンを押して音量をインクリメントさせてやると、一時停止しているのが分かるはずです。
GBA と GB でゾンビモードに入る条件が違うようです。
スイープの挙動が不明なので、もうすこし突っ込んで調べてみることにします。
→ Test5-2
・Bボタン 低音/高音をキーオンします(トグル動作)
・Aボタン スイープ無し・上昇・変化量 2(NR10=$07)を書き込みます。
・SELECT 速度 7・下降・変化量 0(NR10=$78)を書き込みます。
・START 速度 7・上昇・変化量 0(NR10=$70)を書き込みます。
・パッド↑ 速度 2・下降・変化量 2(NR10=$2A)を書き込みます。
・パッド↓ 速度 2・上昇・変化量 2(NR10=$22)を書き込みます。
・パッド→ 速度 7・上昇・変化量 7(NR10=$77)を書き込みます。
・パッド← 速度 7・下降・変化量 7(NR10=$7F)を書き込みます。
スイープは「現在の周波数を(下位3bit)右シフトした値を足す/引く」という動作です。
下位3bit=0の場合、上昇の場合には現在周波数*2になり、下降の場合には0になるはずです。
上昇エンベロープと下降エンベロープを聞き比べると分かりますが、上昇は最後に消音し、
下降は低音が鳴りっぱなしになります。これも動作原理を考えると納得できます。
(右シフトして0になった数値を引いても周波数は変わらない)
以下テスト結果。
・変化量0の上昇スイープは高音でキーオン時はすぐ消音する。低音時は鳴りっぱなし。
・変化量0の下降スイープは高音時も低音時もキーオン以後鳴りっぱなし。
・上昇スイープ中、別パラメータの上昇スイープを設定すると上書き適用される。
・下降スイープ中、別パラメータの下降スイープを設定すると上書き適用される。
・上昇→上昇または下降→下降の時、変化量が0だとその時点の周波数で鳴りっぱなしになる。
この「鳴りっぱなし」の後の挙動がよくわかりません。
・上昇→上昇0→上昇→上昇0→上昇→上昇0と繰り返すと、ある程度の音の高さになると消音
・上昇→上昇0→(鳴りっぱなし)→下降スイープ反映
・下降→下降0→下降で即時低音鳴りっぱなし
・下降→上昇0は即時消音
・上昇→下降0→上昇で即時消音
・上昇→下降0→(鳴りっぱなし)→下降スイープ反映せず低音なりっぱなし。
オーバーフローは消音、アンダーフローは低音なりっぱなしなのでしょうか。
どの時点で出音の演算を行い内部カウンタを進めているかが問題なのかもしれません。
さらに
・上昇スイープ時、スイープ無し上昇変化量2(Aボタン)はスイープ一時停止になる。
この一時停止は繰り返しても消音せず再開できます。
ここだけを掘り下げるべく、もう一つプログラムでテストします。
→ Test5-3
Aボタンで上昇スイープ設定、Bボタンでキーオンです。上下左右 SELECT/START で停止条件テスト。
このテストで一時停止条件はスイープ時間=0(bit4-6=0) であることが分かりました。
他のビットが何であれ、一時停止が起こり、再度 NR10 に値を書き込むとスイープ再開します。
スイープは音源の内部レジスタを逐次更新しながら動作します。
NR13,NR14 に値を設定してスイープを起動すると、両レジスタは書き換えられます。
どのように書き換えられたかは、どちらも読み出し不可なので分かりませんが、
以下のテストでその事実を確認できます。
→ Test5-4
パッド右でスイープを設定し、Bボタンで NR13,NR14 の両レジスタに書き込んでキーオンします。
Aボタンは NR14 のみ書き込んでキーオンです。SELECT を押すとスイープをリセットします。
Bボタンでキーオンしてスイープした後、Aボタンでキーオンするとスイープ開始周波数が違うのが
分かると思います。あるいは SELECT でスイープを止めたあと、Aボタンでキーオンでも分かります。
これはスイープによって NR13 が書き換えられているためと思われます。
(Bボタンは明示的に $060a からスタート、Aボタンは $06xxからスタートになるということです)
GB/GBA どちらも同じ結果になります。
さて、次は長さカウンターです。
長さカウンターはデューティ比と同じレジスタに配置されています。
このうちデューティ比の方はいつ書き込んでも即時反映されることが既に分かっています。
残る長さカウンタですが、これは他のレジスタと少し違います。
→ Test5-5
・パッド→ 長さレジスタに短い値(NR11=$61)を入れる
・パッド← 長さレジスタに最長の値(NR11=$00)を入れる
・パッド↑ エンベロープを設定する
・パッド↓ スイープを設定する
・Aボタン 長さレジスタを使用しない設定でキーオン(音程高)
・Bボタン 長さレジスタを使用する設定でキーオン(音程低)
・SELECT エンベロープとスイープをリセットします。
・START 押す度に1/60秒間隔でNR11に$80を書き込む機能をON/OFFします。
画面上に表示される数値は NR52 の値です。長さカウンタ使用時は再生中フラグの様子が分かります。
長さレジスタが、長さレジスタ使用キーオン後に反映されるのが分かると思います。
Bボタンを押して音が消える前にパッド右か左を入力すると、その時点で音の長さが決定されます。
エンベロープやスイープを設定してからテストすると、より分かりやすいと思います。
あるいは、キーオン後にSTARTを押すか、パッド左を連打すると再生時間が延びるのが分かります。
また、音程高の長さレジスタ未使用のキーオン中に長さレジスタを設定した後、長さレジスタ使用の
キーオンを行うと設定が反映されていることが分かります。
このことから、
・再生中のみ長さレジスタ設定を受け付ける
・長さレジスタ使用フラグが立っているときのみ長さレジスタをカウント(インクリメント?)する
・長さレジスタが0になった時点で NR52 再生中フラグを降ろす
と考えられます。
長さレジスタをセットして再生した次の再生は常に NR11=0 の音長であるため、
NR11 は再生中にレジスタ内容を上書きしながら動作しているように思います。
ただし、これも読み出し不可レジスタなので推測に過ぎません。
最後に ch.3 の音量レジスタについて調査します。
ついでに長さレジスタの挙動についても上記 ch.1 と同じか確認します。
→ Test5-6
パッド左右で音長レジスタセット、パッド上で音量を切り替えます。
Aボタンで長さレジスタ未使用キーオン、Bボタンで長さレジスタ使用のキーオン
長さレジスタに関しては、ch.1 と同じと結論づけてよさそうです。
どうして設定できる長さが違うのかは分かりませんが。
それから、音量に関しては随時受け付けるということが分かりました。
GB/GBA で同じ結果です。
6)マスターチャンネルコントロール
NR52 の再生中フラグが何に従ってON/OFFになるのかを調べます。
まず、Test5-5 等で長さカウンタを使わないキーオンは、常に1が立っていることが分かっています。
逆に長さカウンタを使用するキーオンは再生中が1で再生後は0になります。
その他の条件で0や1になるのでしょうか。
→ Test6-1
・Aボタン キーオン無しで周波数設定します
・Bボタン キーオン有りで周波数設定します
・パッド↑← スイープを設定します 上昇/下降
・パッド↓→ 音量とエンベロープを設定します NR12=$F2/$00
・SELECT NR11=$81 音長カウンタ 1 波形デューティ比50%設定
・START エンベロープ・スイープ無し音量15 音長カウンタ使用でキーオン
このプログラムで調べてみると、NR52 の再生中フラグが降りるのは
・上昇スイープでオーバーフローを起こして音が停止した時
下降エンベロープで音量0になった後もスイープオーバーフローが起こり、フラグは降りる。
・NR12 に $00 を書き込んだ時
であることが分かります。それ以外は下降エンベロープで無音になっていてもフラグは降りません。
GBでは起動直後の NR52 は $F1 (ch.1が再生中)を示していますが、これは起動時のコイン音が
エンベロープと長さカウンタ未使用キーオンによって作られていることを表しています。
この2つの条件の内、NR12=$00 がマスターコントロールであると GBSOUND.txt は解説しています。
これは上記テストでも確かめられます。
NR12=$00 の時はキーオンそのものを受け付けなくなる(NR52の再生フラグが立たない)からです。
単に音量が0というのではなくキーオンをスルーしていると思われます。
さらに Test2-3 で NR50,51 によるクリックノイズをテストしましたが、この時も NR12=$00 では
クリックノイズは出ず、$00以外を出力して初めてノイズが出るようになりました(GBのみ)。
マスターコントロールがONかOFFかは、微少なノイズによっても確かめられます。
NR12=$00 の時はほぼ完全な無音なのに対し、それ以外の時はサーというヒスノイズが聞き取れます。
同じ音量レジスタでも、NR32 はマスターコントロールではありません。
→ Test6-2
・パッド↑↓ NR30 に$00(Ch.3-Off)と$80(Ch.3-On)を書き込みます
・パッド←→ NR32 に$20(音量最大)と$00(消音を書き込みます
・START で Ch.3 をキーオンします。
・SELECTで Ch.1 をキーオンします。
・A/Bボタンで Ch.1 の NR12 に $08 と $00 を書き込みます。
Ch.1 は比較用に入れてあります。
Ch.3 はまずパッド↓で NR30-On を書き込んでから START でキーオンしてください。
NR32 の音量レジスタに $00 を書き込んでも NR52 のステータスが降りないことが確認できます。
なお、NR12=0 が、チャンネルマスターコントロールといっても、他の ch.1 関連レジスタへのアクセスが
無視されると言うことはありません。
→ Test6-3
・START 通常の発音を行います。o5c (NR13,NR14=$860a)
・Aボタン NR12=0 を書き込み、マスターコントロールを OFF にします。
・Bボタン o6c (NR13,NR14=$86ff) に書き込んでから NR12=$F0 マスターコントロールを ON にし、
さらに NR14 に書き込みで音量を反映します。
ここで、START→A→B と押すと、マスターコントロール OFF の状態で書き込んだ NR13=$FF が生きて、o6c で発音されるのが
分かると思います。NR14はマスターON/OFFどちらも NR14=$86なので、NR13 の状態で判別できます。
音源マスターコントロールの rNR52 ですが、これを OFF にすると音源全体が disable になります。
携帯機なのでバッテリーを長持ちさせるための仕組みとしてこうなっているようです。15-20%の延命だそうです(GBSOUND.txt)。
7)起動直後の状態について
表題の通りです。
→ Test7-1
パッド上下でレジスタ選択、Bボタンで内容を表示します。
SELECTボタンで NR12 に $10 を書き込みます。
|
FF10 | FF11 | FF12 | FF13 | FF14 |
FF16 | FF17 | FF18 | FF19 |
FF1A | FF1B | FF1C | FF1D | FF1E |
|
NR10 | NR11 | NR12 | NR13 | NR14 |
NR21 | NR22 | NR23 | NR24 |
NR30 | NR31 | NR32 | NR33 | NR34 |
GBC |
80 | BF | F3 | FF | BF |
3F | 00 | FF | BF |
7F | FF | 9F | FF | BF |
GBA |
80 | BF | F3 | FF | BF |
3F | 00 | FF | BF |
7F | FF | 9F | FF | BF |
|
FF20 | FF21 | FF22 | FF23 |
FF24 | FF25 | FF26 |
|
NR41 | NR42 | NR43 | NR44 |
NR50 | NR51 | NR52 |
GBC |
FF | 00 | 00 | BF |
77 | F3 | F1 |
GBA |
FF | 00 | 00 | BF |
77 | F3 | F1 |
|
FF30 | FF31 | FF32 | FF33 | FF34 | FF35 | FF36 | FF37 |
FF38 | FF39 | FF3A | FF3B | FF3C | FF3D | FF3E | FF3F |
GBC |
00 | FF | 00 | FF | 00 | FF | 00 | FF |
00 | FF | 00 | FF | 00 | FF | 00 | FF |
GBA |
00 | FF | 00 | FF | 00 | FF | 00 | FF |
00 | FF | 00 | FF | 00 | FF | 00 | FF |
GBSOUND.txtの丸写しみたいになってしまいました。
既にテストしたように、読み出せるビットが少ないので内部的に保持されている値は上記の通りではありません。
ch.1 のNR13には起動後のロゴと共に出るコイン音の値が設定されています。
GB と GBAで全く同じ結果ですが、Test7-1 で起動後に SELECTボタンで NR12=$10(0以外)を書き込むと
GB では音が鳴り、GBA では音は鳴りません。ゾンビサウンドの仕様の違いと思われますが
初期化の仕方によってはこうした違いが出てくるのではないかと思います。
8)プチノイズをなんとかしたい
このページや音源・PCMドライバの方でも「音量レジスタをいじるとノイズが乗る」と書きましたが
正確には「音量レジスタを反映させるためにキーオンするとノイズが乗る」です。
プチノイズの原因は NRx2 でなく、NRx4 の bit7 にあることを確認します。
→ Test8-1
パッド上左下右で、それぞれ ch.1/2/3/4 にキーオンを出力します。NRx4のみを操作します。
START でリセット。消音します。
Bボタンを押すとタイマ割り込みで ch.4 ノイズチャンネルに連続してキーオンを発行します。
押すたびに 4096Hz->262.144KHz->65.536KHz->16.384KHz と変わります。画面の表示(0〜3)はこの順です。
Aボタンでタイマ割り込みを止めます。ノイズが鳴っていることを確認できます。
パッドのいずれかの方向を連続で押すと、キーオンのみでプチノイズが発生することが分かります。
GBC/GBAいずれもプチノイズが発生します。
Bボタンのタイマ割り込みは、PCM再生を想定しています。
PCM再生時(特にch.4ノイズチャンネル)の耳障りな発振音の原因が分かると思います。
再生レートを高くして(16384Hz以上??) NR43の値を慎重に選べばどうにかなるかもしれませんが、
当然処理は重くなります。
このプチノイズを無くそうといろいろ頑張ってみたのですが、今のところ解決策はみつかっていません。
・NRx4のbit7=0で再生周波数書き込み→bit7=1で再度書き込み
・キーオン前後に NRx1 に書き込む
・音程を可聴音域外の 0 または $7FF にしてキーオン、その後キーオフ状態で音程のみ任意の可聴音域に変更
等々…。NES の 2A03でも書き込みで位相がリセットされてノイズが乗るそうなので、こちらも同じなのかも。
ただ、同一音程でない、違う音程でキーオンするとクリックノイズが発生していないような気もします。
この場合でも、同一音程でのソフトエンベロープに使えないのには違いはないのですが。
■ その他
未調査項目
・GBA でのゾンビモードの詳細。発動条件が GB と明らかに違う。
・CGB のデューティ比仕様 ロックンチェイス?? (GBSOUND.txt)
・音量がリニアかどうか(GBSOUND.txt には最初期 GB 以外リニアとあるが・・・)
・スイープユニットでPANDOCSでは n/128 毎に更新、GBSOUNDでは (n+1)/128 毎に更新となっている。
(NEZPLUG++では前者)これはGBSOUNDの間違いか
GBAでのテストはGBA上で動くGBエミュレータでも出来るのではないかと思います(DSでも可?)
音源的にGBA音源はGB音源スペックを取り込んでいるので、エミュレータがハード直叩きであればOK。
NEZPlug++は再現度が結構高くて良いです。これ積んだエミュレータがあればいいのですが。
chiptune 関連を扱っている人が一番細かい挙動に詳しいのかも。
nanoloop とか LSDJ とか、もはや何をやっているのか想像つきません…。
■ 履歴
2009.03.03 Test 6-3 Test 8-1 を追加
2009.04.03 Test 1-6 に追記
▲ TOP