シンセ・アンプラグド RSSフィード

2016-12-01

FPGA 版 FM 音源 (50) -- YMF297 (OPN3/OPL3) 測定 (15) -- EG クロック・プリスケーラ (2)

2016 月 11 月 18 日付けの記事 (→こちら) で述べた EG クロック・プリスケーラの動作は、よく考えればレート・マルチプライア (rate multiplier) そのものでした。

パイプライン方式で複数オペレータを実現する場合に各オペレータ固有の内部変数として 8 進レート・マルチプライアの状態を保持する必要があると思っていましたが、EG クロック・プリスケーラをレート・マルチプライアで実現すれば、ひとつのプリスケーラ・ハードウェアを全オペレータで共有でき、内部変数を持つ必要はなくなります。

FPGA / CPLD での RTL 記述、およびソフトウェアによる実現に適した計算方法を下に示します。 (対象はローレートのみ)

f:id:pcm1723:20161130200211p:image:left

ローレート、つまり RATE <= 12 に対して fs クロックを分周する 12 ビットのバイナリ・カウンタが必要ですが、Rof の処理も含めるとさらに 2 ビット拡張して 14 ビット幅の演算が必要になります。

左の図で「COUNTER」と書いてあるのは、ソフトウェアでは普通の変数を順次インクリメントすることでカウンタを実現することを意味し、FPGA / CPLD の RTL 記述ではレジスタ変数に対して「+」演算子によりインクリメントすることでカウンタを実現することを意味しています。

実際に HDL で実現されるカウンタの内部回路の詳細については気にしないことにします。

左の図で「z-1」と表現してあるのは、1 サンプル前のカウンタの内容のコピーです。

ソフトウェア的には単なる変数ハードウェア的には 14 ビット幅の D-FF です。

カウンタの現在値と、1 サンプル前の値 (の反転) とから、ビットごとの AND を取ってカウンタの各ビットの「立ち上がり」エッジを検出しています。

左の図の上半分で作成されバレル・シフタへ入力される信号のタイミング・チャートを下に示します。

f:id:pcm1723:20161130200209p:image

それぞれ fs 1 周期分のパルス幅の、互いに重なり合わないパルス列となっています。

レートの値によりバレル・シフタで選び出した連続する 3 ビットの信号を Rof の値により合成して最終的に EG クロック・イネーブル信号を得ます。

下に例を示します。

f:id:pcm1723:20161130200213p:image

上半分の青いトレースがバレル・シフタ出力の 3 つの波形です。

b0 が Rof == 0 に対する基本のレートで、Rof の値にかかわらず常に出力へミックスされます。

そして、Rof[0] == 1 なら b2 の信号がミックスされ、Rof[1] == 1 なら b1 の信号がミックスされます。

Rof のビットの並びと、クロック・プリスケーラの出力のビットの並びは互いに逆になっています。

上の図の下半分の赤色のトレースが Rof と波形の「ミックス」との対応を示しています。

パルス出力可能なポジションが全部で 8 個ある中で、

  • Rof == 0 では 4 パルス
  • Rof == 1 では 5 パルス
  • Rof == 2 では 6 パルス
  • Rof == 3 では 7 パルス

出力されています。

これは 2011 年 2 月 1 日付けの記事(→こちら) のレート・マルチプライア部の「CLK_EN」の真理値表と「位相」は異なりますが同じことを表しています。

前傾の計算方法を C プログラムで実現した例を下に示します。 (ローレートのみを考慮)

uint32_t psc_cnt = 0; // prescaler counter
uint32_t psc_z1  = 0; // 1 sample delay

// Calculate prescaler clock enable by rate multiplier
uint32_t calc_psc_en(int rate, int rof)
{
  uint32_t psc_en;

  rof = (((0x01 & rof) << 2) | (0x02 & rof) | 0x01);  
  psc_z1 = psc_cnt++;   // 1 sample delay and increment
  psc_en = (~psc_z1 & psc_cnt); // pos edge detect 
  return(0 != (rof & (psc_en >> (12 - rate))));
} // uint32_t calc_psc_en();

ビット逆順になっている「rof」のビットを「マスク・パターン」に変換している部分以外は、非常に簡単な処理で済んでいます。

次回は FPGA / CPLD で実現されるカウンタの中身までゲート・レベルで記述する場合について述べます。

2016-11-28

FPGA 版 FM 音源 (49) -- YMF297 (OPN3/OPL3) 測定 (14) -- EG ミュート状態

