Skip to content

GM/GS フォールバックバンク ​

このページは内蔵シンセサイザーの General MIDI/GS 側を扱います。データ不要の GM フォールバックバンクと、その GS バリエーション音色・ドラムキットバリエーションを扱います。バウンスが GM プログラムチェンジに追従する仕組み、SoundFont プレイヤーが実装する GS のアーキテクチャ層と挿入エフェクト、SoundFont からバンクへ落ちる条件も扱います。プログラムごとの音色一覧は GM 音色マップ にあります。

GS は Roland が定めた General MIDI の拡張規格です。ここにある内容はすべて独立した再実装であり、libsonare はいかなるハードウェアメーカーとも提携・承認関係になく、その音色は特定のモジュールの音を再現するものではありません。

ここに置いてあるのは GS の具体的な側面(アドレス、各種の表、スロット単位の詳細)です。ブラウザで動くオーディオエンジンがなぜ GS に対応しているのかは音源方式にまとめてあります。仕様と食い違う箇所が拡張・意図的な相違・縮退のどれにあたるのかは後述します。

GM フォールバックバンク ​

GM フォールバックは、最後の手段として単純なサイン波を鳴らすだけのバンクではありません。SoundFont が未読み込み、または一部のプログラムを持たないとき、NativeSynth は要求された GM プログラムに近い内蔵の合成音源を選びます。ピアノは較正済みのエンジン、そのほかのアコースティック楽器は物理モデル、エレピとシンセブラスは FM、シンセのリード・パッド・エフェクトは減算合成のオシレーターで鳴ります。ドラムは GM/GS ドラムキットのバリエーションへ送り、利用可能な場合は GS EFX を内蔵インサートチェーンへルーティングします。128 プログラムそれぞれのエンジンは GM 音色マップにあります。目的は、データ不要のプレビューと欠けたプログラムのカバーであり、完成済みのサンプル楽器並みのリアリティではありません。どのエンジンが較正済みかは内蔵シンセサイザーに書いてあります。

あらかじめ知っておきたい点が 1 つあります。bourdon や trumpet-rank のような名前付きのパイプオルガン音色は名前付きプリセットカタログにのみ存在し、GM プログラムルーティングには現れません(プログラム19は教会オルガンのフルーパイプで、プログラム20-23はフリーリードのリードオルガン、アコーディオン、ハーモニカ、バンドネオン(タンゴアコーディオン)です)。

初学者向けに言い換えると、正確な音色や本番向けのサンプル楽器が必要なら SoundFont を使い、軽量で常に鳴るプレビューや欠けたプログラムの保険には NativeSynth フォールバックを使う、という使い分けです。

GS バリエーション音色 ​

GM のプログラム番号が選ぶのはキャピタル音色です。GS と GM2(General MIDI の後継改訂版。MIDI の基礎を参照)はどちらも、プログラムチェンジの前に Bank Select を送ることで、そのキャピタルのバリエーション(ワイドピアノ、デチューンオルガン、12 弦ギターなど)を選ぶ手段を用意しています。フォールバックバンクは、17 のキャピタルプログラムのもとに 30 のバリエーションを音色として持ちます。このページのプログラム番号は 0 始まりです(0 から数えるか、1 から数えるか)。

各バリエーションは1 つの音色に対して 2 つのアドレスを持ちます。GS のバンクセレクト MSB 番号と、GM2 の番号(GM2 のメロディ用 MSB 121(0x79)と一緒に送るバンクセレクト LSB)です。そのため、GS 向けに作られたファイルと GM2 向けに作られたファイルは同じ音色で鳴ります。片方が相手の規格の番号を使ったせいでキャピタルに落ちる、ということが起きません。

キャピタルプログラムバリエーションGS MSBGM2 LSB(MSB 121)
0 Acoustic Grand Pianoワイド81
0 Acoustic Grand Pianoダーク162
1 Bright Acoustic Pianoワイド81
2 Electric Grand Pianoワイド81
3 Honky-tonk Pianoワイド81
4 Electric Piano 1デチューン81
4 Electric Piano 1ベロシティ切り替え162
4 Electric Piano 160年代243
5 Electric Piano 2デチューン81
5 Electric Piano 2ベロシティ切り替え162
6 Harpsichordカップルド(8′+4′ オクターブ)81
6 Harpsichordワイド(2 クワイアのステレオ)162
6 Harpsichordキーオフのジャックノイズ243
11 Vibraphoneワイド81
12 Marimbaワイド81
14 Tubular Bellsチャーチベル81
14 Tubular Bellsカリヨン92
16 Drawbar Organデチューン81
16 Drawbar Organ60年代162
16 Drawbar OrganOrgan 4323
17 Percussive Organデチューン81
17 Percussive OrganOrgan 5322
19 Church Organフルートレジストレーション81
19 Church Organフルオルガン162
21 Accordionイタリアンチューニング8—
24 Acoustic Guitar (nylon)ウクレレ81
24 Acoustic Guitar (nylon)キーオフノイズ162
25 Acoustic Guitar (steel)12 弦81
25 Acoustic Guitar (steel)マンドリン162
40 Violinスローアタック81

イタリアンアコーディオンを GS 専用としているのは意図的です。GM2 はプログラム 21 のバリエーション 1 をフレンチアコーディオンに割り当てており、それはキャピタルがすでに鳴らしているドライなチューニングです。GM2 のアドレスをここで採用すると、2 つの規格が互いに矛盾することになります。

どのバリエーションも指さないバンク番号でも音は鳴る

この表にないバリエーションを指す Bank Select の値は、キャピタル音色へ解決されます。これは、持っていないバリエーションを要求されたときに実機のモジュールがする動作と同じです。バンクがまだ持っていない音色を要求したせいでファイルが音を失うことはありませんし、あとからバリエーションを追加しても、変わるのはすでにそれを要求していたファイルだけです。

