1pub fn program_name(program: u8) -> &'static str {
4 GM_NAMES.get(program as usize).copied().unwrap_or("Unknown")
5}
6
7static GM_NAMES: [&str; 128] = [
8 "Acoustic Grand Piano",
10 "Bright Acoustic Piano",
11 "Electric Grand Piano",
12 "Honky-tonk Piano",
13 "Electric Piano 1",
14 "Electric Piano 2",
15 "Harpsichord",
16 "Clavi",
17 "Celesta",
19 "Glockenspiel",
20 "Music Box",
21 "Vibraphone",
22 "Marimba",
23 "Xylophone",
24 "Tubular Bells",
25 "Dulcimer",
26 "Drawbar Organ",
28 "Percussive Organ",
29 "Rock Organ",
30 "Church Organ",
31 "Reed Organ",
32 "Accordion",
33 "Harmonica",
34 "Tango Accordion",
35 "Acoustic Guitar (nylon)",
37 "Acoustic Guitar (steel)",
38 "Electric Guitar (jazz)",
39 "Electric Guitar (clean)",
40 "Electric Guitar (muted)",
41 "Overdriven Guitar",
42 "Distortion Guitar",
43 "Guitar harmonics",
44 "Acoustic Bass",
46 "Electric Bass (finger)",
47 "Electric Bass (pick)",
48 "Fretless Bass",
49 "Slap Bass 1",
50 "Slap Bass 2",
51 "Synth Bass 1",
52 "Synth Bass 2",
53 "Violin",
55 "Viola",
56 "Cello",
57 "Contrabass",
58 "Tremolo Strings",
59 "Pizzicato Strings",
60 "Orchestral Harp",
61 "Timpani",
62 "String Ensemble 1",
64 "String Ensemble 2",
65 "Synth Strings 1",
66 "Synth Strings 2",
67 "Choir Aahs",
68 "Voice Oohs",
69 "Synth Voice",
70 "Orchestra Hit",
71 "Trumpet",
73 "Trombone",
74 "Tuba",
75 "Muted Trumpet",
76 "French Horn",
77 "Brass Section",
78 "Synth Brass 1",
79 "Synth Brass 2",
80 "Soprano Sax",
82 "Alto Sax",
83 "Tenor Sax",
84 "Baritone Sax",
85 "Oboe",
86 "English Horn",
87 "Bassoon",
88 "Clarinet",
89 "Piccolo",
91 "Flute",
92 "Recorder",
93 "Pan Flute",
94 "Blown Bottle",
95 "Shakuhachi",
96 "Whistle",
97 "Ocarina",
98 "Lead 1 (square)",
100 "Lead 2 (sawtooth)",
101 "Lead 3 (calliope)",
102 "Lead 4 (chiff)",
103 "Lead 5 (charang)",
104 "Lead 6 (voice)",
105 "Lead 7 (fifths)",
106 "Lead 8 (bass + lead)",
107 "Pad 1 (new age)",
109 "Pad 2 (warm)",
110 "Pad 3 (polysynth)",
111 "Pad 4 (choir)",
112 "Pad 5 (bowed)",
113 "Pad 6 (metallic)",
114 "Pad 7 (halo)",
115 "Pad 8 (sweep)",
116 "FX 1 (rain)",
118 "FX 2 (soundtrack)",
119 "FX 3 (crystal)",
120 "FX 4 (atmosphere)",
121 "FX 5 (brightness)",
122 "FX 6 (goblins)",
123 "FX 7 (echoes)",
124 "FX 8 (sci-fi)",
125 "Sitar",
127 "Banjo",
128 "Shamisen",
129 "Koto",
130 "Kalimba",
131 "Bag pipe",
132 "Fiddle",
133 "Shanai",
134 "Tinkle Bell",
136 "Agogo",
137 "Steel Drums",
138 "Woodblock",
139 "Taiko Drum",
140 "Melodic Tom",
141 "Synth Drum",
142 "Reverse Cymbal",
143 "Guitar Fret Noise",
145 "Breath Noise",
146 "Seashore",
147 "Bird Tweet",
148 "Telephone Ring",
149 "Helicopter",
150 "Applause",
151 "Gunshot",
152];
153
154pub fn drum_name(note: u8) -> &'static str {
158 const LOW: u8 = 35;
159 const HIGH: u8 = 81;
160 if !(LOW..=HIGH).contains(¬e) {
161 return "Unknown Drum";
162 }
163 GM_DRUM_NAMES[(note - LOW) as usize]
164}
165
166static GM_DRUM_NAMES: [&str; 47] = [
167 "Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare", "Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi-Hat", "High Floor Tom", "Pedal Hi-Hat", "Low Tom", "Open Hi-Hat", "Low-Mid Tom", "Hi-Mid Tom", "Crash Cymbal 1", "High Tom", "Ride Cymbal 1", "Chinese Cymbal", "Ride Bell", "Tambourine", "Splash Cymbal", "Cowbell", "Crash Cymbal 2", "Vibraslap", "Ride Cymbal 2", "Hi Bongo", "Low Bongo", "Mute Hi Conga", "Open Hi Conga", "Low Conga", "High Timbale", "Low Timbale", "High Agogo", "Low Agogo", "Cabasa", "Maracas", "Short Whistle", "Long Whistle", "Short Guiro", "Long Guiro", "Claves", "Hi Wood Block", "Low Wood Block", "Mute Cuica", "Open Cuica", "Mute Triangle", "Open Triangle", ];
215
216pub fn instrument_range(midi_program: u8) -> (u8, u8) {
221 GM_RANGES.get(midi_program as usize).copied().unwrap_or((0, 127))
222}
223
224static GM_RANGES: [(u8, u8); 128] = [
227 (21, 108), (21, 108), (21, 108), (21, 108),
229 (21, 108), (21, 108), (21, 108), (21, 108),
230 (60, 108), (52, 96), (48, 84), (45, 89), (36, 96), (43, 96), (36, 77), (36, 84), (24, 108), (24, 108), (24, 108), (24, 108),
241 (24, 108), (24, 108), (24, 108), (24, 108),
242 (40, 88), (40, 88), (40, 88), (40, 88),
244 (40, 88), (40, 88), (40, 88), (40, 88),
245 (28, 67), (28, 67), (28, 67), (28, 67),
247 (28, 67), (28, 67), (28, 67), (28, 67),
248 (55, 103), (48, 91), (36, 76), (28, 60), (55, 91), (55, 91), (21, 108), (36, 84), (21, 108), (21, 108), (21, 108), (21, 108),
259 (21, 108), (21, 108), (21, 108), (21, 108),
260 (52, 82), (36, 67), (28, 67), (52, 82), (43, 79), (52, 82), (52, 82), (52, 82), (56, 89), (44, 80), (38, 75), (32, 68), (45, 84), (36, 77), (34, 77), (52, 96), (60, 96), (60, 96), (55, 91), (55, 89), (48, 84), (48, 84), (48, 84), (48, 84), (0, 127), (0, 127), (0, 127), (0, 127),
289 (0, 127), (0, 127), (0, 127), (0, 127),
290 (0, 127), (0, 127), (0, 127), (0, 127),
292 (0, 127), (0, 127), (0, 127), (0, 127),
293 (0, 127), (0, 127), (0, 127), (0, 127),
295 (0, 127), (0, 127), (0, 127), (0, 127),
296 (0, 127), (0, 127), (0, 127), (0, 127),
298 (0, 127), (0, 127), (0, 127), (0, 127),
299 (0, 127), (0, 127), (0, 127), (0, 127),
301 (0, 127), (0, 127), (0, 127), (0, 127),
302 (0, 127), (0, 127), (0, 127), (0, 127),
304 (0, 127), (0, 127), (0, 127), (0, 127),
305];
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn gm_program_name_piano() {
313 assert_eq!(program_name(0), "Acoustic Grand Piano");
314 }
315
316 #[test]
317 fn gm_program_name_violin() {
318 assert_eq!(program_name(40), "Violin");
319 }
320
321 #[test]
322 fn gm_program_name_last_entry() {
323 assert_eq!(program_name(127), "Gunshot");
324 }
325
326 #[test]
327 fn gm_program_name_out_of_range() {
328 assert_eq!(program_name(128), "Unknown");
329 assert_eq!(program_name(255), "Unknown");
330 }
331
332 #[test]
333 fn drum_name_boundary_low() {
334 assert_eq!(drum_name(35), "Acoustic Bass Drum");
335 }
336
337 #[test]
338 fn drum_name_snare() {
339 assert_eq!(drum_name(38), "Acoustic Snare");
340 }
341
342 #[test]
343 fn drum_name_boundary_high() {
344 assert_eq!(drum_name(81), "Open Triangle");
345 }
346
347 #[test]
348 fn drum_name_out_of_range() {
349 assert_eq!(drum_name(0), "Unknown Drum");
350 assert_eq!(drum_name(34), "Unknown Drum");
351 assert_eq!(drum_name(82), "Unknown Drum");
352 assert_eq!(drum_name(255), "Unknown Drum");
353 }
354
355 #[test]
356 fn instrument_range_piano() {
357 assert_eq!(instrument_range(0), (21, 108));
358 }
359
360 #[test]
361 fn instrument_range_flute() {
362 assert_eq!(instrument_range(73), (60, 96));
363 }
364
365 #[test]
366 fn instrument_range_out_of_gm() {
367 assert_eq!(instrument_range(255), (0, 127));
368 }
369}