このメモは ex03_beep.cpp のためのものです。
目的は、まだ豊かな楽器音を作ることではありません。 まずは 1 つの単純な YM2612 beep を、完成した音から逆にたどって理解することです。
コードを読む前に、まずは次のページで目標の音を聞いてみてください。
この demo は ex03_beep.cpp と同じ YM2612 設定を使っています。
この tutorial の問いは、次の 2 つです。
ymfm や実際の chip にどう送るのか最初から register 番号を見るより先に、この beep を FM 的に言い直すと分かりやすいです。
channel 1 を使うalgorithm 7 を使うDT/MULTI を入れるBLOCK + F-Number で 1 つの音程を決めるKey ON を送るこれが、この beep の本当の内容です。 register write は、この内容を chip 固有の形式で表現しているだけです。
YM2612 には 6 個の FM channel があります。 各 channel には 4 個の operator があります。
operator は小さな音の発生器です。 operator 同士を変調に使うこともできるし、そのまま最終出力に混ぜることもできます。
ex03_beep.cpp では channel 1 を使っています。
FM 音源では、基本的に 1 つの channel を 4 つの operator で構成します。
そのため、0x30-0x3c のようにアドレス範囲に幅があるのは、
4 個の operator 分の設定が並んでいるためです。
Algorithm 7 では、4 個の operator がすべて carrier として動きます。 すべてが直接出力に行くので、最初の理解用として分かりやすいです。
唯一の方法ではありませんが、最初の beep には向いています。
この beep を設定の意図として書くと、だいたい次のようになります。
17もう少し具体的には:
DT=0, MULTI=1TL=0x7fTL=0x00AR0xa4 = 0x220xa0 = 0x690x28 = 0xf0Key ON を送らないと、chip の設定は終わっていても音は始まりません。
FM 側の考え方が見えたら、次に chip 側の表現を見ます。
各レジスタ書き込みは、次の 2 段階です。
例:
chip.write(0, 0x30);
chip.write(1, 0x01);
これは、
0x30 を選ぶ0x30 に 0x01 を書くという意味です。
つまり ex03_beep.cpp では、同時に 2 つのことをしています。
ex03_beep.cpp で使うレジスタ0x30-0x3c: operator の detune と multiple0x40-0x4c: operator の total level0x50-0x5c: operator の attack rate0x80-0x8c: operator の sustain level と release rate0xb0: channel の algorithm と feedback0xb4: 左右出力の有効化0xa4 と 0xa0: 周波数0x28: key on / key offこれらのレジスタは、各 operator の detune と frequency multiple を設定します。
0x30, 0x34, 0x38, 0x3cex03_beep.cpp では、すべて 0x01 を設定しています。
何が起きるか:
1補足:
Detune (DT) は音程をわずかにずらすための設定ですMultiple (MUL) は周波数を 1 倍、2 倍、3 倍… のように大きく変える設定ですMUL=2 なら基本音の約 1 オクターブ上、MUL=4 なら約 2 オクターブ上に相当しますこれらのレジスタは、各 operator の出力レベルを設定します。
0x40, 0x44, 0x48, 0x4cex03_beep.cpp では、operator 4 だけを大きくしています。
0x40 = 0x7f0x44 = 0x7f0x48 = 0x7f0x4c = 0x00何が起きるか:
補足:
Total Level (TL) は operator の最終的な出力音量ですこれらのレジスタは、音がどれだけ速く立ち上がるかを設定します。
0x50, 0x54, 0x58, 0x5cex03_beep.cpp では、すべて 0x1f です。
何が起きるか:
補足:
Attack Rate (AR) は Key On 後に最大音量へ達するまでの速さですこれらのレジスタは、エンベロープ設定の一部です。
0x80, 0x84, 0x88, 0x8cex03_beep.cpp では、すべて 0x0f です。
何が起きるか:
補足:
Sustain Level (SL) は decay の後に保たれる音量レベルですRelease Rate (RR) は Key Off 後に音が消えるまでの速さですRR を大きくすると、鍵盤を離した後すぐに音が消えますRR を小さくすると、余韻が長く残ります0xb0 = 0x07これは channel 1 に Algorithm 7 を設定しています。
何が起きるか:
補足:
Algorithm (ALG) は 4 個の operator をどうつなぐかを決めます0xb0 には Feedback (FB) も入りますFeedback は operator の出力を自分自身に戻す量で、強くするとノイズっぽさや鋭さが増します0xb4 = 0xc0これは left と right の両方の出力を有効にしています。
何が起きるか:
MOL と MOR の両方に送られる補足:
PAN の役割も持っています0xa4 = 0x220xa0 = 0x69この 2 つのレジスタで音程を設定します。
何が起きるか:
補足:
0xa4 側に BLOCK などの上位情報0xa0 側に F-Number の下位情報が入り0x28 = 0xf0これは channel 1 の operator 1-4 を ON にしています。
何が起きるか:
補足:
0x28 は実際の発音トリガーですYM2612 をもう一段深く理解して、自分で設定を書けるようになりたい場合は、
ymfm のソースコードをそのまま読むのがかなり有効です。
このリポジトリでは、src/ymfm_opn.h:209 がレジスタ辞書としてとても役に立ちます。
特に次の行が分かりやすいです。
src/ymfm_opn.h:221
0x30 系 -> op_detune, op_multiplesrc/ymfm_opn.h:223
0x40 系 -> op_total_levelsrc/ymfm_opn.h:224
0x50 系 -> op_ksr, op_attack_ratesrc/ymfm_opn.h:229
0x80 系 -> op_sustain_level, op_release_ratesrc/ymfm_opn.h:210
0xb0 -> ch_feedback, ch_algorithmsrc/ymfm_opn.h:212
0xb4 -> 左右出力 / pan 関連src/ymfm_opn.h:209
0xa4 + 0xa0 -> ch_block_freq0x28 の key on / key off の扱いは、src/ymfm_opn.cpp:176 を読むと追えます。
ex03_beep.cpp の write() と、ここでの定義が頭の中でつながるようになると、
かなり自力で YM2612 の beep 設定を書ける段階に近づいています。
beep は特別な 1 命令で出るわけではありません。
次の積み重ねで音になります。
Key ON で発音を始める