各バリエーションは、別録りの音源ではなくキャピタル自身の物理モデルから音色を作ります。そのため、キャピタルの音色を作り直すとバリエーションもそれに追随し、取り残されることがありません。3 つのピアノのキャピタルがグランドのワイド音色を共有せず、それぞれ自前のワイドバリエーションを持つのもこのためです。共有すると、どれかがキャピタルより鈍く、小さく、あるいは音程が整いすぎた「バリエーション」になってしまいます。

下の試聴はキャピタルを 1 つ(プログラム 16 のドローバーオルガン)に絞り、バンクが鳴らし分けている 3 つのバリエーションを並べています。3 つだけにしているのは、バリエーションの実体が無いバンクセレクト MSB はキャピタルへ解決され、ビット単位で同一のバッファを返すからです。このプログラムでは MSB 24 がその一例で、音が変わらない選択肢は聴き比べになりません。

GS · VARIATIONIDLE
GS バリエーション音色 — 1 台のオルガン、4 つのレジストレーション

GS ではキャピタル音色のバリエーションをバンクセレクト MSB で選びます。同じプログラムチェンジでも MSB を変えると兄弟音色が鳴ります。ここではキャピタルをプログラム 16 のドローバーオルガンにし、フォールバックが鳴らし分けているバリエーションのうち 3 つを並べました。Detuned Organ 1(MSB 8)はコーラススキャナーのゆっくりしたうねりを加え、60's Organ 1(MSB 16)は最初の 3 本のドローバーだけを引き出して強いキークリックを乗せ、Organ 4(MSB 32)は全バーを引き出した総奏になります。フォールバックが鳴らし分けていない MSB は GS の仕様どおりキャピタルに戻るため、載せているのはいずれも実際に音が変わるものです。各レンダーは左右共通のピークで揃え、音色ごとのラウドネスの違いは残します。

バリエーション

drum-kit プリセットと GM ドラムマップ ​

drum-kit は percussion エンジンを選び、入ってくる MIDI ノートを General MIDI ドラムマップへ割り当てます。ノート番号をピッチとして扱うのではなく、ノート 36 はキック、ノート 38 はアコースティックスネア、というように対応づけます。ドラムパターンのノートを drum-kit をバインドしたデスティネーションへ送ると、各ノートが対応するパーツを鳴らします。

各規格のドラムキットの選び方 ​

このプレイヤーでは 4 つの慣習が出会い、それぞれ別の方法でキットに届きます。

慣習ドラムパートになる条件キットを選ぶもの
General MIDIMIDI チャンネル 10(インデックス 9)に固定なし(標準キットが 1 つだけ)
GS既定はチャンネル 10。SysEx(「リズムパートとして使う」)で任意のパートをリズムパートに切り替えられるそのリズムパートへのプログラムチェンジ。バンクセレクトは使わない
GM2バンクセレクト MSB 120(0x78)プログラムチェンジ
SoundFont 2 ファイルバンク 128 に置かれたプリセットバンク 128 の中のプリセットのプログラム番号

SF2 の行は、ファイルの中でキットが置かれる場所を示すもので、ワイヤー上のメッセージではありません。プレイヤーはドラムパートと GM2 の MSB 120 を、読み込んだ SoundFont のバンク 128 へ対応づけます。マニフェストがドラムパートをバンク 128 として報告するのはこのためです。

GS / GM ドラムキットバリエーション ​

drum-kit は GS 系のドラムキット選択(GS は General MIDI の拡張セット。キットはバンク 128 のリズムパートのプログラム番号で指定します)も認識し、ノートオンの時点で Standard キットをセットごとに作り変えます。Room ならシェルの鳴りを増やし、Power なら音を下げて長くする、といった具合です。

各行には 2 つの番号が並びますが、これらは入れ替えて使えません。プログラムはファイルが送る番号で、リズムパートのプログラムチェンジ番号、つまり規格が定めるアドレスです。インデックスはこのバンク内部のスロット番号です。インデックスは追加のみで、あとから追加されたセットは空いている次の番号を取ります。そのため、セットを追加しても既存のセットの番号が付け替わることはなく、すでに正しく鳴っていたものが別の音になることもありません。

トーンマップの列は、そのセットを最初に定義した世代を信号線上の番号(1 が最も古く、4 が最新)で示したもので、それを選ぶ手段がバンクセレクトです。このメッセージの 2 つのバイトは別々の役割を持ち、役割が重なることはありません。バンクセレクト MSB がバリエーション音色を選び、バンクセレクト LSB がトーンマップを選びます。LSB にバリエーション番号を書いても、選ばれるのは音色ではなく世代です(GM2 は自前の 2 つの MSB のもとで LSB をバリエーション番号として使い回します。その例外は後述の GS アーキテクチャ層にあります)。

要点だけ言えば、LSB 0 はモジュール自身のマップを鳴らし、1〜4 は 4 つの世代のどれかに固定します(古い順)。

「モジュール自身のマップ」がどの機種を指すか

エンジンが対象とするのは最新世代のモジュールで、そのマップがマップ 4 です。古い世代のファイルは LSB で自分の世代を選べば(マップ 3 のファイルなら 3 を送ります)、何も失わずに鳴ります。

トーンマップの違いが音に出るのは、選んだマップにそのキットが無いときだけです。下の表の 26 セットのうち 16 セットは後発のマップで追加されたものなので、古いマップを指定するとそれらは Standard へ落ちます。その世代の実機がする動作そのままです。メロディック側は逆で、バンクが鳴らし分けているバリエーションはすべて、どのマップからも選べるマップ 1 の音色です。だからこそ LSB だけを変えても上のバリエーション表では何も動かず、下のキット表では大きく動きます。

どのセットも、共有された 1 つのパーカッションモデルを作り直したものであり、モデルの複製ではありません。キック、スネア、タム、ハット、シンバルのパラメータがノートオン時に作り変えられます。つまり、土台のモデルを良くすれば 26 セットすべてが同時に良くなり、逆にセットどうしの差はモデルがパラメータを持つ範囲にとどまります。

