FM音源プログラム (14) -- オペレータ (7)

OPL3 の音源チップでは、F-NUMBER/BLOCK の組で受け取ったピッチ情報に対して、チップ内部でビブラートをかけます。
ピッチベンド/ポルタメントなどに関しては、チップにその機能はないので、ドライバ/アプリケーション・プログラム側で実現することになります。
FM音源プログラムでは、チップのエミュレーション/ドライバ/アプリケーションがひとつにまとめられている形になるので、それぞれの切り分け方法には自由度があります。
ここでは、ピッチに影響する要素はすべて「音程ドメイン」で集約して計算してしまい、ひとたび F-NUMBER/OCT の組として、リニア周波数に変換されたら、その周波数は変化させないことにします。

音程ドメインと拡張 MIDI ノート

音程ドメイン、すなわち、等しい音程に対しては等しい数値が対応する領域として、MIDI ノート番号を基本に考えます。
MIDI ノート番号は整数値で、1 増えると半音上がります。
MIDI ノート番号 0 が最低音で、8.1758 Hz になります。 この音を含むオクターブを 0 として、この音を「C0」と表記することにします。
いわゆる「中央の C」、MIDI ノート番号 60、周波数で言うと 261.6256 Hz は、ここでの表記では「C5」になります。
一般的な呼び方では「C3」あるいは「C4」となります。
MIDI ノート番号 127 が最高音で、12.544 kHz、「G10」になります。
MIDI ノート番号は整数ですが、この自然な拡張として、小数部を持たせることを考えます。
たとえば、(小数部付きの)MIDI ノート番号 60.1 は C5 の音を 10 セント上げたものと考えるわけです。
この小数部は 2 進小数で表現するのが自然ですが、BCD (Binary Coded Decimal) で表現すれば、セント単位の数値を、丸め誤差なく表現できます。
FM音源プログラムでは、C 言語で書いていることもあって、32 ビット整数の上位 16 ビットを整数部として扱い、下位 16 ビットを小数部として扱っています。
こういう表現方法は MIDI 規格の中でも使われていて、チューニング関係のユニバーサル・システム・エクスクルーシブ*1では、14 ビットの小数部を 7 ビットずつ 2 バイトに分けて、整数部との合計 3 バイトでピッチを表現しています。

ピッチ・イベントのライフサイクルによる分類

EG の場合と同様に、ピッチに影響を与えるイベントをライフサイクルによって分類します。

  • MIDI ノートオンにより発生 (note_f)
    • MIDI ノートオン
  • 任意のタイミングで発生する MIDI イベント
    • コースチューン (RPN#0002) (tune_f)
    • ファインチューン (RPN#0001) (tune_f)
    • マスターチューン (システムエクスクルーシブ) (master_tune_f)
    • モジュレーション (CC#01) (MD_modulation)
    • ポルタメント (CC#65) (MD_porta_sw)
    • ポルタメント・タイム (CC#05) (MD_porta_time)
    • ポルタメント・コントロール (CC#84) (MD_porta_src)
    • ピッチ・ベンド (bend_f)
    • ピッチ・ベンド・センス (RPN#0000) (bend_f)
    • スケール/オクターブ・チューニング (システムエクスクルーシブ) (so_tune_ofs[])
  • LFO のサンプリング周期 (4 ms) で発生

ここで、末尾が「_f」となっているのは、イベントの分類別に値を計算して格納しておく変数名です。

ピッチベンドの処理

ピッチベンド・メッセージでは、符号付き 14 ビットの数値を、符号ビットの右に小数点があるものと解釈して -1.0 〜 +1.0 の数値としておきます。
その値に、ベンド幅が半音単位で表現されている RPN (Registered Parameter Number) #0000 のピッチ・ベンド・センスの数値をかけて、bend_f を設定しておきます。

*1:Bulk Tuning Dump、Single-note Tuning Change など