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
222 .get(midi_program as usize)
223 .copied()
224 .unwrap_or((0, 127))
225}
226
227static GM_RANGES: [(u8, u8); 128] = [
233 (21, 108),
235 (21, 108),
236 (21, 108),
237 (21, 108),
238 (21, 108),
239 (21, 108),
240 (21, 108),
241 (21, 108),
242 (60, 108), (52, 96), (48, 84), (45, 89), (36, 96), (43, 96), (36, 77), (36, 84), (24, 108),
253 (24, 108),
254 (24, 108),
255 (24, 108),
256 (24, 108),
257 (24, 108),
258 (24, 108),
259 (24, 108),
260 (30, 91),
262 (30, 91),
263 (30, 91),
264 (30, 91),
265 (30, 91),
266 (30, 91),
267 (30, 91),
268 (30, 91),
269 (23, 72),
271 (23, 72),
272 (23, 72),
273 (23, 72),
274 (23, 72),
275 (23, 72),
276 (23, 72),
277 (23, 72),
278 (55, 105), (48, 93), (36, 93), (28, 67), (55, 91), (55, 91), (21, 108), (36, 84), (21, 108),
289 (21, 108),
290 (21, 108),
291 (21, 108),
292 (21, 108),
293 (21, 108),
294 (21, 108),
295 (21, 108),
296 (52, 86), (34, 77), (26, 67), (52, 86), (34, 79), (52, 82), (52, 82), (52, 82), (56, 91), (44, 87), (38, 81), (32, 72), (45, 93), (36, 84), (34, 77), (50, 96), (60, 108), (59, 98), (55, 91), (55, 89), (48, 84), (48, 84), (48, 84), (48, 84), (0, 127),
325 (0, 127),
326 (0, 127),
327 (0, 127),
328 (0, 127),
329 (0, 127),
330 (0, 127),
331 (0, 127),
332 (0, 127),
334 (0, 127),
335 (0, 127),
336 (0, 127),
337 (0, 127),
338 (0, 127),
339 (0, 127),
340 (0, 127),
341 (0, 127),
343 (0, 127),
344 (0, 127),
345 (0, 127),
346 (0, 127),
347 (0, 127),
348 (0, 127),
349 (0, 127),
350 (0, 127),
352 (0, 127),
353 (0, 127),
354 (0, 127),
355 (0, 127),
356 (0, 127),
357 (0, 127),
358 (0, 127),
359 (0, 127),
361 (0, 127),
362 (0, 127),
363 (0, 127),
364 (0, 127),
365 (0, 127),
366 (0, 127),
367 (0, 127),
368 (0, 127),
370 (0, 127),
371 (0, 127),
372 (0, 127),
373 (0, 127),
374 (0, 127),
375 (0, 127),
376 (0, 127),
377];
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 #[test]
384 fn gm_program_name_piano() {
385 assert_eq!(program_name(0), "Acoustic Grand Piano");
386 }
387
388 #[test]
389 fn gm_program_name_violin() {
390 assert_eq!(program_name(40), "Violin");
391 }
392
393 #[test]
394 fn gm_program_name_last_entry() {
395 assert_eq!(program_name(127), "Gunshot");
396 }
397
398 #[test]
399 fn gm_program_name_out_of_range() {
400 assert_eq!(program_name(128), "Unknown");
401 assert_eq!(program_name(255), "Unknown");
402 }
403
404 #[test]
405 fn drum_name_boundary_low() {
406 assert_eq!(drum_name(35), "Acoustic Bass Drum");
407 }
408
409 #[test]
410 fn drum_name_snare() {
411 assert_eq!(drum_name(38), "Acoustic Snare");
412 }
413
414 #[test]
415 fn drum_name_boundary_high() {
416 assert_eq!(drum_name(81), "Open Triangle");
417 }
418
419 #[test]
420 fn drum_name_out_of_range() {
421 assert_eq!(drum_name(0), "Unknown Drum");
422 assert_eq!(drum_name(34), "Unknown Drum");
423 assert_eq!(drum_name(82), "Unknown Drum");
424 assert_eq!(drum_name(255), "Unknown Drum");
425 }
426
427 #[test]
428 fn instrument_range_piano() {
429 assert_eq!(instrument_range(0), (21, 108));
430 }
431
432 #[test]
433 fn instrument_range_flute() {
434 assert_eq!(instrument_range(73), (59, 98));
435 }
436
437 #[test]
438 fn instrument_range_out_of_gm() {
439 assert_eq!(instrument_range(255), (0, 127));
440 }
441}