プログラムインデックスGS 名トーンマップStandard との音色差
00Standardマップ 1—
81Roomマップ 1シェルの鳴りが増え、残響の尾が長くなる
162Powerマップ 1シェルが大きく/低く/長くなる
243Electronicマップ 1サイン波化し、乾いた膜音になる
254Analog Machine(GM2: Analog)マップ 1減衰サイン波のキック、単一音のスネアとタム
325Jazzマップ 1タイトで高め、柔らかい
406Brushマップ 1スネアが持続するスウィッシュ音になる
487Orchestraマップ 1膜/シンバルの尾が長くなる
568SFXマップ 1ワンショットのセット(Standard の音色で鳴る)
1279Legacy Mapマップ 1短く薄く明るい、GS 以前のドラムマップ
110Standard 2マップ 2より乾いてタイトな響き。スナッピーが強め
2611Danceマップ 2サイン波キック、クラップ寄りのスネア、詰めたハット
4912Ethnicマップ 2ハンドドラム。リーム寄りを叩き、シェルは薄い
5013Kick & Snareマップ 2動くのはキックとスネアだけで、残りは Standard
5714Rhythm FXマップ 2ワンショットのセット(Standard の音色で鳴る)
215Standard 3マップ 3中心を外して叩き、より開いた響き
916Hip Hopマップ 3低く短く、押しつぶした質感
1017Jungleマップ 3すべてを早めに切り、明るい方向へ寄せる
1118Technoマップ 3完全に合成的な膜と、硬く明るい高域
2719Rhythm Boxマップ 3フィルタードノイズのチック。スナッピーのないスネア
2820Compact Machineマップ 3薄く金属的で、アナログ系セットの中で最も胴鳴りが少ない
2921Digital Machineマップ 3アナログではなくサンプル。歯切れよく乾いて短い
3022Hybrid Machineマップ 3長く減衰するサイン波キックの上にクリック
5223Asiaマップ 3ゴングや太鼓。大きく低く、長く鳴る
5324Cymbal & Clapsマップ 3ワンショットのセット(Standard の音色で鳴る)
5825Rhythm FX 2マップ 3ワンショットのセット(Standard の音色で鳴る)

ワンショットのセットはアドレスのみで未モデル化

4 つのリズムセットがあります。SFX(プログラム 56)、Rhythm FX(57)、Cymbal & Claps(53)、Rhythm FX 2(58)です。これらは実機の GS では、音色を作り変えたキットではなく、個別のワンショット録音を集めたバンクです。膜モデルが作り変える対象がそもそも存在しないため、プレイヤーはアドレスと名前を認識しつつ、フォールバックマップは 4 つとも Standard キットの音色へ通します。これはデータ不要のフォールバックだけの制約です。これらのアドレスに実際のサンプルを持つ SoundFont を読み込めば、SF2 プレイヤー経由で通常どおり再生されます。GM のサウンドエフェクトプログラム(120-127)は別で、それぞれがノイズ系の固有の音色を持ちます(GM 音色マップを参照)。

下の試聴は、同じグルーヴを 1 小節、いくつかのセットで鳴らします。キットの選び方は GS ファイルと同じで、リズムパートのプログラムチェンジです。表の全セットではなく抜粋になっているのは、全セットをレンダリングして Standard とビット単位で同一になったものを外して作ったからです。上に挙げた 4 つのワンショットプログラムは、まさに設計どおりそうなります。この線引きのためにホスト側でレンダリングする必要はなく、下の問い合わせ関数がその答えを返します。

GS · DRUM KITIDLE
GS ドラムキット — 同じグルーヴを 8 つのセットで

リズムパート(MIDI チャンネル 10)で同じ 1 小節のロックビートを鳴らし、そのパートのプログラムチェンジでキットを選びます。GS ファイルがドラムセットを切り替えるのと同じ手順です。SoundFont は読み込まないので、各キットは内蔵フォールバックが標準セットの各パーツを鳴らし分けたものです。Power は胴を低く長く、アナログマシンとハイブリッドマシンはクリックの乗った減衰する正弦波に、Jazz は締まって高めに、Orchestra はコンサートバスドラムとティンパニのように響き、Asia はゴングと太鼓になります。フォールバックが鳴らし分けていないセット(ワンショットの SFX や Rhythm FX バンク)は Standard とまったく同じ音になるため、ここには含めていません。各レンダーは左右共通のピークで揃え、キットごとのラウドネスの違いは残します。

キット

どのセットが鳴らし分けられているかを問い合わせる ​

プログラムチェンジやバンクセレクトで実際に音が変わるスロットはどれか、という問いにはエンジン自身が答えます。ピッカーの注記は上の表から書き写すのではなく、3 つの問い合わせ関数から計算してください。WASM/Node では synthGsDrumKitName、synthGsDrumKitIsVoicedApart、synthGsVariationIsVoicedApart で、C ABI と Python にも同じ 3 つがそれぞれの命名規則で用意されています。

  • synthGsDrumKitName(program) は、リズムパートのプログラムチェンジが選ぶ GS リズムセットの名前('Standard'、'Room'、'Jazz' など)を返します。モジュール自身のトーンマップがそのプログラムにセットを定義していなければ null です。エンジンが返す名前には機種の型番が含まれるものがあります。このページの表ではそうしたセットを機種の種類で呼んでおり、自分のページではこの下の例のように自前のラベルを付けてください。プログラム番号はどちらでも同じです。
  • synthGsDrumKitIsVoicedApart(program) は、セット内のドラムノートが 1 つでも Standard と異なれば true、セットが Standard とまったく同じ音で鳴るなら false、そのプログラムにセットがなければ null を返します。プログラム 0 は Standard そのものなので、上の 4 つのワンショットセットと同じく false になります。
  • synthGsVariationIsVoicedApart(bank, program) はメロディック側です。バンクセレクトのバリエーションが固有のパッチを持てば true、キャピタル音色へ解決されるなら false、どちらかの引数が 0..127 の外なら null です。GS のバンクセレクト MSB と GM2 の LSB は同じバリエーションを指すので、どちらを渡しても受け付けます。なお、この API の他の場所ではドラムバンクを指す 128 も、ここでは範囲外です。鳴らし分けのないバリエーションをキャピタルへ解決するのは GS の仕様どおりなので、false は欠落ではなく正しい挙動です。ただし、本当に固有の音を持つバンクと区別できるのはこの問い合わせだけで、これがなければ両方をレンダリングして比較するしかありません。

