ボイス・アサイナ (3)

前回の例では、同音連打でも、ノートオン/ノートオフ・メッセージが直接に1対1対応していて、ふたつの独立した音となっていましたが、可能性としては、MIDI データ上で、下の図のように、最初のノートオン (Note_ON1) の後にノートオフが来ないで、別のノートオン (Note_ON2) が来る場合が考えられます。

その後、ノートオフは2つ (Note_OFF3, Note_OFF4) 続けて到着します。
この二組のノートオン/ノートオフをどのように対応させて2つの音と見なすかで、上の図の上段と、下段のような2種類の解釈が考えられます。
上段の場合には、

  • Note_ON1 --- Note_OFF3 (赤色の線)
  • Note_ON2 --- Note_OFF4 (緑色の線)

と対応させ、「一部がオーバーラップした2つの音」という解釈です。
下段の場合には

  • Note_ON1 --- Note_OFF4 (赤色の線)
  • Note_ON2 --- Note_OFF3 (緑色の線)

と対応させ、「長い音の中に完全に『入れ子』となった短い音が含まれた2つの音」という解釈です。
この2つの音の MIDI チャンネル番号、あるいはノート番号の、いずれか一方でも違っている場合 (同一チャンネルでの同音連打でない場合) には、ノートオン/ノートオフの対応関係は MIDI データから一義的に決定され、あいまいな解釈が入る余地はありません。
同一チャンネルでの同音連打では、Note_ON1 と Note_ON2 の2つのノートオン・メッセージのベロシティ以外の部分のデータは、どちらの音でも全く同じパターンとなります。
同様に Note_OFF3 と Note_OFF4 との間にも差はありませんから、MIDI データだけで判断すると、前述のような解釈のあいまいさが残ります。
ここでは、このような場合には、上の図の上段のように、「一部がオーバーラップした複数の音」という解釈を取ることにします。
つまり、最初のノートオンの後にノートオフが現れず、複数のノートオン・メッセージが到着し、その後はじめてノートオフ・メッセージが到着した場合、そのノートオフは、現在「保留」されている一番古いノートオン・メッセージに対応するものとします。
このような「先入れ先出し」の管理のためには、FIFO (First In First Out) キュー (待ち行列) を利用すれば良く、

  • ノートオンが到着したら、対応するボイスにノートオン処理 (アタック開始) を行い FIFO キューの最後尾に追加
  • ノートオフが到着したら FIFO の先頭から取り出したボイスに対してノートオフ処理 (リリース開始) を行う

という処理で、ノートオン/ノートオフの対応関係を付けることができます。
前回の 2048 要素の「2 次元・ボイス・アレイ」に「静的」にボイスを割り当てておく方式では、「同音連打」に対しては「シングル・アサイン」しかできませんでした。
いま、リソースの使用に関しては制約がない場合を考えていますから、ボイス (発音エレメント) のハード/ソフトは「動的」に無限に生成できるものとし、必要になったら割り付け、不必要になったら特に何もせず、「使い捨て」ることにします。
この場合、2048 要素の 2 次元配列にはボイスそのものを置くのではなく、FIFO キューを置くようにします。
そうすると、「マルチ・アサイン」方式にするためには、ノートオン・メッセージに対して、

  • ボイスを1個生成する
  • ボイスにノート番号に対応する音程データをセットし、アタック処理を開始する
  • ノートオン・メッセージの MIDI チャンネル番号とノート番号から 2 次元配列内の対応する FIFO キュー要素の位置を求める
  • ボイスをその FIFO キューの最後尾に追加する

という処理を行えばよいことになります。
また、ノートオフ・メッセージに対しては、

  • ノートオフ・メッセージの MIDI チャンネル番号とノート番号から 2 次元配列内の対応する FIFO キュー要素の位置を求める
  • その FIFO キューの先頭からボイスを取り出す
  • ボイスにノートオフ処理 (リリース開始) を施す

処理を行います。
ノートオフでリリース処理に入ったボイスは、いずれ発音が終了して出力がゼロとなりますが、リソースは無限に使えるものとしていますから、特に再利用などはせず、使い捨てにします。
ノートオン/ノートオフに関しては上述の処理でいいのですが、ダンパー・べダル (MIDI コントロール・チェンジ 64 番、 Hold1) については別の配慮が必要になります。 それについては次回述べます。