Skip to content

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

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

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

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

GM フォールバックは、最後の手段として単純なサイン波を鳴らすだけのバンクではありません。SoundFont が未読み込み、または一部のプログラムを持たないとき、NativeSynth は要求された GM プログラムに近い内蔵の合成音源を選びます。ピアノは調整済みですが、その他の物理フォールバックモデルはまだ調整・キャリブレーションを行っていません。残りの作業は今後のパッチリリースで進めます。目的は、データ不要のプレビューと欠けたプログラムのカバーであり、完成済みのサンプル楽器並みのリアリティではありません。

GM 領域データ不要のフォールバック音源
プログラム 0-7、鍵盤拡張導波路グランドピアノ、FM エレピ/クラビ、3 種のレジストレーションを持つジャック&プレクトラム式ハープシコード
プログラム 8-15、クロマチックパーカッションモーダルのチェレスタ、グロッケン、オルゴール、ビブラフォン、マリンバ、シロフォン、チューブラーベル、それに Karplus-Strong のダルシマー
プログラム 16-23、オルガン加算ドローバーオルガン(16-18)、物理モデルの教会オルガンのフルーパイプ(19)、フリーリードエンジンのリードオルガン/アコーディオン、ハーモニカ、バンドネオン(20-23)
プログラム 24-37、ギター/ベースKarplus-Strong のナイロン、スチール、エレキ、ミュート/オーバードライブ/ディストーションギター、ベース各種
プログラム 40-47、弦/オーケストラボウイング弦、トレモロ弦のパッド、Karplus-Strong のピチカート弦とハープ、ティンパニのフォールバック
プログラム 52-54、合唱/声専用のソースフィルター方式のボーカルエンジンで鳴らす choir、voice ooh、synth voice
プログラム 56-79、金管/リード/フルート仮実装のリップリード金管(56-60)と FM 金管(61-63)、リード木管/サックス、エアジェットフルート
プログラム 104-107、エスニック撥弦バズブリッジ撥弦のシタール(104)、三味線(106)、箏(107)。バンジョー(105)は Karplus-Strong のまま
プログラム 112-119、パーカッシブパーカッションエンジンのチンクルベル、アゴゴ、スティールドラム、ウッドブロック、太鼓、メロディックタム、シンセドラム、リバースシンバル
ドラムと GS バリエーションGM/GS ドラムキットのバリエーション、GM2/GS バンクフォールバック。利用可能な場合は GS EFX を内蔵インサートチェーンへルーティング

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

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

GS バリエーション音色 ​

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

各バリエーションは1 つの音色に対して 2 つのアドレスを持ちます。GS のバンクセレクト MSB 番号と、GM2 の番号です。そのため、GS でオーサリングされたファイルと GM2 でオーサリングされたファイルは同じ音色で鳴ります。片方が相手の規格の番号を使ったせいでキャピタルに落ちる、ということが起きません。

キャピタルプログラムバリエーションGS MSBGM2
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 をバインドしたデスティネーションへ送ると、各ノートが対応するパーツを鳴らします。

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

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

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

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

どの世代を「現行」とみなすかは、対象とする実機によって決まります。それは最新世代のモジュール、つまり自身のマップがマップ 4 である機種で、マップ 3 の世代を切り捨てるのではなく取り込む形になっています。2 つのパラメータアドレスマップは共通するアドレスすべてで一致し、食い違うのは 10 か所だけです。そのうち 9 か所では新しいほうの機種が上位集合なので、マップ 3 向けのファイルはそのマップ(40 4x 00 = 03)を選んでそのまま鳴ります。ここから出てくる帰結が 2 つあり、どちらも作業を増やすのではなく減らします。実装すべきダブルモジュールモードは存在せず、対象機の 64 パートは第 2 のアドレス空間ではなく 16 パート × 4 ポートなので、パートを指すアドレスのニブルは 1 つのままです。

トーンマップの違いが音に出るのは、選んだマップにそのキットが無いときだけです。下の表の 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 キットの音色へ通します。GM のサウンドエフェクトプログラム(120-127、Guitar Fret Noise から Gunshot まで。GM 音色マップを参照)も同じ立場で、共通の汎用ノイズ系音色を共有します。どちらもデータ不要のフォールバックだけの制約です。これらのアドレスに実際のサンプルを持つ SoundFont を読み込めば、SF2 プレイヤー経由で通常どおり再生されます。