答えは一覧から引くのではなく導出されます。キット側の述語はセットを各ドラムノートの解決済みパッチに適用してバイト単位で比較し、バリエーション側の述語は解決結果がキャピタル音色そのもののパッチかどうかを見ます。そのため、スロットに音色が付けば答えはそれに合わせて変わり、追随させるべき一覧はありません。存在はするが現在のパッチに対しては何も変えないケースも、そのまま報告されます。基準になるのはモジュール自身のトーンマップで、これは最新世代であり、このビルドが鳴らし分けるセットをすべて含みます。古いトーンマップを選ぶファイルから選べるセットはそれより少なくなります。

どちらの述語も3 つの状態を返すため、真偽値として評価するとその区別が失われます。null は「そこにスロットが存在しない」という意味で、102 のプログラムがこの状態です。if (!voicedApart) と書くと、false を返す少数のセットに加えて、この 102 個の空のプログラムまでプレースホルダーとして数えてしまいます。必ず false と明示的に比較してください。

typescript
import { synthGsDrumKitIsVoicedApart, synthGsDrumKitName } from '@libraz/libsonare';

const kits = Array.from({ length: 128 }, (_, program) => program)
  .filter((program) => synthGsDrumKitName(program) !== null)
  .map((program) => ({
    program,
    label: `Rhythm set ${program}`,   // 自前のラベル。返された名前は表示しない
    placeholder: synthGsDrumKitIsVoicedApart(program) === false,
  }));
python
import libsonare as sonare

kits = [
    {
        "program": program,
        "label": f"Rhythm set {program}",
        "placeholder": sonare.synth_gs_drum_kit_is_voiced_apart(program) is False,
    }
    for program in range(128)
    if sonare.synth_gs_drum_kit_name(program) is not None
]

パッチを固定せず GM プログラムに追従させる ​

バインディングは通常、1 つのデスティネーションに 1 つのパッチを固定します。MIDI にどんなプログラムチェンジが入っていても、そのデスティネーションを通る音はすべて同じ音色で鳴ります。一般的な MIDI ファイルではこれは望ましくありません。チャンネルごとに自分の楽器を選んでほしいからです。

GM プログラム追従を有効にすると、シンセはメロディックなボイスを、追跡しているバンクとプログラムチェンジから解決し、MIDI チャンネル 10 は GM ドラムキットマップへルーティングします。マップが対応しない部分にはバインドしたパッチがフォールバックとして残るので、音が消えることはありません。モードを切っていれば、上記の固定パッチの挙動は変わりません。

typescript
// JS バインディングのオプションは SynthPatch オブジェクトに指定する(文字列には指定できない)。
const audio = project.bounceWithSynthInstrument(
  { preset: 'acoustic-piano', useGmPrograms: true },
  { totalFrames: 48000, numChannels: 2 },
);
python
audio = project.bounce_with_synth_instrument(
    "acoustic-piano",          # マップ外プログラムのフォールバック
    auto_select_gm=True,
    sample_rate=48000,
)

このフラグは C ABI の SonareSynthInstrumentBinding では use_gm_programs、Python のバウンス呼び出しでは auto_select_gm、WASM/Node の JavaScript では SynthPatch 記述子の useGmPrograms です。いずれも既定値は false で、固定パッチをフォールバックにする挙動を保ちます。useGmPrograms はバインディングのオプションで、NativeSynth パッチのフィールドではありません。Python にはパッチ単位のフィールド SynthPatch.use_gm_programs もあります。これはそのデスティネーションについて auto_select_gm より優先され、リアルタイムの set_synth_instrument で使える唯一のスイッチです。2 つの CLI では値なしの --synth フラグがこれにあたります(sonare project bounce --in project.json --synth -o out.wav)。プリセット名を渡した場合はそのパッチに固定されます。

totalFrames を 0 のままにすると、アレンジとパッチのリリーステイルから長さを自動導出します。GM プログラムに追従している場合、テイルはアレンジが実際に鳴らしたプログラムだけを対象にします(長さを省略する)。未知のプリセット名は例外を投げます。bounceWith* が共有するチャンネル・サンプルレート・レイテンシなどは プロジェクトバウンス を参照してください。

GS アーキテクチャ層 ​

SoundFont プレイヤーは GM の上に、GS 向けに作られたアレンジが期待する GS 拡張を実装します(独立した再実装であり、いかなるハードウェアメーカーとも提携・承認関係にありません)。以下はすべてアドレスで指定します。GS の書き込みは System Exclusive のフレームで、3 バイトのアドレスがマップ・その中のブロック・さらにその中のパラメータを指します。

GS の書き込みがどこへ届き、どこまで進むか
F041dev4212himidloデータ…sumF7Roland · GS · DT1アドレスデータ・チェックサムhi バイト(どのマップか)00システムモードセット20–27ユーザー保存21 ドラムは鳴る20・22–27 は無視40パッチシステム・エフェクト・EQ・EFX・パートmid バイトがブロックを選ぶ41ドラム設定map m, note rr50·51別グループポートは 1 つ40 の中の mid バイト(どのブロックか)00システムチューン・音量・パン01パッチエフェクトリバーブ・コーラス・ディレイ02マスター EQ低域・高域シェルフ03EFXタイプ・20 パラメータ1xパート xx = パート。0 はパート 102xコントローラーソース 6 × 行き先 113u挿入ユニット u拡張: ユニット 0–154xパート x ルートEQ スイッチ・EFX アサインlo バイト(ブロック内のパラメータ。41 の下ではドラムのノート番号)レベル(書き込みがどこまで届くか)デコード保持発音AUDIBLE40 01 33リバーブレベル値を変えるとレンダリング結果が変わるSTATE40 01 32リバーブ pre-LPF保持して読み戻せるが、バスにその操作子が無いACCEPT40 01 00パッチ名デコードして破棄。表示する画面が無いIGNORE40 4x 21アウトプットアサインデコードして破棄。出力は 1 ペアで、行に理由が書いてある
  • バイトが届く範囲
  • 未到達
  • 不在を宣言、行に理由あり
