redact_composer_midi/
gm.rs

1/// General MIDI Level 1 types.
2use num;
3use num_derive;
4use num_derive::FromPrimitive;
5use std::ops::{Add, Sub};
6
7use crate::elements::Program;
8use redact_composer_core::{derive::Element, IntoSegment};
9use redact_composer_core::{
10    elements::PlayNote,
11    render::{AdhocRenderer, RenderEngine, Renderer, Result},
12    Segment,
13};
14
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17
18/// Default renderers used for GM [`Element`](redact_composer_core::Element)s
19/// ([`Instrument`] and [`DrumHit`]).
20pub fn renderers() -> RenderEngine {
21    RenderEngine::new() + Instrument::renderer() + DrumHit::renderer()
22}
23
24/// Types implementing [`Element`](redact_composer_core::Element).
25pub mod elements {
26    pub use super::{DrumHit, Instrument};
27}
28
29/// Instruments defined according to
30/// [GM1 Sound Set](https://www.midi.org/specifications-old/item/gm-level-1-sound-set)
31#[derive(Element, Debug, Hash, FromPrimitive, PartialEq, Clone, Copy)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[allow(missing_docs)]
34pub enum Instrument {
35    // Piano (0..=7)
36    AcousticGrandPiano,
37    BrightAcousticPiano,
38    ElectricGrandPiano,
39    HonkyTonkPiano,
40    ElectricPiano1,
41    ElectricPiano2,
42    Harpsichord,
43    Clavi,
44
45    // Chromatic Percussion (8..=15)
46    Celesta,
47    Glockenspiel,
48    MusicBox,
49    Vibraphone,
50    Marimba,
51    Xylophone,
52    TubularBells,
53    Dulcimer,
54
55    // Organ (16..=23)
56    DrawbarOrgan,
57    PercussiveOrgan,
58    RockOrgan,
59    ChurchOrgan,
60    ReedOrgan,
61    Accordion,
62    Harmonica,
63    TangoAccordion,
64
65    // Guitar (24..=31)
66    AcousticGuitarNylon,
67    AcousticGuitarSteel,
68    ElectricGuitarJazz,
69    ElectricGuitarClean,
70    ElectricGuitarMuted,
71    OverdrivenGuitar,
72    DistortionGuitar,
73    GuitarHarmonics,
74
75    // Bass (32..=39)
76    AcousticBass,
77    ElectricBassFinger,
78    ElectricBassPick,
79    FretlessBass,
80    SlapBass1,
81    SlapBass2,
82    SynthBass1,
83    SynthBass2,
84
85    // Strings (40..=47)
86    Violin,
87    Viola,
88    Cello,
89    Contrabass,
90    TremoloStrings,
91    PizzicatoStrings,
92    OrchestralHarp,
93    Timpani,
94
95    // Ensemble (48..=55)
96    StringEnsemble1,
97    StringEnsemble2,
98    SynthStrings1,
99    SynthStrings2,
100    ChoirAahs,
101    ChoirOohs,
102    SynthVoice,
103    OrchestraHit,
104
105    // Brass (56..=63)
106    Trumpet,
107    Trombone,
108    Tuba,
109    MutedTrumpet,
110    FrenchHorn,
111    BrassSection,
112    SynthBrass1,
113    SynthBrass2,
114
115    // Reed (64..=71)
116    SopranoSax,
117    AltoSax,
118    TenorSax,
119    BaritoneSax,
120    Oboe,
121    EnglishHorn,
122    Bassoon,
123    Clarinet,
124
125    // Pipe (72..=79)
126    Piccolo,
127    Flute,
128    Recorder,
129    PanFlute,
130    BlownBottle,
131    Shakuhachi,
132    Whistle,
133    Ocarina,
134
135    // Synth Lead (80..=87)
136    LeadSquare,
137    LeadSawtooth,
138    LeadCalliope,
139    LeadChiff,
140    LeadCharang,
141    LeadVoice,
142    LeadFifths,
143    LeadBassPlusLead,
144
145    // Synth Pad (88..=95)
146    PadNewAge,
147    PadWarm,
148    PadPolySynth,
149    PadChoir,
150    PadBowed,
151    PadMetallic,
152    PadHalo,
153    PadSweep,
154
155    // Synth Effects (96..=103)
156    FXRain,
157    FXSoundtrack,
158    FXCrystal,
159    FXAtmosphere,
160    FXBrightness,
161    FXGoblins,
162    FXEchoes,
163    FXSciFi,
164
165    // Ethnic (104..=111)
166    Sitar,
167    Banjo,
168    Shamisen,
169    Koto,
170    Kalimba,
171    BagPipe,
172    Fiddle,
173    Shanai,
174
175    // Percussive (112..=119)
176    TinkleBell,
177    Agogo,
178    SteelDrums,
179    Woodblock,
180    TaikoDrum,
181    MelodicTom,
182    SynthDrum,
183    ReverseCymbal,
184
185    // Sound Effects (120..127)
186    GuitarFretNoise,
187    BreathNoise,
188    Seashore,
189    BirdTweet,
190    TelephoneRing,
191    Helicopter,
192    Applause,
193    Gunshot,
194}
195
196impl From<Instrument> for Program {
197    fn from(value: Instrument) -> Program {
198        Program(value as u8)
199    }
200}
201
202impl Instrument {
203    /// Renderer that render an [`Instrument`] segment as a [`Program`] with the same timing.
204    pub fn renderer() -> impl Renderer<Element = Self> {
205        AdhocRenderer::<Self>::new(|segment, _| {
206            Result::Ok(vec![Program::from(*segment.element).over(segment.timing)])
207        })
208    }
209}
210
211/// ##Example
212/// ```rust
213/// # use redact_composer_midi::gm::elements::Instrument;
214/// # use redact_composer_midi::gm::Instruments;
215/// #
216/// let pianos = Instrument::AcousticGrandPiano + Instrument::BrightAcousticPiano;
217/// assert_eq!(pianos, Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] });
218/// ```
219impl Add for Instrument {
220    type Output = Instruments;
221
222    fn add(self, rhs: Self) -> Self::Output {
223        Instruments {
224            instruments: vec![self, rhs],
225        }
226    }
227}
228
229/// ##Example
230/// ```rust
231/// # use redact_composer_midi::gm::elements::Instrument;
232/// # use redact_composer_midi::gm::Instruments;
233/// #
234/// let pianos = Instrument::AcousticGrandPiano
235///                 + Instruments { instruments: vec![Instrument::BrightAcousticPiano] };
236/// assert_eq!(pianos, Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] });
237/// ```
238impl Add<Instruments> for Instrument {
239    type Output = Instruments;
240
241    fn add(self, rhs: Instruments) -> Self::Output {
242        Instruments {
243            instruments: vec![self],
244        } + rhs
245    }
246}
247
248/// ##Example
249/// ```rust
250/// # use redact_composer_midi::gm::elements::Instrument;
251/// #
252/// assert_eq!(Instrument::from(0u8), Instrument::AcousticGrandPiano);
253/// ```
254impl From<u8> for Instrument {
255    fn from(value: u8) -> Self {
256        num::FromPrimitive::from_u8(value).unwrap()
257    }
258}
259
260impl From<Instrument> for u8 {
261    fn from(value: Instrument) -> Self {
262        value as u8
263    }
264}
265
266/// A thin wrapper around a [`Vec<Instrument>`] with Add/Subtract operations.
267#[derive(Debug, Clone, PartialEq)]
268pub struct Instruments {
269    /// A list of instruments.
270    pub instruments: Vec<Instrument>,
271}
272
273impl Instruments {
274    /// All instruments.
275    pub fn all() -> Instruments {
276        Instruments {
277            instruments: (0..128).map(Instrument::from).collect(),
278        }
279    }
280
281    /// GM1 piano instruments.
282    pub fn piano() -> Instruments {
283        Instruments {
284            instruments: (0..8).map(Instrument::from).collect(),
285        }
286    }
287
288    /// GM1 tonal percussive instruments.
289    pub fn tonal_percussive() -> Instruments {
290        Instruments {
291            instruments: (8..16).map(Instrument::from).collect(),
292        }
293    }
294
295    /// GM1 organ instruments.
296    pub fn organ() -> Instruments {
297        Instruments {
298            instruments: (16..24).map(Instrument::from).collect(),
299        }
300    }
301
302    /// GM1 guitar instruments.
303    pub fn guitar() -> Instruments {
304        Instruments {
305            instruments: (24..32).map(Instrument::from).collect(),
306        }
307    }
308
309    /// GM1 bass instruments.
310    pub fn bass() -> Instruments {
311        Instruments {
312            instruments: (32..40).map(Instrument::from).collect(),
313        }
314    }
315
316    /// GM1 string instruments.
317    pub fn strings() -> Instruments {
318        Instruments {
319            instruments: (40..48).map(Instrument::from).collect(),
320        }
321    }
322
323    /// GM1 ensemble instruments.
324    pub fn ensemble() -> Instruments {
325        Instruments {
326            instruments: (48..56).map(Instrument::from).collect(),
327        }
328    }
329
330    /// GM1 brass instruments.
331    pub fn brass() -> Instruments {
332        Instruments {
333            instruments: (56..64).map(Instrument::from).collect(),
334        }
335    }
336
337    /// GM1 reed instruments.
338    pub fn reed() -> Instruments {
339        Instruments {
340            instruments: (64..72).map(Instrument::from).collect(),
341        }
342    }
343
344    /// GM1 pipe instruments.
345    pub fn pipe() -> Instruments {
346        Instruments {
347            instruments: (72..80).map(Instrument::from).collect(),
348        }
349    }
350
351    /// GM1 synth lead instruments.
352    pub fn synth_lead() -> Instruments {
353        Instruments {
354            instruments: (80..88).map(Instrument::from).collect(),
355        }
356    }
357
358    /// GM1 synth pad instruments.
359    pub fn synth_pad() -> Instruments {
360        Instruments {
361            instruments: (88..96).map(Instrument::from).collect(),
362        }
363    }
364
365    /// GM1 synth FX instruments.
366    pub fn synth_fx() -> Instruments {
367        Instruments {
368            instruments: (96..104).map(Instrument::from).collect(),
369        }
370    }
371
372    /// GM1 ethnic instruments.
373    pub fn ethnic() -> Instruments {
374        Instruments {
375            instruments: (104..112).map(Instrument::from).collect(),
376        }
377    }
378
379    /// GM1 percussive instruments.
380    pub fn percussive() -> Instruments {
381        Instruments {
382            instruments: (112..120).map(Instrument::from).collect(),
383        }
384    }
385
386    /// GM1 sound FX instruments.
387    pub fn sound_fx() -> Instruments {
388        Instruments {
389            instruments: (120..128).map(Instrument::from).collect(),
390        }
391    }
392
393    /// Returns "melodic" instruments which have a clear tone, and are not overly percussive.
394    pub fn melodic() -> Instruments {
395        Self::all()
396            - Self::percussive()
397            - Self::sound_fx()
398            - Self::synth_fx()
399            - Instrument::Timpani
400            - Instrument::TubularBells
401            - Instrument::PadBowed
402            - Instrument::LeadFifths
403            - Instrument::OrchestraHit
404            - Instrument::Kalimba
405            - Instrument::GuitarHarmonics
406    }
407}
408
409impl IntoIterator for Instruments {
410    type Item = Instrument;
411
412    type IntoIter = std::vec::IntoIter<Self::Item>;
413
414    fn into_iter(self) -> Self::IntoIter {
415        self.instruments.into_iter()
416    }
417}
418
419/// ##Example
420/// ```rust
421/// # use redact_composer_midi::gm::elements::Instrument;
422/// # use redact_composer_midi::gm::Instruments;
423/// #
424/// let pianos = Instruments { instruments: vec![Instrument::AcousticGrandPiano] }
425///                         + Instruments { instruments: vec![Instrument::BrightAcousticPiano] };
426/// assert_eq!(pianos, Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] });
427/// ```
428impl Add for Instruments {
429    type Output = Self;
430
431    fn add(self, rhs: Self) -> Self::Output {
432        Instruments {
433            instruments: self.into_iter().chain(rhs).collect(),
434        }
435    }
436}
437
438/// ##Example
439/// ```rust
440/// # use redact_composer_midi::gm::elements::Instrument;
441/// # use redact_composer_midi::gm::Instruments;
442/// #
443/// let pianos = Instruments { instruments: vec![Instrument::AcousticGrandPiano] }
444///                         + Instrument::BrightAcousticPiano;
445/// assert_eq!(pianos, Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] });
446/// ```
447impl Add<Instrument> for Instruments {
448    type Output = Self;
449
450    fn add(self, rhs: Instrument) -> Self::Output {
451        Instruments {
452            instruments: self.into_iter().chain(vec![rhs]).collect(),
453        }
454    }
455}
456
457/// ##Example
458/// ```rust
459/// # use redact_composer_midi::gm::elements::Instrument;
460/// # use redact_composer_midi::gm::Instruments;
461/// #
462/// let no_violins = Instruments { instruments: vec![Instrument::Violin, Instrument::Cello] }
463///                         - Instruments { instruments: vec![Instrument::Violin] };
464/// assert_eq!(no_violins, Instruments { instruments: vec![Instrument::Cello] });
465/// ```
466impl Sub for Instruments {
467    type Output = Self;
468
469    fn sub(self, rhs: Self) -> Self::Output {
470        Instruments {
471            instruments: self
472                .into_iter()
473                .filter(|i| !rhs.instruments.contains(i))
474                .collect(),
475        }
476    }
477}
478
479/// ##Example
480/// ```rust
481/// # use redact_composer_midi::gm::elements::Instrument;
482/// # use redact_composer_midi::gm::Instruments;
483/// #
484/// let no_violins = Instruments { instruments: vec![Instrument::Violin, Instrument::Cello] }
485///                         - Instrument::Violin;
486/// assert_eq!(no_violins, Instruments { instruments: vec![Instrument::Cello] });
487///
488/// let instruments = Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] };
489/// ```
490impl Sub<Instrument> for Instruments {
491    type Output = Self;
492
493    fn sub(self, rhs: Instrument) -> Self::Output {
494        Instruments {
495            instruments: self.into_iter().filter(|i| *i != rhs).collect(),
496        }
497    }
498}
499
500/// ##Example
501/// ```rust
502/// # use redact_composer_midi::gm::elements::Instrument;
503/// # use redact_composer_midi::gm::Instruments;
504/// #
505/// let instruments = Instruments { instruments: vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano] };
506/// let vec_instruments: Vec<Instrument> = instruments.into();
507/// assert_eq!(
508///     vec_instruments,
509///     vec![Instrument::AcousticGrandPiano, Instrument::BrightAcousticPiano]
510/// );
511/// ```
512impl From<Instruments> for Vec<Instrument> {
513    fn from(value: Instruments) -> Self {
514        value.instruments
515    }
516}
517
518/// Represents a drum hit. (Similar to [`PlayNote`]).
519#[derive(Element, Clone, Copy, Debug)]
520#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
521pub struct DrumHit {
522    /// The drum hit sound type.
523    pub hit: DrumHitType,
524    /// The strength of attack.
525    pub velocity: u8,
526}
527
528impl DrumHit {
529    /// Renderer that renders a [`DrumHit`] as a [`PlayNote`] over the same timing.
530    pub fn renderer() -> impl Renderer<Element = Self> {
531        AdhocRenderer::<Self>::new(|segment, _| {
532            Result::Ok(vec![Segment::new(
533                PlayNote {
534                    note: segment.element.hit.into(),
535                    velocity: segment.element.velocity,
536                },
537                segment.timing,
538            )])
539        })
540    }
541}
542
543/// Percussion key map defined according to
544/// [GM1 Sound Set](https://www.midi.org/specifications-old/item/gm-level-1-sound-set)
545#[derive(Debug, Hash, FromPrimitive, PartialEq, Clone, Copy)]
546#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
547#[allow(missing_docs)]
548pub enum DrumHitType {
549    AcousticBassDrum = 35,
550    BassDrum,
551    SideStick,
552    AcousticSnare,
553    HandClap,
554    ElectricSnare,
555    LowFloorTom,
556    ClosedHiHat,
557    HighFloorTom,
558    PedalHiHat,
559    LowTom,
560    OpenHiHat,
561    LowMidTom,
562    HighMidTom,
563    CrashCymbal1,
564    HighTom,
565    RideCymbal1,
566    ChineseCymbal,
567    RideBell,
568    Tambourine,
569    SplashCymbal,
570    Cowbell,
571    CrashCymbal2,
572    Vibraslap,
573    RideCymbal2,
574    HighBongo,
575    LowBongo,
576    MuteHighConga,
577    OpenHighConga,
578    LowConga,
579    HighTimbale,
580    LowTimbale,
581    HighAgogo,
582    LowAgogo,
583    Cabasa,
584    Maracas,
585    ShortWhistle,
586    LongWhistle,
587    ShortGuiro,
588    LongGuiro,
589    Claves,
590    HighWoodblock,
591    LowWoodblock,
592    MuteCuica,
593    OpenCuica,
594    MuteTriangle,
595    OpenTriangle,
596}
597
598impl From<u8> for DrumHitType {
599    fn from(value: u8) -> Self {
600        num::FromPrimitive::from_u8(value).unwrap()
601    }
602}
603
604impl From<DrumHitType> for u8 {
605    fn from(value: DrumHitType) -> Self {
606        value as u8
607    }
608}