Skip to main content

music21/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::System => vec!["System", "Stream", "StreamCore"],
47                StreamKind::Score => vec!["Score", "Stream", "StreamCore"],
48                StreamKind::Opus => vec!["Opus", "Stream", "StreamCore"],
49                StreamKind::Stream => vec!["Stream", "StreamCore"],
50            },
51            StreamElement::Clef(clef) => {
52                let kind = clef.kind();
53                let mut names = vec![kind.class_name()];
54                names.extend(kind.parents().iter().copied());
55                if !names.contains(&"Clef") {
56                    names.push("Clef");
57                }
58                names
59            }
60            StreamElement::Instrument(instrument) => {
61                // An instrument is of its own class and of every family
62                // above it: a flute is a `WoodwindInstrument`.
63                let mut names: Vec<&'static str> = Vec::new();
64                if let Some(class) = instrument.class_name() {
65                    names.push(class);
66                }
67                names.extend(instrument.families().iter().copied());
68                if !names.contains(&"Instrument") {
69                    names.push("Instrument");
70                }
71                names
72            }
73            StreamElement::KeySignature(_) => vec!["KeySignature"],
74            // music21's `Key` is a `DiatonicScale`, which is where
75            // everything it answers about degrees comes from.
76            StreamElement::Key(_) => vec![
77                "Key",
78                "KeySignature",
79                "DiatonicScale",
80                "ConcreteScale",
81                "Scale",
82            ],
83            StreamElement::TimeSignature(_) => vec!["TimeSignature", "TimeSignatureBase"],
84            StreamElement::MetronomeMark(_) => vec!["MetronomeMark", "TempoIndication"],
85            StreamElement::TempoText(_) => vec!["TempoText", "TempoIndication"],
86            StreamElement::MetricModulation(_) => vec!["MetricModulation", "TempoIndication"],
87            StreamElement::TextExpression(_) => vec!["TextExpression", "Expression"],
88            StreamElement::RepeatExpression(_) => vec!["RepeatExpression", "Expression"],
89            StreamElement::Dynamic(_) => vec!["Dynamic"],
90            // music21's `Repeat` is a `RepeatMark` and a `Barline`, in
91            // that order, where a plain barline is only itself.
92            StreamElement::Barline(barline) => {
93                if barline.repeat_direction().is_some() {
94                    vec!["Repeat", "RepeatMark", "Barline"]
95                } else {
96                    vec!["Barline"]
97                }
98            }
99            StreamElement::PedalObject(_) => vec!["PedalObject"],
100            StreamElement::RehearsalMark(_) => vec!["RehearsalMark"],
101            StreamElement::Break(_) => vec!["Break"],
102            StreamElement::Layout(layout) => vec![layout.class_name(), "LayoutBase"],
103            StreamElement::TextBox(_) => vec!["TextBox"],
104            StreamElement::Variant(_) => vec!["Variant"],
105            StreamElement::GlobalComment(_) => vec!["GlobalComment"],
106            StreamElement::MiscTandem(_) => vec!["MiscTandem"],
107            StreamElement::SpineComment(_) => vec!["SpineComment"],
108            StreamElement::BrailleSegmentDivision(division) => match division {
109                crate::braille::SegmentDivision::Required => {
110                    vec!["BrailleSegmentDivision", "BrailleTranscriptionHelper"]
111                }
112                crate::braille::SegmentDivision::Optional => vec![
113                    "BrailleOptionalSegmentDivision",
114                    "BrailleSegmentDivision",
115                    "BrailleTranscriptionHelper",
116                ],
117            },
118        };
119        names.push("Music21Object");
120        names
121    }
122
123    /// Whether the element is of a class, by music21's name for it:
124    /// music21's `isinstance` by class name.
125    ///
126    /// ```
127    /// use music21::{Note, StreamElement};
128    ///
129    /// let note: StreamElement = Note::from_name("C4")?.into();
130    /// assert!(note.is_instance("NotRest"));
131    /// assert!(note.is_instance("GeneralNote"));
132    /// assert!(!note.is_instance("Rest"));
133    /// # Ok::<(), music21::Error>(())
134    /// ```
135    pub fn is_instance(&self, class: &str) -> bool {
136        self.music21_classes().contains(&class)
137    }
138}