FM音源プログラム (28) -- MIDI デコーダ(2)

MIDI メッセージのデータバイト部分を処理する md_data_byte() 関数では、すでに読み込んだバイト数を示す MD_bcnt 変数を参照して処理を分けています。
言い忘れてましたが、デコード関係の関数は、「mididec.c」ファイル中に記述されています。
関数が呼び出された時点での MD_bcnt の値と、その意味は次のようになっています。

MD_bcnt == -1
データバイトを全て無視して読み飛ばす
MD_bcnt == 0
新しいメッセージの始まりを期待している状態、つまり、このデータバイトに先立つステータス・バイトがない状態 (ランニング・ステータス)
MD_bcnt == 1
1 バイト入力された、つまりステータス・バイトが読まれた状態で、このデータバイトは1番目
MD_bnct == 2
2 バイト入力された、つまり1番目のデータ・バイトまで読み込んだ状態で、このデータバイトは2番目

MD_bcnt == -1 は、システム・エクスクルーシブ・メッセージが長すぎる時に読み飛ばして、バッファ・オーバーフローを防ぐためのものです。
このほかに、エクスクルーシブ・バッファのインデクス sysx_cnt をエクスクルーシブ処理モードのフラグとしても使っていて、sysx_cnt == 0 の時は通常モード、sysx_cnt > 0 の時はデータバイトを sysx_buf[] にコピーするモードになります。
通常モードの場合には、switch 文で MD_bcnt の値に応じて場合分けをします。
case ラベルが 0 の場合は、ランニング・ステータスを意味しますが、前に説明したように、ステータス・バイトがあるメッセージと同じ扱いにします。
具体的には、MD_bcnt++ でインクリメントして、値を 1 にすることと、break 文を省略して、case ラベル 1 の処理へ合流するようにしています。
case ラベルが 1 というのは、最初のデータバイトであることを意味します。 
ここでランニング・ステータスである MS_run_stat 変数を調べ、2 バイトメッセージである

  • 0xCn : プログラム・チェンジ
  • 0xDn : チャンネル・キー・プレッシャー (アフタータッチ)
  • 0xFn : MTC クォーター・フレーム
  • 0xFn : ソング・セレクト

に対する処理を行います。*1 
プログラム・チェンジ/アフタータッチの場合には、それぞれ MIDI モニタ表示用の mon_pc_disp() / mon_cc_bend_disp() 関数を呼び出します。
処理の終わりで MS_bcnt = 0 として、次のメッセージの開始を待つ状態にしておきます。
それ以外は 3 バイトメッセージであるとして、MD_bcnt をインクリメントしておきます。
case ラベルが 2 というのは、2 番目のデータバイトであることを意味します。
ここでランニング・ステータスである MS_run_stat 変数を調べ、3 バイトメッセージである 

  • 0x8n : ノートオフ・メッセージ
  • 0x9n : ノートオン・メッセージ
  • 0xBn : コントロール・チェンジ
  • 0xEn : ピッチ・ベンド

に対する処理を行います。 
コントロール・チェンジ/ピッチ・ベンド の場合は、 MIDI モニタ表示用の mon_cc_bend_disp() 関数を呼び出します。
ノートオン/ノートオフは、それぞれ「midifunc.c」ファイル中の midi_note_on() / midi_note_off() 関数を呼び出します。
ピッチ・ベンドは「midifunc.c」ファイル中の pitch_bend() 関数を呼び出します。
コントロール・チェンジについては、md_cc_func() 関数を呼び出して、コントローラの種類について、さらにデコードを続けます。
それ以外の 3 バイトメッセージ

  • 0xAn : ポリフォニック・キー・プレッシャ
  • 0xF2 : ソング・ポジション・ポインタ

は、単に無視します。
処理の終わりで MS_bcnt = 0 として、次のメッセージの開始を待つ状態にしておきます。

*1:0xCn などの 「n」 は MIDI チャンネルを表す数値 (0 〜 F)