リニア出力のアナログ EG では、ディケイ/リリース回路に 1 次 RC 回路の放電特性エクスポネンシャル・カーブを利用していれば、時間の経過とともに出力電圧はサステインあるいはグラウンド・レベルへ限りなく接近していきます。 

リリース状態で「放置」していても、グラウンド・レベルに貼りついたままであり、不都合を起こす心配はありません。

一方、対数ドメインで動作するディジタル EG では、ディケイ/リリースのエクスポネンシャル・カーブでの減衰は、EG アキュムレータに定数を足しこんでいって、減衰量を増やすことによって実現されています。

リリース状態を「放置」しておくと、どんどん増加する EG アキュムレータの値がいつかは最大減衰量を超えてオーバーフローし、ラップ・アラウンドして減衰量が小さな状態に突入してしまいます。

したがって、EG アキュムレータの値の更新を最大減衰量 (あるいは、その付近) で停止させる、「OFF」あるいは「ミュート」と呼ぶべき状態を設ける必要があります。

下に実チップのキャプチャではなく、アタック/ディケイのみのソフトウェア EG シミュレーションプログラムを使って作成した、最大減衰量付近のふるまいの図を示します。

f:id:pcm1723:20161127150206p:image

上の図は、DR = 13 〜 15、Rof = 0 〜 3、レート・マルチプライアの位相 = 0 〜 7 の範囲に渡ってシミュレーションした結果の EG アキュムレータの値を重ねてプロットしたものです。 EG アキュムレータの値が 511 を (含んで) 超える時点のサンプル・インデクスを「0」としてあります。

DR = 13, Rof = 0 より「遅い」レートでは EG アキュムレータの増分は高々「1」なので、9 ビット EG アキュムレータで表現可能な最大減衰量である

  511 = 0x1F = 95.8125 dB

を必ず通過することになります。

DR = 13, Rof = 1 より「速い」レートでは EG アキュムレータの増分は「1」以外に「2」と「4」も登場するので、EG アキュムレータの値は「511」を飛び越して、「512」や「514」(に相当する値) になる可能性もあります。

上の図では、ソフトウェアシミュレーションなので 511 以上の値を保持していますが、実際の 9 ビット EG アキュムレータではオーバーフローしてラップ・アラウンドを生じ、

  (0x1F & 512) = 0 = 0 dB

  (0x1F & 514) = 2 = 0.375 dB

という小さな減衰量の状態となってしまいます。

上の図から、EG アキュムレータの値が 511 以上となる時点の 1 サンプル前の最小値を読み取ると、

  508 = 0x1FC = 9'b111111100 = 95.25 dB

となります。

つまり、EG アキュムレータの値が 508 以上となったことを検出して EG アキュムレータの値の更新をストップすれば、値がラップ・アラウンドする心配はなくなります。

この「検出」は「大小比較」ではなく、EG アキュムレータの上位 7 ビットのみの「一致」を調べるだけで実現できます。

Verilog 風に表現すれば、