下の試聴は、同じグルーヴを 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 です。エンジンが返す名前のうち 6 つは、そのセットが模すドラムマシンの型番です。このページの表ではその 6 つを機種の種類で呼んでいますが、プログラム番号はどちらでも同じです。
  • 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, name: synthGsDrumKitName(program) }))
  .filter((kit): kit is { program: number; name: string } => kit.name !== null)
  .map((kit) => ({ ...kit, placeholder: synthGsDrumKitIsVoicedApart(kit.program) === false }));

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

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

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

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

このフラグは C ABI の SonareSynthInstrumentBinding では use_gm_programs、Python では auto_select_gm、WASM/Node の JavaScript では SynthPatch 記述子の useGmPrograms です。いずれも既定値は false で、固定パッチをフォールバックにする挙動を保ちます。useGmPrograms は JS バインディングの便宜機能で、NativeSynth パッチのフィールドではありません。2 つの CLI では値なしの --synth フラグがこれにあたります(sonare project bounce --in project.json --synth -o out.wav)。プリセット名を渡した場合はそのパッチに固定されます。

typescript
import { init, Project } from '@libraz/libsonare';

await init();

const project = new Project();
project.setSampleRate(48000);

// MIDI クリップ 1 つ: 出力先 0 へルーティングした 2 拍の C4 ノート
const { trackId, clipId } = project.addMidiClip(0, 4);
project.setTrackMidiDestination(trackId, 0);
project.setMidiEvents(clipId, [
  Project.midiNoteOn(0, 0, 0, 60, 100),
  Project.midiNoteOff(2, 0, 0, 60, 0),
]);

try {
  // 名前付きプリセットを出力先 0 へバインドしてステレオでレンダー
  const audio = project.bounceWithSynthInstrument('va:saw-lead', {
    totalFrames: 48000,
    numChannels: 2,
  });
  // audio はインターリーブの Float32(frames * channels)。無音ではない
} finally {
  project.delete();   // WASM ハンドルは GC されない — 必ず解放する
}
python
import libsonare as sonare

project = sonare.Project()
project.set_sample_rate(48000)

track_id, clip_id = project.add_midi_clip(0, 4)
project.set_track_midi_destination(track_id, 0)
project.set_midi_events(clip_id, [
    sonare.Project.midi_note_on(0, 0, 0, 60, 100),
    sonare.Project.midi_note_off(2, 0, 0, 60, 0),
])

# 名前付きプリセットを出力先 0 へバインドしてレンダー -> (frames, channels) float32
audio = project.bounce_with_synth_instrument(
    "va:saw-lead", total_frames=48000, num_channels=2,
)
project.close()
bash
# --synth <preset> はオシレーター波形に限らず、NativeSynth プリセットカタログの
# どの名前でも受け付けます。全一覧は `sonare project synth-presets` で取得できます。
# 値なしの --synth はプロジェクトの GM プログラムチェンジに追従します。
# プリセット名ではなくカスタムの SynthPatch オブジェクトを渡せるのはバインディング
# 専用です(上のブラウザ/Python を参照)。
sonare project bounce --in song.json -o synth.wav --synth saw
sonare project bounce --in song.json -o pad.wav --synth warm-pad

カスタマイズするには、名前の代わりに SynthPatch を渡します。プリセットを出発点に上書きしてください。

typescript
const audio = project.bounceWithSynthInstrument(
  {
    preset: 'warm-pad',
    cutoffHz: 1200,                // プリセットの 2800 Hz より暗く
    resonanceQ: 3,
    modRoutings: [{ source: 'lfo1', destination: 'cutoff-cents', depth: 600 }],
  },
  { totalFrames: 48000, numChannels: 2 },
);

totalFrames を 0 のままにすると、アレンジとパッチのリリーステイルから長さを自動導出します。未知のプリセット名は例外を投げます。bounceWith* が共有するチャンネル・サンプルレート・レイテンシなどは プロジェクトバウンス を参照してください。

GS アーキテクチャ層 ​

