[1chipMSX]
VM2413 SineTable の量子化ノイズ軽減
※情報の正確さは保証できません。
OPLL は、sin波をベースに波形を生成しています。VM2413 では、この sin波を波形テーブルで保持しており、
その分解能は 90度 あたり 512 サンプルという、結構粗いモノになっています。
テーブルのサイズを大きくすればもっと細かくなりますが、そんな対応は面白くないので、補間演算を入れてみる
ことにしました。
まずは、補間前の SineTable の波形を fig.1 に示します。
fig.1 SineTable (補間前)
値が小さいところはわりと滑らかですが、値が大きなところではかなりギザギザしています。
この波形は、対数表現での値なので、値が大きなところの微妙な差は、線形波形に直すと大きな差になって現れます。
つまり、むしろ大きな値の方が滑らかであって欲しいところです。
SineTable は、Operator 内部にインスタンスされていますが、そのアドレス計算に用いるタネは、PhaseGenerator が
出力する値になっています。
PhaseGenerator は、出力値の小数部を削って(回路としては未配線なだけ)から出力していますが、この削る行為を
やめて、そのまま全ビット Operator に投入するように改造します。
具体的に PhaseGenerator で小数部を削っているのは、下記の部分です。
pgout_buf := CONV_PGOUT(memout);
一見すると、単なる型変換にみえる記述ですが、CONV_PGOUT の中身は下記のようになっています。
function CONV_PGOUT ( pv : PHASE_TYPE ) return PGOUT_TYPE is
begin
return pv(PHASE_TYPE'high downto PHASE_TYPE'high - PGOUT_TYPE'high);
end;
「downto」の右側が 0 でないため、PHASE_TYPE'high - PGOUT_TYPE'high ビットだけ、下位ビットを削っています。
これは、演算上では小数部を意味する部分ですが、アドレス値としては小数部は使えませんが、値を補間する補間係数
としては十分利用価値のある値なので、捨てずに全て値を渡すように書き換えます。
(どのように書き換えるのかは、省略 (^^; )
Operator の中身に移り、SineTable のアドレス計算部分に注目します。
SineTable の addr 入力には、pgout (PhaseGenerator の出力) がそのまま投入されています(※一部、リズム音色の
場合は、専用処理が入ってます)
SineTable の補間演算は、sin波形が滑らかになる と言う意味なので、SineTable.vhd の中に構築することにします。
従って、幅の広がった pgout はそのまま SineTable に渡されることになります。Operator の修正は、その幅の修正
に対応することと、リズム音色の専用処理をその幅に対応させることです。
(修正箇所が多いので、修正方法は、修正後のソースを参照してください)
SineTable.vhd を見てみます。
sin波を第1象限の分(0度〜90度)の範囲だけをテーブルとして保持していて、残りはそれをX軸・Y軸で反転する
ことで生成しています。
演算遅延としては、波形メモリから読み出す1サイクルだけです。
反転のためのアドレス変換の回路が複雑にみえたので少し整理。
波形メモリから補間演算用に、連続アドレスの2値を読み出し、その2値を加重平均(線形補間)することにより
オリジナルよりも滑らかな sin波を生成します。
従って、アドレス変換回路には連続する2アドレスを求める処理を追加、波形メモリには2値を同時に読み出せるように
する変更を加えます。
線形補間は大きな乗算器を1つ使うのと、加算もいくつか含まれるため、若干重たい処理になります。それに加え、SineTable
の出力結果を Operator 内で、さらに演算するため、演算遅延が大きくなってしまいます。
これをそのまま組み込んでみたところ、1chipMSX 全体が不安定になってしまいました(表示が乱れたり、暴走したり)。
演算遅延が大きくなるというのは、演算回路に入力値が投入されて、出力が安定するまでの時間が長くなるという意味で、
これが 1clock をオーバーすると、結果をラッチするフリップフロップに不正な値が記憶され、挙動不審に陥ります。
これを避けるには、演算途中に適時フリップフロップを挟み、その都度足並みを揃え、フリップフロップ間の演算遅延が
1clock に収まるように調整していく必要があります。
VM2413 では、各ブロックのタイミング制御信号として Stage と Slot という値を用いていますが、各ブロックに投入
されている Stage, Slot は微妙にズレがあります。それをふまえた上で、出力に悪影響を与えないような遅延調整を
行って、補間演算を安定化させました。
[タイミング調整(PDF)]
上の PDF で、赤い矢印は依存部分です。赤い文字は、今回のタイミング調整のために変更した部分です。
この修正によって、SineTable 補間演算追加による 1chipMSX の挙動不審は改善されました。
修正後の SineTable 波形を fig.2 に示します。
fig.2 SineTable (補間後)
上の fig.1 と比べて波形が滑らかになっているのが確認できると思います。
修正は、
最新版デザインデータに含まれています。
[▲上へ]