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] = [
230 (21, 108),
232 (21, 108),
233 (21, 108),
234 (21, 108),
235 (21, 108),
236 (21, 108),
237 (21, 108),
238 (21, 108),
239 (60, 108), (52, 96), (48, 84), (45, 89), (36, 96), (43, 96), (36, 77), (36, 84), (24, 108),
250 (24, 108),
251 (24, 108),
252 (24, 108),
253 (24, 108),
254 (24, 108),
255 (24, 108),
256 (24, 108),
257 (40, 88),
259 (40, 88),
260 (40, 88),
261 (40, 88),
262 (40, 88),
263 (40, 88),
264 (40, 88),
265 (40, 88),
266 (28, 67),
268 (28, 67),
269 (28, 67),
270 (28, 67),
271 (28, 67),
272 (28, 67),
273 (28, 67),
274 (28, 67),
275 (55, 103), (48, 91), (36, 76), (28, 60), (55, 91), (55, 91), (21, 108), (36, 84), (21, 108),
286 (21, 108),
287 (21, 108),
288 (21, 108),
289 (21, 108),
290 (21, 108),
291 (21, 108),
292 (21, 108),
293 (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),
322 (0, 127),
323 (0, 127),
324 (0, 127),
325 (0, 127),
326 (0, 127),
327 (0, 127),
328 (0, 127),
329 (0, 127),
331 (0, 127),
332 (0, 127),
333 (0, 127),
334 (0, 127),
335 (0, 127),
336 (0, 127),
337 (0, 127),
338 (0, 127),
340 (0, 127),
341 (0, 127),
342 (0, 127),
343 (0, 127),
344 (0, 127),
345 (0, 127),
346 (0, 127),
347 (0, 127),
349 (0, 127),
350 (0, 127),
351 (0, 127),
352 (0, 127),
353 (0, 127),
354 (0, 127),
355 (0, 127),
356 (0, 127),
358 (0, 127),
359 (0, 127),
360 (0, 127),
361 (0, 127),
362 (0, 127),
363 (0, 127),
364 (0, 127),
365 (0, 127),
367 (0, 127),
368 (0, 127),
369 (0, 127),
370 (0, 127),
371 (0, 127),
372 (0, 127),
373 (0, 127),
374];
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379
380 #[test]
381 fn gm_program_name_piano() {
382 assert_eq!(program_name(0), "Acoustic Grand Piano");
383 }
384
385 #[test]
386 fn gm_program_name_violin() {
387 assert_eq!(program_name(40), "Violin");
388 }
389
390 #[test]
391 fn gm_program_name_last_entry() {
392 assert_eq!(program_name(127), "Gunshot");
393 }
394
395 #[test]
396 fn gm_program_name_out_of_range() {
397 assert_eq!(program_name(128), "Unknown");
398 assert_eq!(program_name(255), "Unknown");
399 }
400
401 #[test]
402 fn drum_name_boundary_low() {
403 assert_eq!(drum_name(35), "Acoustic Bass Drum");
404 }
405
406 #[test]
407 fn drum_name_snare() {
408 assert_eq!(drum_name(38), "Acoustic Snare");
409 }
410
411 #[test]
412 fn drum_name_boundary_high() {
413 assert_eq!(drum_name(81), "Open Triangle");
414 }
415
416 #[test]
417 fn drum_name_out_of_range() {
418 assert_eq!(drum_name(0), "Unknown Drum");
419 assert_eq!(drum_name(34), "Unknown Drum");
420 assert_eq!(drum_name(82), "Unknown Drum");
421 assert_eq!(drum_name(255), "Unknown Drum");
422 }
423
424 #[test]
425 fn instrument_range_piano() {
426 assert_eq!(instrument_range(0), (21, 108));
427 }
428
429 #[test]
430 fn instrument_range_flute() {
431 assert_eq!(instrument_range(73), (60, 96));
432 }
433
434 #[test]
435 fn instrument_range_out_of_gm() {
436 assert_eq!(instrument_range(255), (0, 127));
437 }
438}