1use core::convert::TryFrom;
2
3#[cfg(feature = "std")]
4use strum::{Display, EnumIter, EnumString};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum GeneralMidi {
11 GM1 = 1,
12 GM2 = 3,
13 Off = 2,
14}
15
16#[cfg_attr(feature = "std", derive(EnumIter, Display, EnumString))]
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(u8)]
36pub enum GMSoundSet {
37 AcousticGrandPiano = 0,
38 BrightAcousticPiano = 1,
39 ElectricGrandPiano = 2,
40 HonkytonkPiano = 3,
41 ElectricPiano1 = 4,
42 ElectricPiano2 = 5,
43 Harpsichord = 6,
44 Clavi = 7,
45 Celesta = 8,
46 Glockenspiel = 9,
47 MusicBox = 10,
48 Vibraphone = 11,
49 Marimba = 12,
50 Xylophone = 13,
51 TubularBells = 14,
52 Dulcimer = 15,
53 DrawbarOrgan = 16,
54 PercussiveOrgan = 17,
55 RockOrgan = 18,
56 ChurchOrgan = 19,
57 ReedOrgan = 20,
58 Accordion = 21,
59 Harmonica = 22,
60 TangoAccordion = 23,
61 AcousticGuitarNylon = 24,
62 AcousticGuitarSteel = 25,
63 ElectricGuitarJazz = 26,
64 ElectricGuitarClean = 27,
65 ElectricGuitarMuted = 28,
66 OverdrivenGuitar = 29,
67 DistortionGuitar = 30,
68 GuitarHarmonics = 31,
69 AcousticBass = 32,
70 ElectricBassFinger = 33,
71 ElectricBassPick = 34,
72 FretlessBass = 35,
73 SlapBass1 = 36,
74 SlapBass2 = 37,
75 SynthBass1 = 38,
76 SynthBass2 = 39,
77 Violin = 40,
78 Viola = 41,
79 Cello = 42,
80 Contrabass = 43,
81 TremoloStrings = 44,
82 PizzicatoStrings = 45,
83 OrchestralHarp = 46,
84 Timpani = 47,
85 StringEnsemble1 = 48,
86 StringEnsemble2 = 49,
87 SynthStrings1 = 50,
88 SynthStrings2 = 51,
89 ChoirAahs = 52,
90 VoiceOohs = 53,
91 SynthVoice = 54,
92 OrchestraHit = 55,
93 Trumpet = 56,
94 Trombone = 57,
95 Tuba = 58,
96 MutedTrumpet = 59,
97 FrenchHorn = 60,
98 BrassSection = 61,
99 SynthBrass1 = 62,
100 SynthBrass2 = 63,
101 SopranoSax = 64,
102 AltoSax = 65,
103 TenorSax = 66,
104 BaritoneSax = 67,
105 Oboe = 68,
106 EnglishHorn = 69,
107 Bassoon = 70,
108 Clarinet = 71,
109 Piccolo = 72,
110 Flute = 73,
111 Recorder = 74,
112 PanFlute = 75,
113 BlownBottle = 76,
114 Shakuhachi = 77,
115 Whistle = 78,
116 Ocarina = 79,
117 Lead1 = 80,
118 Lead2 = 81,
119 Lead3 = 82,
120 Lead4 = 83,
121 Lead5 = 84,
122 Lead6 = 85,
123 Lead7 = 86,
124 Lead8 = 87,
125 Pad1 = 88,
126 Pad2 = 89,
127 Pad3 = 90,
128 Pad4 = 91,
129 Pad5 = 92,
130 Pad6 = 93,
131 Pad7 = 94,
132 Pad8 = 95,
133 FX1 = 96,
134 FX2 = 97,
135 FX3 = 98,
136 FX4 = 99,
137 FX5 = 100,
138 FX6 = 101,
139 FX7 = 102,
140 FX8 = 103,
141 Sitar = 104,
142 Banjo = 105,
143 Shamisen = 106,
144 Koto = 107,
145 Kalimba = 108,
146 Bagpipe = 109,
147 Fiddle = 110,
148 Shanai = 111,
149 TinkleBell = 112,
150 Agogo = 113,
151 SteelDrums = 114,
152 Woodblock = 115,
153 TaikoDrum = 116,
154 MelodicTom = 117,
155 SynthDrum = 118,
156 ReverseCymbal = 119,
157 GuitarFretNoise = 120,
158 BreathNoise = 121,
159 Seashore = 122,
160 BirdTweet = 123,
161 TelephoneRing = 124,
162 Helicopter = 125,
163 Applause = 126,
164 Gunshot = 127,
165}
166
167impl TryFrom<u8> for GMSoundSet {
168 type Error = &'static str;
169
170 fn try_from(value: u8) -> Result<Self, Self::Error> {
171 if value > 127 {
172 return Err("Invalid value for GMSoundSet");
173 }
174 Ok(unsafe { core::mem::transmute::<u8, GMSoundSet>(value) })
175 }
176}
177
178#[cfg_attr(feature = "std", derive(EnumIter, Display, EnumString))]
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197#[repr(u8)]
198pub enum GMPercussionMap {
199 AcousticBassDrum = 35,
200 BassDrum1 = 36,
201 SideStick = 37,
202 AcousticSnare = 38,
203 HandClap = 39,
204 ElectricSnare = 40,
205 LowFloorTom = 41,
206 ClosedHiHat = 42,
207 HighFloorTom = 43,
208 PedalHiHat = 44,
209 LowTom = 45,
210 OpenHiHat = 46,
211 LowMidTom = 47,
212 HiMidTom = 48,
213 CrashCymbal1 = 49,
214 HighTom = 50,
215 RideCymbal1 = 51,
216 ChineseCymbal = 52,
217 RideBell = 53,
218 Tambourine = 54,
219 SplashCymbal = 55,
220 Cowbell = 56,
221 CrashCymbal2 = 57,
222 Vibraslap = 58,
223 RideCymbal2 = 59,
224 HiBongo = 60,
225 LowBongo = 61,
226 MuteHiConga = 62,
227 OpenHiConga = 63,
228 LowConga = 64,
229 HighTimbale = 65,
230 LowTimbale = 66,
231 HighAgogo = 67,
232 LowAgogo = 68,
233 Cabasa = 69,
234 Maracas = 70,
235 ShortWhistle = 71,
236 LongWhistle = 72,
237 ShortGuiro = 73,
238 LongGuiro = 74,
239 Claves = 75,
240 HiWoodBlock = 76,
241 LowWoodBlock = 77,
242 MuteCuica = 78,
243 OpenCuica = 79,
244 MuteTriangle = 80,
245 OpenTriangle = 81,
246}
247
248impl TryFrom<u8> for GMPercussionMap {
249 type Error = &'static str;
250
251 fn try_from(value: u8) -> Result<Self, Self::Error> {
252 if !(35..=81).contains(&value) {
253 return Err("Invalid value for GMPercussionMap");
254 }
255 Ok(unsafe { core::mem::transmute::<u8, GMPercussionMap>(value) })
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[cfg(feature = "std")]
264 use std::str::FromStr;
265 #[cfg(feature = "std")]
266 use strum::IntoEnumIterator;
267
268 #[cfg(feature = "std")]
269 #[test]
270 fn gm_iter() {
271 for (i, inst) in GMSoundSet::iter().enumerate() {
272 assert_eq!(inst as u8, i as u8);
274 }
275 }
276
277 #[cfg(feature = "std")]
278 #[test]
279 fn gm_from_string() {
280 assert_eq!(
281 GMSoundSet::TenorSax,
282 GMSoundSet::from_str("TenorSax").unwrap()
283 );
284 }
285
286 #[cfg(feature = "std")]
287 #[test]
288 fn gm_display() {
289 assert_eq!("TenorSax", format!("{}", GMSoundSet::TenorSax));
290 }
291
292 #[cfg(feature = "std")]
293 #[test]
294 fn gm_tostring() {
295 assert_eq!("TenorSax", GMSoundSet::TenorSax.to_string());
296 }
297
298 #[test]
299 fn gm_as_u8() {
300 assert_eq!(0, GMSoundSet::AcousticGrandPiano as u8);
301
302 assert_eq!(127, GMSoundSet::Gunshot as u8);
303 }
304
305 #[test]
306 fn gm_from_u8() {
307 assert_eq!(
308 GMSoundSet::AcousticGrandPiano,
309 GMSoundSet::try_from(0).unwrap()
310 );
311 assert_eq!(GMSoundSet::Gunshot, GMSoundSet::try_from(127).unwrap());
312 }
313
314 #[test]
315 fn gm_from_u8_invalid() {
316 assert!(GMSoundSet::try_from(128).is_err());
317 }
318
319 #[test]
320 fn gm_percussion_as_u8() {
321 assert_eq!(35, GMPercussionMap::AcousticBassDrum as u8);
322 assert_eq!(81, GMPercussionMap::OpenTriangle as u8);
323 }
324
325 #[test]
326 fn gm_percussion_from_u8() {
327 assert_eq!(
328 GMPercussionMap::AcousticBassDrum,
329 GMPercussionMap::try_from(35).unwrap()
330 );
331 assert_eq!(
332 GMPercussionMap::OpenTriangle,
333 GMPercussionMap::try_from(81).unwrap()
334 );
335 }
336
337 #[test]
338 fn gm_percussion_from_u8_invalid() {
339 assert!(GMPercussionMap::try_from(34).is_err());
340 assert!(GMPercussionMap::try_from(82).is_err());
341 }
342
343 #[cfg(feature = "std")]
344 #[test]
345 fn percussion_iter() {
346 for (i, perc) in GMPercussionMap::iter().enumerate() {
347 assert_eq!(perc as u8, (i + 35) as u8);
349 }
350 }
351}