gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

FM音源(もどき)dsPIC(続き)

オルゴールです。それっぽい音()が出ました。

いきなり解説ページということです。ハードはPCMPlayerとほぼ同じでモノラルである点だけ異なります。FM音源を2OPかつフィードバックなしで調節もなしというFM音源らしくない音源ですが、同時発音数は20オンを達成することが出来ました。やった〜。はい。

概要を説明すると,SD=>dsPIC=>DAC(dsPIC)=>AMP

という感じです。SDには譜面を入れておきます。MIDIは面倒なので独自形式でXD。まあいいっしょ。dsPICでは音の計算、合成、出力をやっています。では音の計算からはなしを進めましょう。

音の作成にはsinを基本としたテーブルを参照して合成、再生します。もともとsinを使うことで自然に近い音色を出すことができます。しかしこのままだともごもごした音になるのでここから位相変調をかけて合成し、他のチャンネルの音をさらに合成し、再生します。そのため矩形波等にくべてものすごく負荷が高いです。それはしょうがないんですよね。でも性能がある程度あればごまかせます(笑)あとは最適化の問題でどれだけ演算をハードウェアに対してチューニングできるかにかかっています。演算によって負荷は大きく変わります。テーブルは基本sinのみなので少なくて済みます。8bitの128pointのテーブルを作っておきます。cosだとプツプツした音になりそうなので。

まずはsin波を再生します。これはどうしようもないことなのですが波形を再生するときには128pointだけなので誤差が大きくなります。例えば加算方式の場合。これは周波数に対して比例した出力を出せるため高域も正確な周波数が出ます。テーブル分割方式の場合、これは低域にて正確な周波数が出ます。ですがこれは正確さはありますが高域では音が狂ってしまうほかテーブルの分割数、サンプリング間隔によっては高域が出ません。sinの分割間隔が128以上であるとメモリー空間を食います。なので仮想上の空間として128*16だけの分割点を用意し、その中で計算し最後に/16して128点で計算します。この時に加算方式を取ると非常に良い特性を得ることができます。(しかし使っているマイコンが16bitなので高域でオーバーフローしてしまいました)これはオーバーサンプリングと呼ばれる技術で倍率が高いほど精度が高いと言われています。

[c] //nは2n指定です。

define _OVER_SAMPLING_GAIN 4

define _NUM_OF_SINTABLE

define _SAMPLING_FREQ 44100

define _OUT_FREQ 500

uint iv = (OUT_FREQ * (1<<OVER_SAMPLING_GAIN) * NUM_OF_SINTABLE) / SAMPLING_FREQ uint x = 0; for(uint c = 0;c < <再生時間>;c++){ int output = wavetable[(x >> _OVER_SAMPLING_GAIN) & 0x7F]; x += iv; } [/c]

このようにしてsin波は再生できましたがテーブルを他に変更するとその波形も再生できます。ウェーブテーブル参照型のオルゴールなどの原理です。img_2527

以上の図はテーブル参照型の再生に用いるリングテーブルの図です。その場の位置からある一定の数だけずらしてカウントします。なので毎回波形は少しずれます。これが誤差をうまくキャンセルしてくれます。テーブルサイズは16でさらに4倍のオーバーサンプリングをしている図になります。実際ではオーバーサンプリングは32倍程度でテーブルサイズは256点ほどですかね。でも考え方は同じです。この数が大きいほど誤差が低くなります。ちなみにサンプリング周波数が高いと目標出力周波数との誤差が大きくなります。波形は正確になりますがね。

img_2529その点の値を求める際には点と点の中間の間を取ることも多くあります。その中央まで計算すると綺麗な波形になります。が、少々計算が増えてめんどくさいですね。青が切り捨てた時で赤が中間点を取った時です。計算量が少々あります。角度と角度の間を取るので正確ですが。波形のテーブルサイズも小さくて済む利点もあります。