投稿日: Jun 10, 2017 7:16:28 PM
MCUで音源を作るときに必要になるのは
DAC
とりあえずこれがないと始まらない。
PWMで代用してもいいけど速度が出ない。速度が出ない上に高周波が入り込んでフィルタが面倒くさい。
どうしてもPWMがいいって言う場合、Arduinoなら高速PWMというのがあるのでそれを使う。
高速PWMでなら最速で22KHzステレオくらいまではなんとかいける。
SPI DACの場合はライブラリなんかに頼らずにガリガリ書く。
forループなんて遅くなるだけだからすべてのビット分ガリゴリ展開して書く。
これで44.1KHzステレオの出力になんとか間に合います。各種処理を書くと間に合わなくなるかもしれない。というきわどさ。
他にR-2R DACというのがあります。GPIOをめっさ大量に使うのでアレですが、はやい。
余裕で44.1KHzの出力が出来ます。でもGPIOを大量につかうからモノラル出力がいいところ。
ピンがたくさんあるMCUを使うならこれは結構良い方法。
内蔵DACを使う。
ARMならDACを内蔵している物が多いのでこの手段をつかうのがいい感じです。
I2S。
バッファ処理でどうにかするならこれが最善。これまたARMなら内蔵してる場合が多い。
でも音源の場合バッファ処理ってしづらいんで。この辺は。アレ。
外付けにI2S対応のDACが必要になるのもアレ。
次に必要になるのが
タイマー割り込み
具体的な数字でいくと、44.1KHzで音を出す場合、22.6usごとに割り込みする。
たったの22.6usしかオーディオを処理する時間が無いのです。
何が厳しいかこれでわかったかな?
主に必要なのはこの2つだけです。
時間が厳しい以外は至ってシンプルですね。
凝った処理なんてしたら時間も間に合わなくなるし シンプル指向でいきましょう。
具体的な波形の生成方法について。
波形メモリ音源方式
カウンター方式
凝った波形使いたいなら波形メモリ方式になりますし、フェイザーとか矩形波ならカウンターでいいでしょう。
波形メモリでも結局カウンターを使うんですが。
波形メモリの方は周波数に合わせていい感じでインデックスを移動してDACに値を出力してやるという流れ。
カウンター方式は例えばこんな感じ
// 12bit dac
#define maxCount 0xfff
int counter;
int chCount = 100; // for Frequency
counter += chCount;
if(counter > macCount){
counter -= maxCount;
}
if(counter>0){
//output
squareWave = ((counter & 0xf00) !=0 ) ? 0xfff : 0x000;
dacOutput = squareWave; // squre
//dacOutput = counter; // phaser
}
単純な波形しかつくれないけどメモリを殆ど消費しないのでプリミティブな波形しか必要ない場合は有効ですよね。
chCountの数値を変えると様々な周波数を生成できる。わけなのですが実のところcounterが12bitじゃまともに使えません。のであくまでこれは例ってことで。
とりあえずそんなところ?
また気が向いたらちらっと書いてみましょうか。