高速化だけが設計ではない

 MIDIのプロトコルは、データリンク層では上のように単純ですが、プレゼンテーション層では若干複雑です。つまり、ステータスバイトによって次にどのようなデータが送られているかというのは変わってくるのです。

 当初は、レイテンシーを可能な限り少なくするために、このようなMIDIメッセージの解釈も含めて、すべてをFPGA上のロジックとして実現することを考えていました。しかし、このような複雑で条件分岐を多く含む部分をロジックで実現した場合、どのようにデバッグをすればよいでしょうか。ここはインターフェース部分なので、受信し得る入力のパターンは無限にあります。まずシミュレーションが困難な上に、仮にシミュレーションで動いたとしても、実際の回路でもうまくいくかどうかは分かりません。ソフトウエアであれば、デバッガで変数の中身を見ることができるのですが、FPGAではそうもいきません。(方法はないわけではありませんが、さまざまなデメリットが発生します。)

 そこで、講師の方に助言を頂いて、受信した1byteを一度CPUに渡し、CPU側で解釈した後、シンセサイザーの対応するパラメーターを保存するレジスターに書き込むという形を取ることにしました。

 CPUとのやり取り部分を書くのは、それなりに労力が要ります。さらに、間にCPUを挟むことによって処理時間のオーバーヘッドは生まれてしまいます。しかし、開発は格段に楽になりました。一度CPU側でパラメーターの値を読み書きできるような形にしてしまえば、もしキーボードを弾いてうまく音が出なかった時、その問題がMIDI受信回路の方にあるのか、それともシンセサイザーの発音部分にあるのかを特定できます。キーボードを使わなくても、CPUからの制御で音を鳴らすことができるので、例えばMIDIファイルを使ってシンセサイザー部分を制御する、といった拡張も簡単になります。さすがに講師の方はプロです。独学では、つまずいて確実に何週間かムダにしていたでしょう。

やっとシンセサイザー本体の実装へ

 無事、キーボードからMIDIメッセージを受信できるようになり、取りあえず鍵盤を押して音が出るような何かを作ることができました。これで、やっとシンセサイザー本体部分に取り掛かることができます。

 作成したのは、波形テーブル式という、最も単純な仕組みのシンセサイザーです。肝心な部分なのですが、詳しく書くとサンプリング定理からシンセサイザーの仕組みまでだらだらと解説するだけになってしまいますので、説明は他の資料に譲ることにして、簡単に説明します。

 波形テーブル式のシンセサイザーのコア部分は、あらかじめ決められた波形テーブルから、周波数に応じたスピードで順番に値を取り出していくことで、任意の周波数の波形を生成する、というものです。

 もちろん、波形テーブルをどのくらいの細かさで持つか、波形テーブルの値はどのくらいのビット数にするか、といったことは設計の段階で検討します。あまりに細かすぎると回路を圧迫してしまいますが、粗ければノイズが目立ってしまいます。今回はテーブルの深さを1024、値を10bitで持つことにしました。さらに、波形テーブル自体を、書き込み時のアドレッシングを工夫することで発音を途切れさせることなくCPUから書き換えられるようにしました。

 こうして作成した、テーブル再生部(オシレーター、VCOと呼びます)に加えて、これらにフィルターをかけるモジュール(VCF)、音量を調整するモジュール(VCA)を作成します。さらに、鍵盤を押してからの音色変化を起こすためのモジュール(エンベロープ・ジェネレーター)や、低い周波数で継続的な変化を起こすためのモジュール(LFO)を作成し、VCO/VCA/VCFの3つのパラメーター自体を、これらのモジュールからの入力で変化させることができるようにします。VCOのピッチに関しては、さらにMIDIキーボード上のモジュレーション・ホイールを操作することで、ある程度の操作ができるようにします。

シンセサイザーの構成
[画像のクリックで拡大表示]

 ここは以前ソフトウエアでシンセサイザーを開発した経験があるので、ひたすら実装を進めました。なお,シンセサイザーに関しては、このサイトが参考になります。