FM音源プログラム (11) -- オペレータ (4)

次は、フェーズ・ジェネレータ (phase generator) まわりの話です。
オペレータの式を、フィードバックを省略し、番号を省いて簡略化して示すと、
\qquad {OP}(t) = E(t) \cdot \sin \left { \omega \cdot t + {\rm pm}(t) \right }
のようになります。
サイン関数 \sin \left { \cdot \right } の引数部分である位相
\qquad \phi(t) = \omega \cdot t + {\rm pm}(t)
を、サンプリング周期を T として  t = n \cdot T \qquad (n = 0, 1, 2, ... ) により離散化して \phi [ n ] で表すことにすると、
\qquad \phi [ n ] = \omega \cdot n \cdot T + {\rm pm}[ n ]
となります。
これを1周期 2^{\small N} エントリのサイン波テーブルのインデクスとするためのスケーリングをすると、 \omega = 2\pi \cdot f より、
\qquad \frac{2^{N}}{2\pi} \left ( \omega \cdot n \cdot T + {\rm pm}[ n ] \right ) = n \cdot 2^{\small N} \cdot T \cdot f +  \frac{2^{N}}{2\pi}{\rm pm}[ n ]
となります。
角周波数 \omega 由来の項である、右辺第一項について
\qquad \text{phacc} = n \cdot 2^{\small N} \cdot T \cdot f
\qquad \text{phinc} = 2^{\small N} \cdot T \cdot f
と定義すると、フェーズ・アキュムレータの初期値 phacc = 0 として、C 言語の式で表現すれば、

phacc += phinc;

の計算をサンプリング周期ごとに繰り返せば良いことが分かります。 
1周期 2^{\small N} を超えてオーバーフローする部分は無視され、常に 0 〜 2^{\small N} -1 の部分だけが使われるものとします。
この時間と共に増加する、ピッチ情報の表現である位相を生成する部分をフェーズ・ジェネレータ (phase generator) と呼び、PG と略記します。
これに位相変調入力 phmod を足してサイン波テーブルを参照すれば、オペレータの基本部分の処理になります。

sinval = SINTAB[phacc + phmod];

phmod の値はテーブルの参照時にのみ使われて、phacc の値に影響を与えないことに注意してください。

OPL3 のオペレータでは、ピッチ関係のパラメータには

  • BLOCK
  • F_NUMBER
  • MULT

の3つがあります。
BLOCK はオクターブを指定するバラメータで、0 を最低、7 を最高とする 8 オクターブが指定可能です。
F_NUMBER は、詳しくは後で説明しますが、オクターブ内のリニア周波数に比例する数値です。
基本のピッチの指定は、C 言語の式で書けば、

phinc = F_NUMBER << BLOCK;

により、BLOCK と F_NUMBER を使って表現されます。
実際のオペレータの周波数は、この基本のピッチに MULT で符号化された倍率を掛けたものになります。
その対応表は次のようになります。

MULT 0 1 2 3 4 5 6 7
倍率 1/2 1 2 3 4 5 6 7
MULT 8 9 10 11 12 13 14 15
倍率 8 9 10 10 12 12 15 15

同じ発音単位に属する全てのオペレータは、基本的には同じ基本ピッチ情報を共有しますから、ひとつのフェーズ・ジェネレータから基本ピッチの位相情報を各オペレータに配り、各オペレータではそれを MULT 倍して使うことができます。
しかし、実際には、各オペレータごとに、本当の周波数変調であるビブラートのあり/なしを選択できるようになっているので、フェーズ・ジェネレータは、それぞれのオペレータが自前のものを持っています。
モジュレータとキャリアとが同じビブラート深度であれば、出力の波形は変化せず、純粋なビブラートとして、周波数だけが変化することになります。
モジュレータとキャリアのビブラート量が違うと、出力波形は変化し、アナログシンセ用語で言うグロウル (growl) 、つまり VCF に LFO の変調をかけた状態になります。