このアドレス空間のどのアドレスも、4 つのレベルのちょうど 1 つを持ちます。レベルの無いアドレスは「何もしない」ではなく欠陥として扱われます。読み違えやすいのは STATE です。これは、受け取って正しく保持されるが下流のどこからも読まれないバイトを指します。読まない理由は、それが動かすはずのエフェクトにその操作子が無いからです。

4 つのレベルは、プレイヤーがアドレスごとに保証している内容です。AUDIBLE はバイトを変えればレンダリング結果が変わること、STATE は値が保持され読み戻せるがどのエンジンも読まないこと、ACCEPT はデコードして破棄すること、IGNORE は行が意図的に受け付けないと宣言し、その理由を書いていることを意味します。プレイヤーが持つ 16 パートは、受け取る MIDI ポートが 1 つであることから来ています。50 ** ** と 51 ** ** は別グループのパート用ブロックで、同じ理由から受け付けません。対象機にはそもそもこのアドレスが無く、40 と 41 がどちらのグループを指すかはポートが決めます。WebAssembly の制約ではありません。本当に WebAssembly から来ている制約は音源方式が切り分けています。

  • バリエーションバンクフォールバック: SoundFont がカバーしない GS バリエーションバンクは、キャピタル(バンク 0)の音色へフォールバックします。欠けたバリエーションでも無音にならず、正しいファミリーを鳴らします。
  • チャンネル 10 のバンク 128 ドラムキット: ドラムプログラムはバンク 128 にあり、慣習でチャンネル 10(インデックス 9)がドラムパートです。
  • NRPN パート編集: パートごとのフィルター(TVF)のカットオフとレゾナンス、パートごとの音量(TVA)のエンベロープ、ビブラートを NRPN でパートごとに編集でき、さらに個別のドラム音用のドラムごとの NRPN も使えます。
  • GS/GM SysEx: GS Reset、GM System On、「リズムパートに使用」の SysEx を認識します。ホストからのものと、アレンジ内に埋め込まれた SysEx イベントの両方に対応します。プレイヤーのリセットはコントローラーとあわせてシステムエフェクトとマスター EQ もクリアするため、リセット前に設定したリバーブレベルや EQ の持ち上げは鳴り止みます。GS Reset と GM System On は、バンクセレクト LSB で選んだ音色マップもクリアするため、すべてのパートがモジュール自身のマップに戻ります。
  • センドリターン方式のシステムエフェクト: 16 パート共通の 1 つのセンドリターンバスに、リバーブ・コーラス・ディレイの 3 ユニットが載っています。各パートの送信量は 2 つの経路の合算です。チャンネル CC センドでは、CC91 がリバーブ送信、CC93 がコーラス送信、CC94 がディレイ送信を担います。リバーブとコーラスには、SF2 ゾーンジェネレーター reverbEffectsSend/chorusEffectsSend の値がさらに上乗せされます(GS のディレイ送信は CC 専用で、対応する SF2 ジェネレーターはありません)。パワーオン時の送信量はリバーブ 40、コーラス 0 です。このため、リセット SysEx を送らない SMF でも空間の響きが残ります。これとは別に、パートごとのドライブインサート(ゲイン補正付きサチュレーション)もこのバスに並んで存在し、後述する GS の挿入エフェクト(EFX)とは別のものです。
  • システムディレイのモード: リバーブの CHARACTER を 6 にすると Delay、7 にすると Panning Delay になり、それぞれの時間とフィードバック設定で動作します。Panning Delay は左右の出力を交互に鳴らします。独立した GS ディレイユニットは負のフィードバックも保持するため、繰り返すエコーの極性が交互に反転します。
  • MIDI 2.0/GM2: MIDI 2.0 のバンク付きプログラムチェンジをデコードします。バンクセレクト LSB(CC#32) の解釈は MSB によって 2 通りに分かれます。
    • GM2 のアドレッシング: MSB が GM2 のメロディックバンク(0x79)またはパーカッションバンク(0x78)のとき、LSB はそのままバリエーション番号(またはパーカッションセット番号)で、GM2 の定義どおりです。
    • GS のトーンマップ選択: それ以外の MSB では、LSB は MSB のバリエーション番号がどの世代の音色セットから選ばれるかを指定します。詳しくは GS / GM ドラムキットバリエーションを参照してください。これ以外の値は 0(モジュール自身のマップ)として読まれます。

LSB は 2 つの意味を持つ

これは Project.midiBankProgram(...) に bankLsb として渡すバイトで、最も間違えやすい値です。GM2 の MSB のもとではバリエーションを選び、GS の MSB のもとではトーンマップを選びます(バリエーション番号は MSB 側にあります)。GS のバリエーション MSB と並べて bankLsb: 1 と書いてもバリエーション 1 にはならず、そのパートが最も古いトーンマップ 1 の音色セットに固定されます。

どこまでが GS で、どこからが意図的に GS でないか ​

「GS 準拠」とだけ書いて終わると、意図的な違いがすべて見落としのように見えてしまいます。エンジンは自分の差分を 3 種類に分けており、このページも同じ 3 分類を使います。3 つは互いに置き換えできません。1 つは構造上安全なもの、1 つは理由のある決定、1 つは対応できないことの明示です。

種別意味代表例
拡張仕様が何も禁じていない場所に足した能力。仕様準拠のファイルがこの能力を使うことはないからこそ安全モジュール全体で 1 基だったインサーションエフェクトが16 基になり、40 3u xx ブロックで指定できる(src/midi/synth/docs/gs.md、src/midi/synth/gs_address_table.h)
意図的な相違理由を添えて意図的に選んだ別の挙動パン値 00 はハードウェアではランダムだが、ここではセンターとして扱う。バウンス結果をビット単位で一致させることと乱数生成は両立しないため(src/midi/synth/gs_address_table.h の 40 1x 1C と 41 m4 rr の行)。実測機ではリズムパートのコーラスセンドが鳴らないが、ここでは鳴らす。どちらの理由も src/midi/synth/docs/gs.md に書かれている
縮退こちら側の構成にその対象が存在しないため、受け取ったうえで捨てる40 4x 21 OUTPUT ASSIGN は IGNORE。理由は「libsonare renders one output pair, so there is no second one to route a part to」。50 ** ** と 51 ** ** はポートが 1 系統であるため IGNORE。どちらの理由文字列も行自身が持つもので、src/midi/synth/gs_address_table.h にある

アドレス空間のすべてのアドレスは 4 段階のいずれかを持ち、行のないアドレスは、黙って何もしないのではなく不具合として扱われます。したがって縮退は、書かれた理由であって省略ではありません。

16 パートという上限も、ブラウザの制約ではありません。これは MIDI ポートを 1 系統しか受けないことから来ており、エンジン自身の理由文字列がそう書いています。旧機種が別の 16 パートを指定するために使っていた 50 ** ** と 51 ** ** は IGNORE です。理由は「libsonare receives one port, so there is no second group of parts to address」と「libsonare receives one port, so there is no second group's drum setup to address」です。00 01 xx のチャンネル別ポート割り当ても同じ理由を持ちます。3 つの行はいずれも src/midi/synth/gs_address_table.h にあります。

エンジンは単一のモジュールを想定しているため、00 00 7F SYSTEM MODE SET は範囲こそ受け取るものの、実際に効くのは 00 だけです。入力ポートが 1 系統、パートのグループも 1 つです。

GS 挿入エフェクト(EFX) ​

独自の DSP による再現であり、ハードウェアのデータを同梱するものではありません

libsonare の挿入エフェクトは、公開されている情報をもとに再構成した libsonare 独自のアルゴリズムの組み合わせで、GS の EFX の SysEx とタイプ番号体系に対応づけた独自の DSP による再現です。これにより GS 準拠で作られた MIDI が作曲者の意図したエフェクトを選べます。ただしアルゴリズムは独立しているため、同じアドレス指定とエフェクト構成には従いますが、特定のハードウェアモジュールの音そのものを再現するものではありません。1:1 のエミュレーションではなく、互換性のある再構成として捉えてください。サンプル・ROM データ・ファームウェアの同梱は一切なく、いかなるハードウェアメーカーとの提携や承認を意味するものでもありません。この互換性の背景にある標準や文献については、アルゴリズム根拠を参照してください。

前述のリバーブ・コーラス・ディレイのセンドリターンバスとは別に、GS は挿入エフェクト(EFX)を定義しています。センドリターンバスと異なり、ギターのエフェクターのようにパートの信号経路へ直接挿入されるエフェクトです。仕様上のブロックは 40 03 xx にあり、実機はモジュール全体でこのユニットを 1 つだけ持ちます。libsonare は 16 個持ちます。ユニット 0 は 40 03 xx のまま(意味も既定値もレイアウトも仕様どおり)で、残る 15 個は 40 3u xx にあり、ユニット番号はアドレスのニブルそのものです。40 30 xx はふたたびユニット 0 で、40 03 xx がすでに書き込んでいる記憶領域への 2 つめの入口です。

ルーティングもアドレスを増やしません。40 4x 22 PART EFX ASSIGN は 00 BYPASS と 01 EFX を仕様どおりの意味のまま保ち、自分の値の範囲を広げます。02〜10 がユニット 1〜15 を選びます。00〜10 の外側の値は、他の範囲外書き込みと同じく無視されます。衝突が起きないのは、40 30〜40 3F がどちらの機種のパラメータアドレスマップにも行を持たないからです。そのため仕様に準拠したファイルがこの拡張を使ってしまうことはなく、フィーチャーフラグが無くても安全です。実機は未知のアドレスを無視するので、この拡張を使ったファイルは実機でも挿入エフェクト 1 つで再生されます。

パート、インサート、システムエフェクト、マスター EQ
パート x40 4x 22ユニット 01–10挿入エフェクトタイプ + 20 パラメータ合算後に 1 回だけ通るマスター EQ40 02 00–03バイパス: 40 4x 20出力ドライミックス40 4x 22 = 00: バイパス、インサートなしパートで分岐CC91 · 93 · 94エフェクト後に分岐40 03 17–19システムエフェクトセンドリターン、ウェットのみ並列リバーブ40 01 30–37コーラス40 01 38–40ディレイ40 01 50–5Aリターンはミックスへ合流コーラス→リバーブ・コーラス→ディレイ・ディレイ→リバーブ: 保持するが結線しない(STATE)
  • ルーティングされたパートの経路
  • センドとリターン、ウェットのみ
  • バイパス: 40 4x 22 = 00
パート自身のリグは EFX ユニットの前で動作します。バイパス中のパートはパート経路から、ユニットへルーティングされたパートはエフェクト後段から、システムエフェクトへ送ります。

「実機の挙動」という言い方には別々の 2 つが混ざっていて、これを一緒にしてはいけません。モジュール全体でユニットが 1 つというのは、作られた機械のリソース上の制限であって GS の性質ではないので、外してあります。同じユニットへルーティングされたパートが合算されるほうは制限ですらありません。2 本のギターを 1 台のエフェクターへ通せば互いに干渉するのと同じで、エフェクトとはそういうものです。こちらは外していません。ユニットは、割り当てられた全パートの合算に対して 1 回だけ走ります。つまり変わったのはユニット数で、合算は変わっていません。「合算を元に戻す」がユニット数を制限する意味になることは決してありません。

ユニットの出力は 1 本の信号なので、その下流にあるものはパートではなくユニットに属します。システムエフェクトへのセンドはユニット自身のもの(40 3u 17〜19)で、ルーティングされたパートのパートレベルの CC91/CC93/CC94 センドは、残響の尾が二重に送られないよう抑止されます。マスター EQ のルーティングは、そのユニットへ入るパートたちの指定が一致するときにだけそれに従います。40 4x 20 のバイパスが効くのは、そのユニットに載る全パートがバイパスを要求したときだけで、そうでなければユニットは EQ を通ります。EQ を通すのが、どのパートもパワーオン時に持っている状態です。

パートリグと EFX の直列ルーティング ​

各パートには GS EFX ユニットの前に自身のリグ段があります。実際の経路は 音源 → パートリグ → EFX ユニット → システムエフェクトとマスター EQ です。パートを EFX ユニットへルーティングしても、音源がそのパートへ割り当てる既定のバンクリグはユニットの前に残ります。アンプなどの段を自動的に外すことはありません。ホストがリグを指定するとバンクリグを置き換えますが、EFX へのルーティングだけでは置き換わりません。EFX を割り当てないパートも自身のリグを通り、パート単位のシステムエフェクトセンドを維持します。 パートリグのモードは PART_RIG_MODES = ['bank', 'none', 'chain'] です。bank は現在のプログラムに対する音源自身のリグを使い、プログラムチェンジに追従する唯一のモードです。none は音源の直接出力(DI)を使い、chain はバンクリグを信号順の 1〜8 個のインサート段で置き換えます。各段はインサートファクトリーの processor 名と params オブジェクトで指定し、レイテンシは 48 kHz 基準で最大 256 samples です。無効なプロセッサやパラメータは拒否されます。 part は GS スロットの 0〜15、またはデスティネーション全体の既定値を表す PART_RIG_ALL_PARTS(0xFF)です。特定パートのエントリがデスティネーション既定値を上書きします。プロジェクトでは Project.setPartRig(...)、getPartRig(...)、clearPartRig(...) を使い、Node はリクエストオブジェクト、WASM は位置引数形式を公開します。Python の名前は set_part_rig、get_part_rig、clear_part_rig です。リアルタイムエンジンではバインド済み音源に対して setPartRig(...)/set_part_rig(...) を直接呼び出します。デスティネーションには音源が必要で、パートリグを実装しない組み込み音源やコールバック音源、またはマスタリング機能のないビルドの chain は NotSupported になります。 プロジェクトのエントリは、トラックがそのデスティネーションへまだルーティングされていなくてもデスティネーションとパートごとに保存され、バウンスでは SoundFont と物理モデルのデスティネーションへ適用されます。アンプを含むチェーンは最後のアンプまで入力をモノラルにまとめ、その後でパートのパンを戻します。SMF の書き出しにはパートリグを含めません。

GS の音色調整と EQ のロー/ハイシェルフは 1 次フィルターです。slopeDbOct は 6 dB/octave で、周波数はシェルフのゲイン変化が dB 値で半分になる位置を表します。1 次シェルフでは q は効きません。ホストからパラメトリック EQ のシェルフバンドを設定するときも、slopeDbOct: 6 で同じ次数を選べます。

パラメータのバイトが音に届くまで

公開されている資料に記載された EFX パラメータは、すべて操作子か段の切り替えに使われます。translated は実測の変換表、または記載された範囲から決まる刻みを使う対応です。designed は資料から変換則が決まらない箇所に、音の特性に合う法則を選んだ対応です。enables は段をオン・オフしたり、複数の段から選んだりします。これらは再実装の応答を示します。設計で選んだ法則が、実機でも使われていたと保証するものではありません。

GS 音源モジュールのデモ では、各パラメータの操作先と変換の根拠を確認できます。1 バイトが複数の操作子に届く場合や、セレクターで選んだ段に届く場合もあります。

どのバインディングにも「EFX を設定する」といった専用の型付き API はありません。実際の GS ハードウェアと同じように、EFX のタイプとパラメータは生の SysEx を送ることでのみプログラムします。ライブでは RealtimeEngine.pushMidiSysex() でそのバイト列を送り、オフラインではアレンジの MIDI に埋め込まれた SysEx がバウンス中にインラインで適用されます。

EFX タイプ → 挿入エフェクト ​

各 EFX タイプ番号が 1 つの挿入エフェクトを選びます。タイプ 0 は Thru(エフェクトなし)です。

EFX タイプGS EFX 名libsonare の挿入エフェクト
0x0100Stereo EQパラメトリック EQ
0x0101Spectrumグラフィック EQ
0x0102Enhancerプレゼンスエンハンサー
0x0103Humanizer母音フィルター
0x0110Overdrivesaturation.overdrive → saturation.ampSim
0x0111Distortionsaturation.distortion → saturation.ampSim
0x0120Phaserフェイザー
0x0121Auto Wahエンベロープ追従型レゾナントバンドパス
0x0122Rotary2ローターのロータリースピーカーモデル
0x0123Stereo Flangerフランジャー
0x0124Step Flangerフランジャー
0x0125Tremolo振幅変調として駆動するリングモジュレーター
0x0126Auto Panオートパン
0x0130Compressorコンプレッサー
0x0131Limiterリミッター
0x0140Hexa Chorus6声アンサンブル
0x0141Tremolo Chorusコーラス
0x0142Stereo Chorusコーラス
0x0143Space chorusコーラス(変調なし)
0x01443D Chorusコーラス(広がりを付加)
0x0150Stereo Delayステレオディレイ
0x0151Modulation Delayステレオディレイ
0x0152–0x01543-tap/4-tap/Time-Control Delayステレオディレイ
0x0155Reverbプレートリバーブ
0x0156Gate Reverbプレートリバーブ(ゲートテールは未実装)
0x01573D Delayステレオディレイ
0x01602-voice Pitch Shifterピッチシフター
0x0161Feedback Pitch Shifterピッチシフター(フィードバックループは未モデル化)
0x0170/0x01713D Auto/Manualバイノーラル定位
0x0172/0x0173Lo-Fi 1/2ビットクラッシャー

Humanizer(0x0103)は、ドライブと母音の操作子を持つ母音フィルターを使います。3D Auto と 3D Manual(0x0170、0x0171)はバイノーラル定位を使います。各パラメータは実測または設計で選んだ変換則を通して操作子に届き、任意の段があるエフェクトでは専用のスイッチでその段を切り替えます。

modern 実現方式の Overdrive と Distortion は、アンプシミュレーターの前に saturation.overdrive または saturation.distortion のペダルを置きます。Amp Type がアンプを選び、Amp Sw がすべてのアンプ段のキャビネットを切り替えます。SoundFont プレイヤーの GM プログラム 29(Overdriven Guitar)と 30(Distortion Guitar)も、ペダルからアンプへ進む同じ順序で鳴ります。

複合 EFX タイプ(多段チェーン) ​

複合 EFX タイプは、ハードウェアのブロック構成に合わせて、上記と同じ DSP インサートを直列につないだチェーンとして実現されます。たとえばギター用マルチエフェクトも、個々のアンプシミュレーター/コーラス/ディレイのインサートをつないで動作します。下の表は代表例で、実際のマップは 0x0200〜0x020C の 2 段マトリクス(Overdrive/Distortion/Enhancer を Chorus・Flanger・Delay に通す組み合わせ)と、0x0400〜0x0500 のギター/ベース/エレクトリックピアノ/キーボード用マルチプリセットまでを網羅します。

EFX タイプGS EFX 名チェーン(信号順)
0x0200OD → Chorusオーバードライブペダル → アンプシミュレーター → コーラス
0x0202OD → Delayオーバードライブペダル → アンプシミュレーター → ステレオディレイ
0x0400Guitar Multi 1コンプレッサー → アンプシミュレーター → コーラス → ディレイ
0x0405Bass Multiコンプレッサー → アンプシミュレーター(ベースキャビネット) → EQ → コーラス
0x0406Electric piano Multiエンハンサー → フェイザー → コーラス → オートパン
0x0500Keyboard Multiリングモジュレーター → EQ → ピッチシフター → フェイザー → ディレイ

モダンとクラシックの EFX ​

SoundFont 音源をバインドまたはバウンスするとき、gsEfxRealization で EFX の音作りを選べます。NativeSynth のフォールバックにも同じ指定が適用されます。

  • modern(既定値)は、現在のインサートプロセッサを組み合わせます。上の対応表はこちらの経路を示しています。
  • classic は、内部で 32 kHz の専用モデルを動かし、プロジェクトのサンプルレートへ変換します。EFX のタイプとパラメータのバイトは共通です。音源のボイスと、システムのリバーブ・コーラス・ディレイは、この選択とは別に動きます。サンプルレート変換の往復と出力 FIFO のプリフィルにより内部遅延が加わりますが、インサートはこれを 0 と報告します。並列パスやドライパスの位置合わせをするホストは、classic ではレポートされるレイテンシに頼らないでください。

GS 音源モジュールのデモ では、再生前に経路を選べます。選択中のパートを EFX に割り当て、エフェクトを選んで聴き比べてください。Thru には比較するインサーションエフェクトがありません。

レベルとバランスのバイト ​

EFX のバランスのバイトは 2 段のランプ則に従います。ドライとエフェクトのうち大きいほうの側は常にフルレベルに保たれるため、既定の中央値ではどちらも等倍で鳴り、中央から外れると片側だけが下がります。出力とタップのレベルのバイトは、0 以外の値がそれぞれ固有のレベルに対応し、-24 dB で頭打ちになりません(0 は無音)。ディレイとモジュレーションのバイトは、エフェクト自身が許す上限まで届きます。フィードバックは 98% まで、コーラスとアンサンブルのプリディレイは 100 ms までです。

ライブとオフラインでの実現方式 ​

  • オフライン(バウンス): アレンジに埋め込まれた EFX の SysEx はレンダー中にインラインで適用されます。バウンスの途中で EFX が変わっても、次のブロックから反映されます。
  • ライブ: pushMidiSysex() はオーディオスレッドの外で新しいエフェクトチェーンを構築し、ウェイトフリーに引き渡すため、ライブエンジンは再生を止めずに EFX の変化を反映できます。

下のデモでは、同じ持続和音を GS 互換プレイヤーで鳴らしながら挿入エフェクトを切り替えて、それぞれがトーンをどう変えるかをドライ音と聴き比べられます。

GS · EFXIDLE
GS 挿入エフェクト(EFX) — 一つずつ聴く

同じ持続和音を、GS 互換プレーヤーで、挿入エフェクト(EFX)を1つ挿して鳴らします。エフェクトを選ぶと音色がどう変わるかを聴けます — オーバードライブは歪みを、ロータリーは回転する揺れを、フェイザーはうねりを、ディレイは繰り返しを加えます。これらは公開情報をもとに再構成した libsonare 独自の DSP アルゴリズムで、GS の EFX 番号体系に対応づけています。同じアドレス指定に従いますが、特定ハードウェアの音そのものではありません。各レンダーは左右共通のピークで揃え、エフェクトによるラウドネスの違いは残します。「ドライ」で元の音と比べられます。3D オートと 3D マニュアルは、ヘッドホン向けの実際のステレオ・バイノーラル出力です。

エフェクト
実装方式

MIDI ヘルパーで GS バンクをオーサリングする

Project.midiBankProgram(ppq, group, channel, bankMsb, bankLsb, program) は、バンクセレクトとプログラムチェンジを setMidiEvents が受け付ける MIDI イベントへ展開します。GS バリエーションやドラムキットを選ぶ正しい方法です。Project.gmInstrumentName(program)、Project.gmDrumName(note)、Project.gm2InstrumentName(bankLsb, program)、Project.midiCcName(controller) のような静的ヘルパーがスロットに名前を付けるので、オーサリングコードが読みやすくなります。逆方向も対称です。Project.gmProgramForName(name)、Project.gmDrumNoteForName(name)、Project.midiCcIndexForName(name) は正規名から番号を返し(未知の名前は -1)、Project.gmFamilyName(family) と Project.gmFamilyFirstProgram(family) は 16 の GM 楽器ファミリーを列挙します。Project.gm2DrumSetName(bankLsb) と Project.gm2DrumName(bankLsb, note) は GM2 のドラムセットバリエーションに名前を付けます。

GM 音色マップ ​

128 プログラムすべての楽器名・エンジン・備考をまとめた表は、GM 音色マップにあります。