FM音源プログラム (6) -- EG (6)

「YMF715x(OPL3-SA3) -Register Description Document-」(以降「rege」と省略) のエンベロープ・レートと時間との対応表について、詳細に検討してみました。
現在のFM音源プログラムは、テーブルを使ってエンベロープ・レートからアキュムレータの増分値を得ています。 このテーブルは、2^{-{\rm rate}/4} に比例する値をプログラムで計算して作成しています。
「rege」の表と、なるべく一致するような値を選んでいるのですが、微妙に違っているのが気にはなっていました。
深く追求しないで放っておいたのですが、今回、詳細に検討してみて、ハードウェアでの実現方法の片鱗が見えてきたような気がします。
まずは、アタック・レートの 0-100 % の時間の表について調べます。
実ARの値が 4 増えると時間が 1/2 になるのは自明ですから、4 以内の差について、アタック時間の比を求めます。

AR アタック時間 (AR-1)の値との比 AR=4の値との比
4 2826.24 --- 1.00000 = 69/69
5 2252.80 0.79710 = 55/69 0.79710 = 55/69
6 1884.16 0.83636 = 46/55 0.66667 = 46/69
7 1597.44 0.84783 = 39/46 0.56522 = 39/69
8 1413.12 0.88462 = 69/78 0.50000 = 69/138

ちなみに、プログラムで作成したテーブルでは、隣との比はすべて等しく、2^{-1/4} = 0.8409 です。
クロックの分周比が大きければ、分周後のクロックは遅くなり、そのクロックで駆動される回路の時間は長くなります。 同様に、分周比が小さければ、分周後のクロックは速くなり、時間は短くなります。
したがって、この表から、

  • (AR mod 4) = 0 のとき 69 分周
  • (AR mod 4) = 1 のとき 55 分周
  • (AR mod 4) = 2 のとき 46 分周
  • (AR mod 4) = 3 のとき 39 分周

したクロックを EG ハードウェア回路のクロックとして使用すれば、上の表の時間の比率を実現できることになります。
(AR div 4)、つまり、元の音色パラメータの AR 値は、EG アキュムレータをインクリメントするビット位置の選択に使います。

この考えで、「rege」の表と同等の表を出力する C プログラムを下に示します。

#include <stdio.h>

#define fs (400e3)
#define EGACC_MAX (0x4000L)

int ardiv[] = { 69, 55, 46, 39 };

double calc_attacktime(int rate)
{
  double fclk;
  fclk = fs / ardiv[(rate & 0x03)];
  return((EGACC_MAX >> ((rate>>2) - 1))/ fclk);
}

void main()
{
  int i;
  double t;
  printf("Rate Time [ms]\n");
  for (i = 4; i < 60; i++) {
    t = 1e3 * calc_attacktime(i);
    printf("%3d %9.2f\n", i, t);
  } // for (i
}

AR=0〜3 はエンベロープ変化なし、AR=60〜63 はアタック・タイム=0 となる特別な場合なので、上のプログラムでは除外しています。
このプログラムでは、400 kHz のメインクロックを 1/69, 1/55, 1/46, あるいは 1/39 の周波数に分周して、約 5.8 〜 10.3 kHz の EG クロックとし、重み 2^{({\rm AR div\,} 4) -1} のビットだけが立っているビットパターンで 14 ビット・アキュムレータに加算するというイメージです。
このプログラムの出力と「rege」の表を比べて、下のような誤りを発見しました。

AR
20 176.76 176.64

多分、これは、データを人手で入力した時の誤りだと思います。
「rege」の同じ表の 10-90 % の立ち上がり時間については、単に 0-100 % の値と比例関係にあると思っていましたが、実際に詳しく調べてみると、

AR 時間 (AR-1)の値との比 AR=4の値との比
4 1482.75 --- 1.00000 = 181/181
5 1155.07 0.77901 = 141/181 0.77901 = 141/181
6 991.23   0.85816 = 121/141 0.66851 = 121/181
7 868.35 0.87603 = 106/121 0.58564 = 106/181
8 741.38 0.85378 = 181/212 0.50000 = 181/362

となり、0-100 % の場合と結果が違います。
これは、なぜなのか、良く分かりません。