FM音源プログラム (13) -- オペレータ (6)
OPL3 の音源チップでは、リニア周波数的な表現である F-NUMBER、BLOCK の組でピッチ情報を指定します。
一方、KSL (Level Key Scale) では、1 オクターブ当り何 dB という形で出力レベルに補正が加えられます。
この変換は、下の表にしたがって、チップ内部で行われます。
OCT FNUM |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 3.000 | 6.000 | 9.000 |
2 | 0 | 0 | 0 | 0 | 3.000 | 6.000 | 9.000 | 12.000 |
3 | 0 | 0 | 0 | 1.875 | 4.875 | 7.875 | 10.875 | 13.875 |
4 | 0 | 0 | 0 | 3.000 | 6.000 | 9.000 | 12.000 | 15.000 |
5 | 0 | 0 | 1.125 | 4.125 | 7.125 | 10.125 | 13.125 | 16.125 |
6 | 0 | 0 | 1.875 | 4.875 | 7.875 | 10.875 | 13.875 | 16.875 |
7 | 0 | 0 | 2.625 | 5.625 | 8.625 | 11.625 | 14.625 | 17.625 |
8 | 0 | 0 | 3.000 | 6.000 | 9.000 | 12.000 | 15.000 | 18.000 |
9 | 0 | 0.750 | 3.750 | 6.750 | 9.750 | 12.750 | 15.750 | 18.750 |
10 | 0 | 1.125 | 4.125 | 7.125 | 10.125 | 13.125 | 16.125 | 19.125 |
11 | 0 | 1.500 | 4.500 | 7.500 | 10.500 | 13.500 | 16.500 | 19.500 |
12 | 0 | 1.875 | 4.875 | 7.875 | 10.875 | 13.875 | 16.875 | 19.875 |
13 | 0 | 2.250 | 5.250 | 8.250 | 11.250 | 14.250 | 17.250 | 20.250 |
14 | 0 | 2.625 | 5.625 | 8.625 | 11.625 | 14.625 | 17.625 | 20.625 |
15 | 0 | 3.000 | 6.000 | 9.000 | 12.000 | 15.000 | 18.000 | 21.000 |
この表は「YMF715x (OPL3-SA3) -Register Description Document-」(以下「rege」と略記) の Page 7 に掲載されているものと同じです。
表の数値は、オペレータの出力レベルに追加する減衰量を dB 単位で表現したものです。
「FNUM」 は 10 ビット幅の F-NUMBER の上位 4 ビット、つまり b9..b6 を抜き出したものです。 「OCT」 は前に出てきた 「BLOCK」 のことで、表現上の統一が取れていませんが、「rege」の表現に従いました。
この表は KSL=1 の 3 dB/oct の場合で、KSL=2 の 1.5 dB/oct の場合は数値を半分に、KSL=3 の 6 dB/oct の場合は数値を倍にしたものになります。
最初にこの表を見たときには何のことか良く分かりませんでしたが、考えてみたら、実質的には対数変換の表であることが分かりました。
式で表すと、ほほ、
になります。 「3.0」の部分は KSL の値によって「1.5」または「6.0」になります。
「ほぼ」と言ったのは、表の数値と一致させるためには、以下の条件を満たす必要があるからです。
- FNUM=7, 9 に対しては +0.5 した 7.5, 9.5 を計算に使う
- FNUM=14, 15 に対しては +1 した 15, 16 を計算に使う
- log2 の値は小数点以下 3 ビット精度に丸める
- 結果がマイナスの場合は 0 で置き換える
これらの条件も考慮した、「rege」の表と同等の出力が得られる C プログラムを示します。
#include <stdio.h> #include <math.h> // 'log2()' defined void main() { int fnum, oct, i; double fn, ksl, db_per_oct = 3.0; printf(" OCT"); for (oct = 0; oct < 8; oct++) { printf("%8d ", oct); } // for (oct printf("\n FNUM\n"); for (fnum = 0; fnum < 16; fnum++) { printf("%4d ", fnum); fn = (13 < fnum) ? fnum+1 : fnum; if ((7 == fnum)|(9 == fnum)) fn += 0.5; for (oct = 0; oct < 8; oct++) { ksl = log2(fn + 1e-9) - 4.0 + oct; i = ksl * 8 + 0.5; if (i < 0) i = 0; ksl = db_per_oct * i / 8.0; printf("%8.3f ", ksl); } // for (oct printf("\n"); } // for (fnum } // main()
OPL3 ハードウェアを忠実にエミュレートするなら、この表も実装しなければなりません。
しかし、FM音源プログラムでは、「音程ドメイン」の一連の計算の中で KSL 補正値を求めることとし、この表は実装しませんでした。
ビブラート、ピッチベンド、ポルタメントなど、ピッチ情報に影響を及ぼす要素は全て「音程ドメイン」で計算して一本化し、F-NUMBER に集約して扱うことにしました。
次回以降で、この「音程ドメイン」での計算について説明します。