Skip to main content

music21_rs/stream/
classes.rs

1//! music21's class names for the elements of a stream: what music21's
2//! `classes` lists, the most particular first, for the questions that ask
3//! for elements by class.
4
5use super::{StreamElement, StreamKind};
6
7impl StreamElement {
8    /// music21's class names of the element, the most particular first,
9    /// ending with `Music21Object`.
10    pub fn music21_classes(&self) -> Vec<&'static str> {
11        let mut names: Vec<&'static str> = match self {
12            StreamElement::Note(_) => vec!["Note", "NotRest", "GeneralNote"],
13            StreamElement::Unpitched(_) => vec!["Unpitched", "NotRest", "GeneralNote"],
14            StreamElement::Chord(chord) if chord.numeral().is_some() => vec![
15                "RomanNumeral",
16                "Harmony",
17                "Chord",
18                "ChordBase",
19                "NotRest",
20                "GeneralNote",
21            ],
22            StreamElement::Chord(_) => vec!["Chord", "ChordBase", "NotRest", "GeneralNote"],
23            StreamElement::PercussionChord(_) => {
24                vec!["PercussionChord", "ChordBase", "NotRest", "GeneralNote"]
25            }
26            StreamElement::ChordSymbol(symbol) => {
27                let mut names = vec![
28                    "ChordSymbol",
29                    "Harmony",
30                    "Chord",
31                    "ChordBase",
32                    "NotRest",
33                    "GeneralNote",
34                ];
35                if symbol.is_no_chord() {
36                    names.insert(0, "NoChord");
37                }
38                names
39            }
40            StreamElement::Rest(_) => vec!["Rest", "GeneralNote"],
41            StreamElement::Stream(stream) => match stream.kind() {
42                StreamKind::Measure => vec!["Measure", "Stream", "StreamCore"],
43                StreamKind::Voice => vec!["Voice", "Stream", "StreamCore"],
44                StreamKind::Part => vec!["Part", "Stream", "StreamCore"],
45                StreamKind::PartStaff => vec!["PartStaff", "Part", "Stream", "StreamCore"],
46                StreamKind::Score => vec!["Score", "Stream", "StreamCore"],
47                StreamKind::Opus => vec!["Opus", "Stream", "StreamCore"],
48                StreamKind::Stream => vec!["Stream", "StreamCore"],
49            },
50            StreamElement::Clef(clef) => {
51                let kind = clef.kind();
52                let mut names = vec![kind.class_name()];
53                names.extend(kind.parents().iter().copied());
54                if !names.contains(&"Clef") {
55                    names.push("Clef");
56                }
57                names
58            }
59            StreamElement::Instrument(instrument) => {
60                // An instrument is of its own class and of every family
61                // above it: a flute is a `WoodwindInstrument`.
62                let mut names: Vec<&'static str> = Vec::new();
63                if let Some(class) = instrument.class_name() {
64                    names.push(class);
65                }
66                names.extend(instrument.families().iter().copied());
67                if !names.contains(&"Instrument") {
68                    names.push("Instrument");
69                }
70                names
71            }
72            StreamElement::KeySignature(_) => vec!["KeySignature"],
73            // music21's `Key` is a `DiatonicScale`, which is where
74            // everything it answers about degrees comes from.
75            StreamElement::Key(_) => vec![
76                "Key",
77                "KeySignature",
78                "DiatonicScale",
79                "ConcreteScale",
80                "Scale",
81            ],
82            StreamElement::TimeSignature(_) => vec!["TimeSignature", "TimeSignatureBase"],
83            StreamElement::MetronomeMark(_) => vec!["MetronomeMark", "TempoIndication"],
84            StreamElement::TempoText(_) => vec!["TempoText", "TempoIndication"],
85            StreamElement::MetricModulation(_) => vec!["MetricModulation", "TempoIndication"],
86            StreamElement::TextExpression(_) => vec!["TextExpression", "Expression"],
87            StreamElement::RepeatExpression(_) => vec!["RepeatExpression", "Expression"],
88            StreamElement::Dynamic(_) => vec!["Dynamic"],
89            // music21's `Repeat` is a `RepeatMark` and a `Barline`, in
90            // that order, where a plain barline is only itself.
91            StreamElement::Barline(barline) => {
92                if barline.repeat_direction().is_some() {
93                    vec!["Repeat", "RepeatMark", "Barline"]
94                } else {
95                    vec!["Barline"]
96                }
97            }
98            StreamElement::PedalObject(_) => vec!["PedalObject"],
99            StreamElement::RehearsalMark(_) => vec!["RehearsalMark"],
100            StreamElement::Break(_) => vec!["Break"],
101            StreamElement::Layout(layout) => vec![layout.class_name(), "LayoutBase"],
102            StreamElement::TextBox(_) => vec!["TextBox"],
103            StreamElement::Variant(_) => vec!["Variant"],
104        };
105        names.push("Music21Object");
106        names
107    }
108
109    /// Whether the element is of a class, by music21's name for it:
110    /// music21's `isinstance` by class name.
111    ///
112    /// ```
113    /// use music21_rs::{Note, StreamElement};
114    ///
115    /// let note: StreamElement = Note::from_name("C4")?.into();
116    /// assert!(note.is_instance("NotRest"));
117    /// assert!(note.is_instance("GeneralNote"));
118    /// assert!(!note.is_instance("Rest"));
119    /// # Ok::<(), music21_rs::Error>(())
120    /// ```
121    pub fn is_instance(&self, class: &str) -> bool {
122        self.music21_classes().contains(&class)
123    }
124}