# gm/xg ## Purpose Yamaha's XG dialect uses Bank-Select MSB (CC 0) to select instrument variations on top of the GM1 base programs — the inverse of GS, which uses Bank LSB. The XG specification covers hundreds of variations across the full program range; this module exposes a curated set of the canonical XG patches every XG-aware engine should at least be able to label. The table key encoding intentionally matches `gm2Key(program, bankMsb)` so consumers can write a single resolver function that handles all three dialects by branching on which CC carried the bank select. ## Features - `XG_VARIATIONS` frozen map keyed by `program * 256 + bankMsb`. - Mandatory XG variation set; vendor-specific extensions layer on top. - Same key encoding as `GS_VARIATIONS` and `GM_LEVEL2_VARIATIONS` — uniform composition. - Frozen object to safeguard against accidental mutation. ## Usage: Basic ```ts import { XG_VARIATIONS, gm2Key } from "@suaveplan/midi"; console.log(XG_VARIATIONS[gm2Key(56, 16)]); // "Trumpet 2" ``` ## Usage: Advanced ```ts import { GM_LEVEL1_PATCHES, XG_VARIATIONS, gm2Key, } from "@suaveplan/midi"; function xgPatchName(program: number, bankMsb: number): string { return ( XG_VARIATIONS[gm2Key(program, bankMsb)] ?? GM_LEVEL1_PATCHES[program] ?? `Program ${program}` ); } ``` ## API Reference - `XG_VARIATIONS: Readonly>` — frozen map; key encoding is `program * 256 + bankMsb`. ## Implementation Notes Because XG selects on Bank MSB rather than LSB, an engine running multiple dialects in parallel must track both CCs separately and dispatch on the dialect chosen for the channel. The frozen-object idiom keeps the runtime contract immutable: composing `{ ...XG_VARIATIONS, [gm2Key(80, 64)]: 'Custom Lead' }` produces a fresh object without touching the canonical export.