Files
skills/docs/media/audio/midi/src/gm/level1.md
2026-05-29 08:20:56 +01:00

2.4 KiB

gm/level1

Purpose

The General MIDI Level 1 patch and percussion tables — the canonical instrument-name lookups every GM-compliant playback engine, score editor, and patch-browser needs. Without a shared source of truth, every consumer ends up hand-typing the same 128-entry table with the same handful of typos ("Honky-Tonk Piano" vs "Honky-tonk Piano" being a perennial favourite).

This module exposes three immutable, exhaustive tables: the 128-entry patch map (GM_LEVEL1_PATCHES, program 0..127), the 47-entry percussion map (GM_LEVEL1_PERCUSSION, notes 35..81), and the 16-entry family list (GM_LEVEL1_FAMILIES, grouped in eight-program blocks). Spelling and capitalisation follow the official MMA specification.

Features

  • Frozen GM_LEVEL1_PATCHES covering every program 0..127 with the spec-canonical name.
  • Frozen GM_LEVEL1_PERCUSSION covering channel-10 drum notes 35..81.
  • Frozen GM_LEVEL1_FAMILIES for UI grouping (program ÷ 8).
  • All tables use the MMA canonical capitalisation — diff-compatible with other specs.

Usage: Basic

import { GM_LEVEL1_PATCHES, GM_LEVEL1_PERCUSSION } from "@suaveplan/midi";

console.log(GM_LEVEL1_PATCHES[0]); // "Acoustic Grand Piano"
console.log(GM_LEVEL1_PERCUSSION[36]); // "Bass Drum 1"

Usage: Advanced

import { GM_LEVEL1_FAMILIES, GM_LEVEL1_PATCHES } from "@suaveplan/midi";

// Build a hierarchical patch browser for a UI tree component.
function buildPatchTree() {
  const tree = GM_LEVEL1_FAMILIES.map((family, i) => ({
    name: family,
    patches: Array.from({ length: 8 }, (_, j) => {
      const program = i * 8 + j;
      return { program, name: GM_LEVEL1_PATCHES[program]! };
    }),
  }));
  return tree;
}

API Reference

  • GM_LEVEL1_PATCHES: Readonly<Record<number, string>> — frozen map, 128 entries (programs 0..127).
  • GM_LEVEL1_PERCUSSION: Readonly<Record<number, string>> — frozen map, 47 entries (notes 35..81 on channel 10).
  • GM_LEVEL1_FAMILIES: readonly string[] — 16 instrument-family names, indexed by Math.floor(program / 8).

Implementation Notes

Both maps are declared as Object.freeze({ ... }) rather than via numeric arrays because programs and percussion notes are sparse from the consumer's perspective — looking up PERCUSSION[36] directly is clearer than PERCUSSION[36 - 35]. The freeze guarantees downstream compose patterns ({ ...GM_LEVEL1_PATCHES, 0: 'Custom Piano' }) produce a new object rather than mutating the canonical table.