SoundFont プレイヤーは GM の上に、GS でオーサリングされたアレンジが期待する Roland-GS 拡張を実装します。以下はすべてアドレスで指定します。GS の書き込みは Roland のフレームで、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 イベントの両方に対応します。
  • センドリターン方式のシステムエフェクト — 16 パート共通の 1 つのセンドリターンバスに、リバーブ・コーラス・ディレイの 3 ユニットが載っています。各パートの送信量は 2 つの経路の合算です。チャンネル CC センドでは、CC91 がリバーブ送信、CC93 がコーラス送信、CC94 がディレイ送信を担います。リバーブとコーラスには、SF2 ゾーンジェネレーター reverbEffectsSend/chorusEffectsSend の値がさらに上乗せされます(GS のディレイ送信は CC 専用で、対応する SF2 ジェネレーターはありません)。パワーオン時は、音楽的に聞き取れる既定のルーム感(リバーブ送信 40、コーラス送信 8)から始まるため、リセット SysEx を送らない SMF でも空間の響きが残ります。これとは別に、パートごとのドライブインサート(ゲイン補正付きサチュレーション)もこのバスに並んで存在し、後述する GS の挿入エフェクト(EFX)とは別のものです。
  • MIDI 2.0/GM2 — MIDI 2.0 のバンク付きプログラムチェンジをデコードします。バンクセレクト LSB(CC#32) の解釈は MSB によって 2 通りに分かれます。
    • GM2 のアドレッシング — MSB が GM2 のメロディックバンク(0x79)またはパーカッションバンク(0x78)のとき、LSB はそのままバリエーション番号(またはパーカッションセット番号)で、GM2 の定義どおりです。
    • GS のトーンマップ選択 — それ以外の MSB では、LSB は MSB のバリエーション番号がどの世代の音色セットから選ばれるかを指定します。0 はモジュール自身の(最新の)マップ、1 から 4 は 4 つの世代の音色セットを定義された順(古いものから)に指します。つまり 4 が最新で、このモジュールでは 0 が選ぶのと同じセットです。これ以外の値は 0 として読まれます。このメッセージを受け取っていないモジュールは、すでに自分のマップで鳴っているからです。選ばれたマップより後に追加された音色やキットは、キャピタル音色または Standard キットへフォールバックします。これはその世代の実機がする動作と同じです。

LSB は 2 つの意味を持つ

これは Project.midiBankProgram(...) に bankLsb として渡すバイトで、最も間違えやすい値です。GM2 の MSB のもとではバリエーションを選び、GS の MSB のもとではトーンマップを選びます(バリエーション番号は MSB 側にあります)。GS のバリエーション MSB と並べて bankLsb: 1 と書いてもバリエーション 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
バイパスしているパートは、パート自身からリバーブ・コーラス・ディレイへ送ります。ユニットへルーティングされたパートはエフェクトの後段から、そのユニット自身の 3 つのセンドレベルで送ります。つまり残響の尾は、生の信号ではなく処理後の信号から作られます。

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

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

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母音フィルター
0x0110Overdriveアンプシミュレーター(クランチ系)
0x0111Distortionアンプシミュレーター(ハイゲイン系)
0x0120Phaserフェイザー
0x0121Auto Wahエンベロープ追従型レゾナントバンドパス
0x0122Rotary2ローターのロータリースピーカーモデル
0x0123Stereo Flangerフランジャー
0x0124Step Flangerフランジャー
0x0125Tremolo振幅変調として駆動するリングモジュレーター
0x0126Auto Panオートパン
0x0130Compressorコンプレッサー
0x0131Limiterリミッター
0x0140Hexa Chorus6声アンサンブル
0x0141Tremolo Chorusコーラス
0x0142Stereo Chorusコーラス
0x0143Space-Dコーラス(変調なし)
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ピッチシフター(フィードバックループは未モデル化)
0x0172/0x0173Lo-Fi 1/2ビットクラッシャー

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

複合 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 → コーラス
0x0406Rhodes Multiエンハンサー → フェイザー → コーラス → オートパン
0x0500Keyboard Multiリングモジュレーター → EQ → ピッチシフター → フェイザー → ディレイ

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

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

  • modern(既定値)は、現在のインサートプロセッサを組み合わせます。上の対応表はこちらの経路を示しています。
  • classic は、内部で 32 kHz の専用モデルを動かし、プロジェクトのサンプルレートへ変換します。EFX のタイプとパラメータのバイトは共通です。音源のボイスと、システムのリバーブ・コーラス・ディレイは、この選択とは別に動きます。

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

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

  • オフライン(バウンス) — アレンジに埋め込まれた 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 のドラムセットバリエーションに名前を付けます。

NativeSynth と SoundFont フォールバック ​

NativeSynth は SoundFont プレイヤーの下にあるセーフティネットです。bounceWithSf2Instrument でレンダーする(またはライブで SF2 をバインドする)と、libsonare はアレンジが実際に鳴らす各 (channel, bank, program) を解決します。

  • 読み込んだ SoundFont がそのプログラムをカバーしていれば、そのノートは SF2 から鳴ります(GS バリエーションとドラムフォールバックを含む)。
  • そうでなければ — SoundFont を一切読み込んでいない場合も含めて — そのノートは NativeSynth の GM フォールバックバンク(128 種すべてのプログラムとドラムマップ)で鳴ります。

レンダー前にプログラムごとのバックエンドを確認するには soundFontManifest() を使います。最初に使われる順に、各プログラムについて 'sf2' か 'synth' を報告します。

typescript
project.loadSoundFont(sf2Bytes);
const manifest = project.soundFontManifest();
// [{ channel, bank, program, backend: 'sf2' | 'synth', presetName }, ...]

GM フォールバックバンクが常に存在するため、データがないという理由で MIDI が無音になることはありません。SF2 データの読み込みやチャンネル/プログラムごとの解決は SoundFont プレイヤー を参照してください。

GM フォールバックのプログラムルーティング ​

フォールバックバンクは、GM プログラムのファミリーごとに最も近い NativeSynth エンジンを使います。楽器の挙動の違いが重要な箇所では、プログラム単位の上書きがあります。ピアノは調整済みですが、その他の物理フォールバックモデルはまだ調整・キャリブレーションを行っていません。下のアコースティック楽器系の行は、完成済みのサンプル楽器並みのリアリティではなく、ルーティング上の対応範囲として読んでください。

GM プログラム楽器フォールバックエンジン理由
4-5Electric Piano 1 / 2fmタイン/ベル的な明るさを位相変調で表現
6Harpsichordharpsichordジャック&プレクトラム。打鍵の速さが音量をほとんど変えない
7Clavifm打弦とピックアップの色づけを、現状は FM で近似
8, 10, 14Celesta, Music Box, Tubular Bellsmodalフェルトで打つスティールバー、ツインティースによるタインの揺らぎ、基音を持たない打撃ピッチ
9, 11-13Glockenspiel, Vibraphone, Marimba, Xylophonemodal調律されたバーの共鳴
15Dulcimerkarplus-strong暫定実装。撥弦ではなく打弦
16-23Organ familyadditive / pipe-organ / free-reedドローバー系レジストレーション(16-18)、仮実装の教会オルガンのフルーパイプ(19)、フリーリードのリードオルガン、ハーモニカ、バンドネオン(20-23)
24-31Guitar familykarplus-strong撥弦の導波路モデル
32-37Acoustic, electric, fretless, slap basskarplus-strongベース弦導波路。スラップ/偏波はプログラム別
40-43Violin, Viola, Cello, Contrabassbowed-string仮実装の摩擦励起型・持続弦導波路
44Tremolo Stringssubtractiveデチューンしたのこぎり波セクションにアンプトレモロ LFO を重ねたもので、擦弦モデルではない
45-46Pizzicato Strings, Orchestral Harpkarplus-strongヴァイオリンボディまたはスチール弦のコーパスへの短い撥弦
47Timpanipercussionノートトラッキングするケトルドラムのフォールバックボイス
48String Ensemble 1subtractiveソロ弓弦ではなく、パッド的なアンサンブル音色
52-54Choir Aahs, Voice Oohs, Synth Voicevocalソースフィルター方式のボイス(声門音源+母音フォルマントバンク)で、減算合成のパッドではない
56-60Trumpet, Trombone, Tuba, Muted Trumpet, French Hornbrass仮実装のリップリード金管導波路
61-63Brass Section, Synth Brass 1 / 2fm金管導波路ではなく、設計上 FM
64-71Saxophones, Oboe, English Horn, Bassoon, Clarinetreed仮実装のリードと管体の導波路
72-79Piccolo, Flute, Recorder, Pan Flute, Bottle, Shakuhachi, Whistle, Ocarinaflute仮実装のエアジェット/開管導波路
104, 106, 107Sitar, Shamisen, Kotoplucked-stringバズブリッジ(ジャワリ/サワリ)の撥弦。バンジョー(105)は karplus-strong のまま
112-119Tinkle Bell, Agogo, Steel Drums, Woodblock, Taiko Drum, Melodic Tom, Synth Drum, Reverse Cymbalpercussionノートトラッキングするパーカッションエンジンのボイスで、ドラムキットのマップとは別

Bank Select は、フォールバックがバリエーションを持つキャピタルプログラムすべてで読み取られます。全体の対応は前述の GS バリエーション音色を参照してください。

このルーティングは名前付きプリセットカタログとは別です。synthPresetNames() が返すのは手で設計されたプリセット(e-piano、harp、drum-kit など)であり、GM フォールバックバンクは SF2 フォールバック時に MIDI プログラム番号ごとの内部パッチを選びます。

GM 音色マップ — 全128プログラム ​

General MIDI の各プログラムは、音作りエンジンのいずれかに解決されます。全128プログラム分の楽器名・エンジン・備考をまとめた表は分量が大きいため、独立したページに置いています。各プログラムの正式名称は実行時に Project.gmInstrumentName(program) からも取得できます。

完全な表は GM 音色マップ を参照してください。