<< 目次に戻る

YM2203・YMZ294・SP0256を使ったハードウエアMIDI音源の製作
ボイスアサイナの実装

いかに楽器らしく自然な発音をさせるか?

MidiTalkでは使用する6個の音源ICが全て独立して動作しているので、それぞれのICにうまく演奏データを割り振るのがボイスアサイナの役割です。
全てのボイスをモノフォニック仕様にすれば面倒なプログラムを書く必要が無いのですが、一応MIDI音源なんだから一般的なSMFぐらいまともに鳴って欲しいですよね。

General MIDI Lite のガイドラインには、
3.1.7 ボイス(サウンド・ジェネレータ)アサイン
新たなノート・オンを受信した時に空きボイスがあれば、チャンネルに関わらず、そのボイスにアサインする。
以下のような場合、ボイス・アサイナの動作は各社が最善と考える方法をとってよい。

1. 音源のすべてのボイスが発音中の時に新たなノート・オンを受信した場合
2. 1つのノート番号により複数のジェネレータが同時に使用された場合

空きボイスがない場合にチャンネルによって優先度が異なるアサイナの場合は、その優先度は次のようにすべきである。 10ch. > 1ch. > 2ch. > .. > 9ch. > 11ch. > .. > 16ch.
さすがにチャンネルの話をされると自由にパート割り当てできなくなるからなぁ…

この文章の「空きボイスがあれば、チャンネルに関わらず、そのボイスにアサインする」というところがミソで、 個々のボイスの発音特性が違うMidiTalkでは好き勝手に空きボイスを引っ張ってくるわけにはいきません。 例えば、SSGのハードウエアエンベロープは1系統しかないため、複数のボイスでエンベロープ使用すると他のボイスまで影響を与えてしまいます。 つまり、エンベロープを使っているSSGで完全ポリフォニックにするには4ボイスしか使えないのです。

さて、かなり昔のMIDI音源でCM-64とかSC-55などRolandの音源ではパーシャルリザーブという機能があって、パートごとに割り当てるボイス数を固定してしまうことができました。 つまり、MidiTalkでも同じような機構にすれば、ボイス数を静的に割り当ててしまうことが可能になります。


"空きボイス"の定義

空きボイスとはその名のとおり「使われていない」ボイスです。
mono
上の図はモノフォニックの時の動作で、次の音を出すために前回鳴っていた音を強制的に消しているところを表しています。
poly
次はポリフォニックの図。赤の音がノートオフする前に緑の音が鳴り始めているため、ここで空きボイスを取得していることがわかります。
次に緑から青の部分が問題のところ。赤のボイスはすでにノートオフしてリリースも終了しています。 緑のボイスもノートオフしているが、リリース中です。 そして次の音を出さないといけない時に、3つあるボイスのうちどのボイスを割り当てるべきでしょうか?
ボイスそのものに優先度をつけていない場合は、赤いボイスを使用してしまうかもしれません。 もしくは、最後に使用したボイスがOFFになっている場合、最後のボイスを再利用するプログラムにしてしまうと緑が使用されてしまうかも知れません。が、どちらもNGです。

リリースが入る音の場合は、永遠に音が鳴りつづけると考えて他のボイスを選択しなければなりません。 具体的に言うと赤の前にOFFになったであろう青いボイスです。 ちなみに、YM2203ではリリース音が消えているかどうかを知るすべは用意されていません。


ここからは実際に行っているノートオン・オフの解説になります。チャンネルからパート番号へ変換する部分は省略しています。

ボイスのアサインに使用する属性値

ボイスパラメータ
所属パートボイスがどのパートに関連付けられているかを示す。
優先度ノートオンの順番を決める値で0が最優先。起動時に初期値がセットされる。
ノートオフフラグボイスのON/OFFにかかわらずノートオフを示す。優先度の計算に使用する。
ボイスサステイン中フラグパートサステイン中フラグがONの時にノートオフを受信した時に立つ。
ノート番号ノートオフ時のボイス検索に使用する。

パートパラメータ
パートの最大ボイス数優先度の計算に使用する。起動時・ボイスアサイン変更時に設定される。
パートサステイン中フラグパートがサステインONを受信した時に立つフラグ。

ノートオンの処理

ノートオンは音階を計算し、各ボイスに割り当てられた優先度にしたがってボイスをオンし、優先度を無条件に更新するだけの単純な作業になります。

発音させるボイスはノートオンを受信後、MIDIチャンネルからパート番号へ変換され、 パートの中で優先度が0になっているボイスが対象になります。 ボイスが確定すれば、ノート番号・ピッチベンド・ピッチベンドセンシティビティから音階を、 ベロシティ・ボリューム・エクスプレッション・TLから音量を計算し、ボイスをオンします。

次にボイスの使用状況を記録するため、ノートオフフラグをオフ、ボイスサステイン中フラグをオフ、ノート番号を保存します。
ONしたボイスの優先度は、パートの最大ボイス数を優先度にセットし、パートに割り当てられた全てのボイスの優先度をデクリメントして優先度の更新は完了です。

一連の流れを実行すると、ノートオンしたボイスはパートの中で一番低い優先度を持つようになります。 仮に全てのボイスがオンになった場合でも、優先度が一周するので一番古いボイスが次の候補に選ばれるようになります。

下の図では、パート4の優先度が一番高い(=0)ボイス10にC4のノートをオンする様子です。
noteon

ノートオフの処理

優先度更新の前準備

消音させるボイスはノートオフを受信後、MIDIチャンネルからパート番号へ変換され、パートの中でノートオフで指定されるノート番号が記録されているボイスが存在するかどうかを確認します。 同時に優先度の更新のため、パート中でノートオフしているボイスの数をカウントして控えておきます。
該当するノート番号が存在する場合は、優先度の値が0に近いボイスの番号を保存しておきます。これがオフする対象のボイスになります。 これは多重ノート(同じチャンネルで同じノート番号のノートオンが重複して送られること)が発生した場合の回避策です。

優先度更新の段階

オフ対象のボイスが決定すれば、ボイスオフの前に優先度を更新します。
パート中にあるボイスで、ノートがオンしている かつ ボイスの優先度がボイスオフ候補の優先度より高い場合、 優先度を1段階下げます。そして、オフするボイスの優先度には前準備段階でカウントしたノートオフしているボイスの数をセットします。
一連の流れで、ノートオンしているボイスはできるだけ優先度を低く、ノートオフしたボイスはノートオフしているボイスの中で一番低い優先度を持つようになります。 その結果、リリース音ができるだけ長く続くような発音順序を再現できるようになります。

ボイスオフの段階

前準備段階で保存したオフ対象ボイスのノートオフフラグをセットします。
次に、パートサステイン中フラグを確認し、サステインしていない場合は対象ボイスをオフします。 フラグがONの時は、対象ボイスのボイスサステイン中フラグをセットします。

下の図では、パート4で発音しているG4のノートをオフする様子です。
ボイス12がOFFになるため、ボイス10と11の優先度よりも優先度が高くなりますが、最優先の0は代入されません。
noteoff

サステインオンの処理

ノートオフと関係が深い処理にサステインがあります。 サステインをオンにした場合は、パートのサステイン中フラグをオンにするだけです。

サステインオフの処理

サステインオフを実行する場合、ボイスのサステイン中フラグが立っているボイスを全てオフにします。 サステインに移行したボイスをオフにできるのはサステインオフだけです。 また、優先度の更新はノートオフの時に行われているため行いません。

<< 目次に戻る