1// General MIDI program names, used to label imported tracks.
2export const GM_PROGRAMS: string[] = [
3 'Acoustic Grand Piano', 'Bright Acoustic Piano', 'Electric Grand Piano', 'Honky-tonk Piano',
4 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clavinet',
5 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone',
6 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer',
7 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ',
8 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion',
9 'Acoustic Guitar (nylon)', 'Acoustic Guitar (steel)', 'Electric Guitar (jazz)', 'Electric Guitar (clean)',
10 'Electric Guitar (muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar Harmonics',
11 'Acoustic Bass', 'Electric Bass (finger)', 'Electric Bass (pick)', 'Fretless Bass',
12 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2',
13 'Violin', 'Viola', 'Cello', 'Contrabass',
14 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani',
15 'String Ensemble 1', 'String Ensemble 2', 'Synth Strings 1', 'Synth Strings 2',
16 'Choir Aahs', 'Voice Oohs', 'Synth Voice', 'Orchestra Hit',
17 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet',
18 'French Horn', 'Brass Section', 'Synth Brass 1', 'Synth Brass 2',
19 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax',
20 'Oboe', 'English Horn', 'Bassoon', 'Clarinet',
21 'Piccolo', 'Flute', 'Recorder', 'Pan Flute',
22 'Blown Bottle', 'Shakuhachi', 'Whistle', 'Ocarina',
23 'Lead 1 (square)', 'Lead 2 (sawtooth)', 'Lead 3 (calliope)', 'Lead 4 (chiff)',
24 'Lead 5 (charang)', 'Lead 6 (voice)', 'Lead 7 (fifths)', 'Lead 8 (bass + lead)',
25 'Pad 1 (new age)', 'Pad 2 (warm)', 'Pad 3 (polysynth)', 'Pad 4 (choir)',
26 'Pad 5 (bowed)', 'Pad 6 (metallic)', 'Pad 7 (halo)', 'Pad 8 (sweep)',
27 'FX 1 (rain)', 'FX 2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)',
28 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)',
29 'Sitar', 'Banjo', 'Shamisen', 'Koto',
30 'Kalimba', 'Bag pipe', 'Fiddle', 'Shanai',
31 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock',
32 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal',
33 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet',
34 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot',
35];
37// Coarse mapping from a GM program number to the nearest builtin synth,
38// used when importing a MIDI file so playback lands roughly in the right
39// family without a soundfont. Channel 10 is handled separately (drum kit).
40export function gmProgramInstrument(program: number | undefined): string {
41 if (program === undefined) return 'piano';
42 const p = Math.max(0, Math.min(127, Math.floor(program)));
43 if (p <= 7) return 'piano'; // pianos
44 if (p <= 15) return 'epiano'; // chromatic percussion
45 if (p <= 23) return 'organ'; // organs and accordions
46 if (p <= 31) return 'pluck'; // guitars
47 if (p <= 39) return 'synthbass'; // basses
48 if (p <= 55) return 'strings'; // strings, ensembles, choirs
49 if (p <= 71) return 'brass'; // brass and reeds
50 if (p <= 87) return 'lead'; // pipes and synth leads
51 if (p <= 103) return 'strings'; // pads and FX
52 return 'pluck'; // ethnic, percussive, effects
53}
55export function noteName(pitch: number): string {
56 const names = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
57 return `${names[((pitch % 12) + 12) % 12]}${Math.floor(pitch / 12) - 1}`;
58}