(7'b1111111 == eg_acc[8:2])

となります。

2016-11-27

FPGA 版 FM 音源 (48) -- YMF297 (OPN3/OPL3) 測定 (13) -- EG パラメタ・レジスタ

今回の小ネタは、OPL3 の EG パラメタ (AR/DR/RR) の値が有効になる (参照される) タイミングについてです。

結論から言えば、アタック/ディケイ/リリースで、その状態に対応するレート・レジスタ AR/DR/RR が選択されている限り、ラッチされることはなく常に素通しで、ホスト・マイコンがそのレジスタの値を書き換えるとリアルタイムに出力に反映されます。

サステイン・レベル (SL) に関しては、サステイン状態への遷移の判断に使われるだけで、いったんサステイン状態に進むと、SL の値を変更しても EG の状態は変化しません。

EG がリリース状態になってから遂次 RR を減衰が早くなるように書き換えた場合の、実チップの EG 出力のキャプチャ結果を下に示します。

f:id:pcm1723:20161127150204p:image

「湾曲」した「折れ線」状態になっていますが、「湾曲」はリリースがエクスポネンシャルで変化するためであり、「折れ線」になるのは RR の数値を増やした結果が素通しでリアルタイムに反映されているためです。

これは、パイプラインおよび時分割多重 (タイム・スロット) 方式で 1 組のオペレータ・ハードウェアを多重化して利用する場合にオペレータごとに必要となる内部変数を減らすためと思われます。

たとえば、フェーズ・アキュムレータは発音チャネルごとに、EG アキュムレータおよび EG ステートマシン変数はオペレータごとに必要になります。

EG パラメタ・レジスタを何かのタイミングでラッチしてから利用すると、そのラッチした値を内部変数として保存する必要が生じ、ハードウェア量の増加を招きます。

ソフトウェアでは特に意図したものでない限り、そのレート・レジスタが有効な状態では値を変更しないという「お約束」にしておけば、特にハードウェアで値をラッチしておく必要もありません。

2016-11-26

FPGA 版 FM 音源 (47) -- YMF297 (OPN3/OPL3) 測定 (12) -- サステイン・レベル

今回は、OPL3 の音色パラメタの「SL」(Sustain Level) と実際の EG 出力のサステイン・レベルの不一致についての話です。

音色パラメタの SL は 4 ビットの値で、dB 単位の出力レベルと各ビットとが下の表のように対応づけられています。

b3 : -24 dB

b2 : -12 dB

b1 : -6 dB

b0 : -3 dB

たとえば、SL = 1 では出力レベル = -3 dBSL = 14 では出力レベル = -42 dB の指定となります。

EG アキュムレータがこの値に等しくなった場合に、EGT = 1 では (KON = 1 である限り) サステイン・レベルを維持する状態となり、EGT = 0 では、ではディケイ・レート (DR) での減衰からリリース・レート (RR) での減衰に切り替わります。

9 ビットの EG アキュムレータとアライメントを合わせると、

EG_ACC[8] : 0

EG_ACC[7] : SL[3]

EG_ACC[6] : SL[2]

EG_ACC[5] : SL[1]

EG_ACC[4] : SL[0]

という対応関係で数値を比較することになります。

EG アキュムレータの最上位ビット EG_ACC[8] に対しては、「定数」のゼロと比較します。

DR = 13, Rof = 0 以下では、EG アキュムレータは fs クロックごとに高々 1 増加するだけです。

その場合、上記の 5 ビットの値が最初に一致するのは EG アキュムレータに 1 を足した結果、EG_ACC[3:0] がゼロになって EG_ACC[4] に向かってキャリーが発生し、Verilog 風に表現すれば、

EG_ACC[8:4] == {1'b0, SL[3:0]} 

となる場合に限られます。

したがって、下位 4 ビットは全く考慮することなく、上位 5 ビットだけを見ていれば SL パラメタで指定されたサステイン・レベルに達したことが検出できます。

一方、DR = 13, Rof = 1 以上では、 fs クロックごとに EG アキュムレータの値が 2 あるいは 4 変化する可能性があります。 その場合には上位 5 ビットが一致した時点で下位 4 ビットがゼロになるとは限りません。

下にそのような例を図で示します。

f:id:pcm1723:20161126041408p:image

(a) の図は、EG アキュムレータの増分が 1 / 2 / 4 の固定値で、上位の一致を見るだけで n サンプル目で下位ビットまで一致する場合です。

(b) の図は、EG アキュムレータの増分が 1 / 2 / 4 が混在する場合で、n-1 サンプル目まで上位ビットが一致せず、n サンプル目で上位ビットが一致しますが、下位ビットはゼロとならず、サステイン・レベル・パラメタ (SL) で指定される値を行過ぎる場合です。 EG の値としては過剰に減衰して出力されることになります。

(b) の場合、過剰に減衰する形となった EG 出力値を SL で指定される値に置き換えることも回路的には可能ですが、実チップを測定すると、出力値の置き換えは行なわれていません。

キャプチャした結果の図を下に示します。

f:id:pcm1723:20161125145814p:image

EG 関係のパラメタを

Rof = 3

AR = 13

DR = 14

SL = 1 (-3 dB)

として、KON の間隔を奇数に選んで繰り返したものです。 この設定では、ディケイにおける EG アキュムレータの増分は 2 と 4 の混在となります。

上の図で青色トレースで示されているのが、SL パラメタで指定されるサステイン・レベルのリニア値に等しい 2888 となる場合です。 (EG アキュムレータ値としては 9'b000010000 )

赤色のトレースで示されているのが過剰に減衰してサステイン・レベルのリニア値が 2766 となる場合です。 (EG アキュムレータ値としては 9'b000010010 )

SL で指定した通りのサステイン・レベルになるか、過剰に減衰したレベルになるかは、レート・マルチプライアの位相によって決まり、8 回の繰り返しの中で SL 通りの出力値 2888 が 7 回、過剰な減衰の 2766 が 1 回表れます。

これがモジュレータ出力の EG 波形とすると、タイミングによっては、サステイン時の変調レベルに 0.375 dB の変動が生じることになり、厳密には音色にわずかな変化が生じることになります。

2016-11-18

FPGA 版 FM 音源 (46) -- YMF297 (OPN3/OPL3) 測定 (11) -- EG クロック・プリスケーラ (1)

OPL3 の EG では、AR/DR/RR で指定するレートが 13 の場合に fs クロックごとに EG アキュムレータの値が変化するようになり、レートが 12 を含んでそれ以下になる場合には、EG アキュムレータを更新するクロックが fs を分周したもの (プリスケールされたもの) になります。 (キーレート・スケーリングによる Rof = 0 の場合)

レート = 12 では 2個ずつ EG の同じ値が繰り返され、レート = 11 では同じ値 4 回の繰り返し、... と続き、レート = 1 では 4096 回の繰り返しとなります。

アタック/ディケイのみをサポートする EG を Verilog で 書いた以前の記事 (→こちら) では、アタック → ディケイの遷移の度に fs プリスケーラをリセット (に相当する処理を) していましたが、OPL3 の実チップを測定すると、プリスケーラは「フリーラン」で動いているらしいことが分かりました。

下に AR = 9 (fs/16 クロック)、DR = 9 (fs/16 クロック) での、アタック → ディケイのトランジェント部分を波形編集ソフトで表示したものを示します。

f:id:pcm1723:20161118023916p:image

左右中央付近で 4100 の罫線に近い EG 出力値は正確には 4094 で、EG 出力の 0 dB に相当し、アタック・カーブのピーク部分です。

垂直の黄色い点線 (カーソル) はアタック → ディケイの切り替わり部分と推定されるタイミングです。

AR = DR = 9 なので、A → D と切り替わってもプリスケーラの設定は同じで、当然、「位相」が乱れることもなく 16 個ずつ同じ値を繰り返しています。

次は AR = 9 (fs/16 クロック)、DR = 10 (fs/8 クロック) の場合です。f:id:pcm1723:20161118023555p:image

DR = 10 では同じ値 8 個の繰り返しとなりますが、A → D 切り替え直後だけは 4 個の繰り返しとなっています。

次は AR = 9 (fs/16 クロック)、DR = 11 (fs/4 クロック) の場合です。

f:id:pcm1723:20161118023556p:image

DR = 11 では同じ値 4 個の繰り返しとなりますが、A → D 切り替え直後だけは 2 個の繰り返しとなっています。

次は AR = 9 (fs/16 クロック)、DR = 12 (fs/2 クロック) の場合です。

f:id:pcm1723:20161118023558p:image

DR = 12 では同じ値 2 個の繰り返しとなりますが、A → D 切り替え直後も含めて 2 個の繰り返しとなっています。

次は AR = 9 (fs/16 クロック)、DR = 13 (fs クロック) の場合です。

f:id:pcm1723:20161118023600p:image

DR = 13 では fs ごとに変化する形となりますが、A → D 切り替え直後だけは 2 個の繰り返しとなっています。

これは A → D 切り替えのオーバーヘッド分が「余計」な 1 サンプルとして見えているものと思われます。

以上の例は AR <= DR、つまり、アタックのクロックの方が「遅い」場合です。

EG クロック・プリスケーラはフリーランと思われるので、アタック・カーブの変化タイミングは fs クロックを 16 分周したクロックの有効エッジのタイミングに限られます。

それはディケイ・カーブの変化タイミングより「制約」が大きいので、キーオン・タイミングにかかわらず、上で示したような EG 出力となります。

AR >= DR、つまり、アタックのクロックの方が「速い」場合を下に示します。

AR = 13 (fs クロック)、DR = 9 (fs/16 クロック) でキーオン間隔を奇数に選び、キーオン・タイミングが 16 種の位相に渡る場合を重ねてプロットしています。

f:id:pcm1723:20161118024641p:image

波形編集ソフトでは表示しにくいので、キャプチャした wave ファイルを読み出して数値データのファイルとして書き出し、gnuplot で表示しています。

アタック側は「制約」なくアタック・カーブを任意の fs タイミングで開始できるのに対し、ディケイ・カーブはフリーランの fs/16 のタイミングでしか変化できないため、A → D 切り替え直後の繰り返しは 1 〜 16 に渡って変化しています。

以上の結果から推測される fs プリスケーラのタイミング・チャートを 4 ビット分だけ下に示します。

f:id:pcm1723:20161118023913p:image

初段の FF を除き、前段のクロックの立下りでトグルするリプル・カウンタ出力の、立ち上がりを有効エッジとして利用する形になっています。

たとえば、Q4 → Q3 の切り替えでは、4 ビットカウンタのカウント値を 16 進数で表現して、

  7↑89ABCDEF01234567↑89AB↑CDEF0123↑456789AB↑C

となります。 ここで、「↑」は出力されるクロックの有効エッジを示すものとします。

上の例では、EG 値の繰り返し回数が

  ・16・4・8・8・...

となり、実チップの実測値と一致します。

FPGACPLD では、逆極性のクロックやリプル・カウンタは実現しにくいので、実際には全ての FF のクロックは fs とし、上の図で EN1 〜 EN4 で示したような「クロック・イネーブル」信号を作成して利用することになります。

2016-10-31

FPGA 版 FM 音源 (45) -- YMF297 (OPN3/OPL3) 測定 (10) -- モジュレーション入力

ほぼ 1 年前 (→2015 年 9 月 20 日の記事) に OPL3 モードに設定した YMF297 で、セルフ・フィードバックの経路に FIR LPF が存在することを確認しました。

そのときから気になっていたのですが、「普通」のモジュレーション入力のパスには LPF がなく、入力値が計算にダイレクトに寄与することを、実チップ出力をキャプチャしたものとプログラムシミュレーションした結果をつき合わせて実際に確認しました。

モジュレータ」となるオペレータの波形は、下図のように、FB = 5, TL = 4 と設定しました。

f:id:pcm1723:20161031025020p:image

TL = 4 は出力レベル -3 dB に相当し、TL = 0 のフルスケールの場合よりセルフ・フィードバックによる「振動」の程度が低くなっています。

変調された「キャリア」側のオペレータの出力を下に示します。 (キャリアは TL = 0)

f:id:pcm1723:20161031025017p:image

青色の線がプログラムによるシミュレーション結果で、赤色の線が実チップからキャプチャした結果です。

両者は一致しており、青色の線は赤色の線の下に隠れて全く見えません。

ディジタル・データとしても完全に一致しています。

2016-08-19

新版FM音源プログラム (12)

2016 年 1 月 1 日付けの記事 (→こちら) の 4 K エントリの場合と同様に、テーブル・インデクスを「マスク」する方法により、テーブル・サイズを 3.75 K (3840) エントリまで削減することができました。

また、4 K エントリの場合と同様に、符号の操作も併用すると、3 K (3072) エントリまで減らすことができました。

3.75 K エントリのウェーブテーブル全体をプロットしたものを下に示します。

f:id:pcm1723:20160819154445p:image

テーブル・インデクス 0 〜 1535 までが WS = 0, 1, 2, 3, 6 で共有している部分で下の図のようにアクセスします。

f:id:pcm1723:20160819154443p:image

青いバーで示している範囲をアクセスします。

WS = 0, 1 は 1024 エントリ、WS = 2, 3 は 512 エントリ、そして WS = 6 は 2 エントリのみのアクセスになります。

黒い三角印がノート ON 時に設定する初期位相の位置を示しています。

WS = 7 については図示してありませんが、テーブル・インデクス 1536 〜 2559 までの 1024 エントリをアクセスします。

テーブル・インデクス 2560 〜 3839 までが WS = 4, 5 で共有している部分で下の図のようにアクセスします。

f:id:pcm1723:20160819154447p:image

この 3.75 K エントリの方法では、符号の操作はせず、テーブルから読み出した値をそのまま使います。

WS の値により、テーブルから読み出した値の符号を落として、正の値として扱う操作を加え、エントリ数を 3 K (3072) まで削減したものを下に示します。

f:id:pcm1723:20160819154449p:image

WS = 4, 5, 7 の場合のアクセス範囲も示してあります。

WS = 4, 5 の範囲は全く同じで、 WS = 5 の場合だけ読み出したデータの符号を落として、すべて正の数として扱います。 WS = 5 以外では、読み出したデータの符号をそのまま使います。

WS = 0, 1, 2, 3, 6 で共有している部分は下の図のようにアクセスします。

f:id:pcm1723:20160819154453p:image

これは 3.75 K エントリの場合とウェーブテーブル内のオフセットが違うだけで、処理方法としては同じです。