ムライボックス (8) --- ソフトウェア (3)

C 言語で記述したプログラムの断片を示しながら、もう少し具体的な処理の説明をします。
まず、処理で使う変数です。

  uint16_t r_mask;  // "running" bit mask

  uint8_t  c;       // MIDI byte from MIDI-IN
  uint8_t  midi_ch; // MIDI ch / sys msg type
  uint16_t bm;      // mask bitmap for "OR" gate

変数「r_mask」は、「ランニング」ビットマスク・パターンで、永続的に有効な値を保持する必要があります。
グローバル変数」あるいは (スコープとしての意味ではなく) 記憶クラスとしての「static」属性を宣言した変数とします。
その他の変数は、関数が実行されている間だけ有効な「ローカル変数」で構いません。
「c」は MIDI-IN から入力されたバイト・データを (一時的に) 保持する変数、「midi_ch」は、チャネル・メッセージの場合のチャネル番号、およびシステム・メッセージの場合のメッセージ種別を表す値を (一時的に) 保持する変数、「bm」は外部ハードウェアの「OR」ゲートに出力するマスク・パターンのビットマップを (一時的に) 保持する変数です。
まず、変数 c に MIDI-IN から入力したバイトが格納されているとして、その処理の最初の部分は次のようになります。

  midi_ch = (0x0f & c); // extract MIDI ch / sys msg type
  bm = r_mask;          // use "running" port mask

入力されたバイト c がチャネル・メッセージのステータス・バイトの場合には、チャネル番号部分を書き換えてしまうので、あらかじめ元のチャネル番号部分を抽出して変数 midi_ch に控えておきます。
最も最近に出現したステータス・バイトで書き換えられたランニング・ビットマスクが変数 r_mask に記憶されているので、変数 bm に値を読み出しておきます。
このあと、MIDI バイト c の値により処理が変わります。
c の b7 が「0」の場合はデータ・バイトであり、その場合にはすでに必要な処理が済んでいるので、c および bm について操作はせず、そのまま出力処理に移ります。
c の b7 が「1」の場合はステータス・バイトであり、その場合には、チャネル・メッセージとシステム・メッセージとで扱いを変えます。 (2017 年 12 月 11 日追記: 「ステータス・バイト」とすべきところを「データ・バイト」と表記していた誤りを修正しました)
まず、チャネル・メッセージは、ステータス・バイトの値が 0x80 〜 0xef の範囲ですから、

  if (0xf0 > c) { // ch mode message [0x80..0xef]
    bm     = mask_tab[midi_ch]; // get port mask pattern  
    r_mask = bm; // set "running" port mask pattern 
    c = ((c & 0xf0) | remap_tab[midi_ch]); // remap MIDI channel
  } 

ビット・マスクはチャネル・メッセージ用のテーブルである mask_tab を参照して変数 bm に代入します。 それと同時に、ランニング・ビットマスク r_mask にも記憶しておきます。
リマップ・テーブル remap_tab
を参照して得たリマップ後のチャネル番号を、強制的に MIDI バイト c の下位 4 ビットに格納します。
システム・メッセージの処理は下のようになります。 上のプログラムの if 文の else 節となっています。

  else { // system message [0xf0..0xff]
    bm = sysmsg_tab[midi_ch]; // escaping for system realtime
    if (0xf8 > c) { // system common msg [0xf0..0xf7]
      r_mask = bm; // set "running" port mask pattern
    } // if (0xf8 > c) { ...    
  } // if (0xf0 > c) {} else { ...

システム・メッセージにはチャネル番号の概念はないので、その書き換えは行なわず、ビットマスク・パターンだけを扱います。
ビットマスク・パターンはシステム・メッセージ用のテーブル sysmsg_tab[] を参照して、システム・コモン・メッセージ (0xf0 〜 0xf7)、システム・リアルタイム・メッセージ (0xf8 〜 0xff) の計 16 種のメッセージを共通に扱います。
そして、システム・コモン・メッセージ (0xf0 〜 0xf7) では、チャネル・メッセージと同様にランニング・ビットマスク r_mask にも記憶しておきます。
システム・リアルタイム・メッセージ (0xf8 〜 0xff) では、r_mask は変化させず、「今回限り」の値である bm にだけビットマスクを代入しています。
以上で MIDI バイトの種別に応じた処理が終了したので、その後は共通の出力処理に入ります。

  for (i = 0; i < N_PORTS; i++) {
    if (0x01 & bm) { // port active
      (*write_func_p[i])(c); // port output
    } // if
    bm >>= 1;
  } // for (i = 0; ...

これは以前示した「PSoC5LP 富豪版」の例ですが、「富豪版」なので出力ポートの数だけ送信 UART があり、他のポートのタイミングを考慮する必要がないので、単にビットマスクをシフトして 1 ビットごとに参照しながら UART へ出力するかどうか決めているだけです。
「エコノミー版」では出力タイミングを監視しながら出力しなければならないので、割り込み/ポーリング/バッファ等の構成によりプログラムは変わってきます。