基本中の基本、チューニングに使うラの音は(一般的に)440Hzです。ここから上のドの周波数を求めてみましょう。
数式は以下のとおりです。
x にはラから何音上下しているかを指定するので、440*(2^(3/12)) = 523Hz という具合で求めます。
式を見れば一目瞭然ですが、この数式で出現する小数はおろか乗除算ははPICでは扱えませんのでソフトで対応する必要があります。
さて、MIDIのキホンを読んだ方は分かると思いますが、ノートオンのイベントは960usかかります。 これは20MHzで動作するPIC16F877では4,800ステップに相当します。ただし、これを16チャンネル全てで計算を行った場合、 1チャンネルはわずか300ステップしかありません。ランニングステータスルールが適用されると33%減になるので200ステップです。
200ステップ以内でそれなりの精度の小数演算を行い、ベロシティの計算をして音源ICにセットするのは確実に無理でしょう。
そこでテーブルリードです。1オクターブ分の音階テーブルを作っておき、そこから値を読み出してレジスタにセットします。 テーブル上の位置を計算するだけなので整数の割り算ルーチンを使えば何とかなりそうです。 オクターブの変更は、テーブルから読み出した値に2を掛ける・割る(1ビットシフトさせる)だけで完成です。
MIDIデータのノートオンイベントについてくるノートナンバーは、0=ド・1=ド#・2=レ…と並んでいます。 これを12で割った値の余りが音階テーブル読み出し用の番号、12で割った商がオクターブになります。 わずか数十ステップで値を求めることができますね。
実際のプログラムでは、ピッチベンド用に半音を64段階に分けた768音階のテーブルを作っています。
数式で表すと、
となりますが、12音階の時と比べてもわずかなステップ数しか変わりません。
PICで文字列などの定数をプログラムに埋め込む場合、RETLWを使った定数テーブルを構成することがあります。 Microchipに掲載されているアプリケーションノート「AN556 - Implementing a Table Read」ではデータテーブルをいかにして作るかという内容が書かれており、大変勉強になります。
今回のプログラムでは、768音階のデータをFM音源とSSG音源の2通り持っています。 しかもチューニングが440Hzと444Hzの2種類あるので合計で4つのテーブルが存在することになり、 さらにテーブルに入れるデータは12ビット(つまり2バイト)のデータなので、RETLWで入れようとすると 768 * 2 * 4 で6,144ワードもの巨大なデータになってしまいます。 6,144ワード中のデータには、いらない4ビットのおまけがつくので1,536ワード分のメモリは無駄になります。
今回はPICNICで使われていた手法で、「プログラムEEPROMに生データを埋め込む」方法でテーブルを作りました。 プログラムEEPROMは14ビットで構成されるので、これだけでデータサイズは半分の3,072ワードになります。ただし、PIC自体がプログラムEEPROMを読み出す機能をもっていないとこの方法は使えません。 分かりやすく言えば、データEEPROMの14ビット版という感じです。