Skip to main content

music21/
mei.rs

1//! MEI: music21's `mei.base`, which reads a score encoded by the Music
2//! Encoding Initiative's schema.
3//!
4//! An MEI score is measures, each holding a `<staff>` for every part and in
5//! it a `<layer>` for every voice; `<scoreDef>` and `<staffDef>` say the
6//! meter, key, clef and instrument. Slurs, ties, beams and tuplets may be
7//! written on the notes or apart from them, naming the notes they join by
8//! their `xml:id`.
9
10use std::collections::HashMap;
11
12use crate::articulations::{Articulation, ArticulationKind};
13use crate::bar::{Barline, BarlineType, RepeatDirection};
14use crate::chord::Chord;
15use crate::clef::{Clef, ClefKind};
16use crate::defaults::{FloatType, IntegerType};
17use crate::duration::{Duration, DurationType, Tuplet, TupletType};
18use crate::error::{Error, FormatErrorKind, Result};
19use crate::expressions::{Expression, Ornament, OrnamentKind};
20use crate::instrument::{Instrument, SearchLanguage};
21use crate::interval::Interval;
22use crate::key::{Key, KeySignature};
23use crate::makenotation::op_frac;
24use crate::metadata::Metadata;
25use crate::meter::TimeSignature;
26use crate::notation::{BeamType, Lyric, Syllabic, Tie, TieType};
27use crate::note::Note;
28use crate::pitch::{Accidental, Pitch, PitchOptions};
29use crate::rest::Rest;
30use crate::spanner::{Spanner, SpannerKind};
31use crate::stream::{Stream, StreamElement, StreamEvent, StreamKind};
32use crate::xml::Xml;
33
34fn mei_error(message: impl Into<String>) -> Error {
35    Error::mei(message.into())
36}
37
38/// A tag with any namespace prefix taken off.
39fn local(tag: &str) -> &str {
40    tag.rsplit(':').next().unwrap_or(tag)
41}
42
43fn children<'a>(element: &'a Xml, tag: &'a str) -> impl Iterator<Item = &'a Xml> {
44    element
45        .children
46        .iter()
47        .filter(move |child| local(&child.tag) == tag)
48}
49
50fn child<'a>(element: &'a Xml, tag: &str) -> Option<&'a Xml> {
51    element
52        .children
53        .iter()
54        .find(|child| local(&child.tag) == tag)
55}
56
57/// Every element under this one of a tag, in document order.
58fn descendants<'a>(element: &'a Xml, tag: &str, out: &mut Vec<&'a Xml>) {
59    for held in &element.children {
60        if local(&held.tag) == tag {
61            out.push(held);
62        }
63        descendants(held, tag, out);
64    }
65}
66
67/// A random version-4 UUID, as music21 names a slur written apart from its
68/// notes with `uuid4()`; `count` keeps two in one read apart.
69fn fresh_uuid(count: usize) -> String {
70    use std::hash::{BuildHasher, Hasher};
71
72    // std seeds each `RandomState` afresh, which is all the randomness
73    // a name needs.
74    let random = std::collections::hash_map::RandomState::new();
75    let mut halves = [0_u64; 2];
76    for (half, made) in halves.iter_mut().enumerate() {
77        let mut hasher = random.build_hasher();
78        hasher.write_usize(count);
79        hasher.write_usize(half);
80        *made = hasher.finish();
81    }
82    let high = (halves[0] & !0xF000) | 0x4000;
83    let low = (halves[1] & 0x3FFF_FFFF_FFFF_FFFF) | 0x8000_0000_0000_0000;
84    format!(
85        "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
86        high >> 32,
87        (high >> 16) & 0xFFFF,
88        high & 0xFFFF,
89        low >> 48,
90        low & 0xFFFF_FFFF_FFFF
91    )
92}
93
94fn without_hash(id: &str) -> &str {
95    id.strip_prefix('#').unwrap_or(id)
96}
97
98/// A tuplet a `<tupletSpan>` runs from one note to another, waiting for
99/// the layer to say which notes lie between.
100#[derive(Clone, Debug)]
101struct Search {
102    end: &'static str,
103    number: u32,
104    base: u32,
105}
106
107/// A thing a layer holds: an element, and what is known of it that the
108/// element itself cannot say.
109#[derive(Clone, Debug)]
110struct Thing {
111    element: StreamElement,
112    /// The number slurs know it by.
113    uid: usize,
114    search: Option<Search>,
115    /// A measure rest with no length of its own.
116    whole_measure: bool,
117}
118
119/// What a `<staffDef>` says: music21's dictionary of instrument, meter, key
120/// and clef, in that order.
121#[derive(Clone, Debug, Default)]
122struct StaffDef {
123    instrument: Option<Instrument>,
124    meter: Option<TimeSignature>,
125    key: Option<Key>,
126    clef: Option<Clef>,
127}
128
129impl StaffDef {
130    fn elements(&self) -> Vec<StreamElement> {
131        let mut out: Vec<StreamElement> = Vec::new();
132        if let Some(instrument) = &self.instrument {
133            out.push(instrument.clone().into());
134        }
135        if let Some(meter) = &self.meter {
136            out.push(meter.clone().into());
137        }
138        if let Some(key) = &self.key {
139            out.push(StreamElement::Key(key.clone()));
140        }
141        if let Some(clef) = &self.clef {
142            out.push(clef.clone().into());
143        }
144        out
145    }
146}
147
148/// A measure of one staff while it is put together.
149#[derive(Clone, Debug)]
150struct Measure {
151    number: IntegerType,
152    /// Each voice with its name and what it holds.
153    voices: Vec<(String, Vec<Thing>)>,
154    /// What stands at the start outside any voice, in the order inserted.
155    own: Vec<StreamElement>,
156    left: Option<Barline>,
157    right: Option<Barline>,
158    /// The length a measure rest fixed it at.
159    length: Option<FloatType>,
160}
161
162/// What a part holds in order: an instrument before its measures, then the
163/// measures.
164#[derive(Clone, Debug)]
165enum Held {
166    Instrument(Box<Instrument>),
167    Measure(Box<Measure>),
168}
169
170/// music21's `MeiToM21Converter`: the document, and what the elements that
171/// stand apart from the notes say of each note by its id.
172struct Reader {
173    /// For each `xml:id`, the attributes to be put on the element.
174    extra: HashMap<String, Vec<(&'static str, String)>>,
175    /// The slurs, each with the name it is known by and the notes it joins.
176    slurs: Vec<(String, Vec<usize>)>,
177    next_uid: usize,
178    next_slur: usize,
179}
180
181const DURATIONS: [(&str, FloatType); 14] = [
182    ("long", 16.0),
183    ("breve", 8.0),
184    ("1", 4.0),
185    ("2", 2.0),
186    ("4", 1.0),
187    ("8", 0.5),
188    ("16", 0.25),
189    ("32", 0.125),
190    ("64", 0.0625),
191    ("128", 0.03125),
192    ("256", 0.015625),
193    ("512", 0.0078125),
194    ("1024", 0.00390625),
195    ("2048", 0.001953125),
196];
197
198/// The length a `<mRest>` with no `dur` is given until its measure says
199/// how long it is.
200const NO_DURATION: FloatType = 0.00390625;
201
202fn accidental_of(attribute: Option<&str>) -> Result<Option<&'static str>> {
203    let Some(attribute) = attribute else {
204        return Ok(None);
205    };
206    Ok(Some(match attribute {
207        "s" | "ns" => "#",
208        "f" | "nf" => "-",
209        "ss" | "x" => "##",
210        "ff" => "--",
211        "xs" | "ts" => "###",
212        "tf" => "---",
213        "n" => "n",
214        "su" => "#~",
215        "sd" | "nu" => "~",
216        "fu" | "nd" => "`",
217        "fd" => "-`",
218        other => {
219            return Err(mei_error(format!(
220                "Unexpected value for \"accid\" attribute: {other}"
221            )));
222        }
223    }))
224}
225
226fn gestural_accidental_of(attribute: &str) -> Result<&'static str> {
227    Ok(match attribute {
228        "s" => "#",
229        "f" => "-",
230        "ss" => "##",
231        "ff" => "--",
232        "n" => "n",
233        "su" => "#~",
234        "sd" => "~",
235        "fu" => "`",
236        "fd" => "-`",
237        other => {
238            return Err(mei_error(format!(
239                "Unexpected value for \"accid.ges\" attribute: {other}"
240            )));
241        }
242    })
243}
244
245fn length_of(attribute: Option<&str>) -> Result<FloatType> {
246    let Some(attribute) = attribute else {
247        return Ok(NO_DURATION);
248    };
249    DURATIONS
250        .iter()
251        .find(|(name, _)| *name == attribute)
252        .map(|(_, length)| *length)
253        .ok_or_else(|| {
254            mei_error(format!(
255                "Unexpected value for \"dur\" attribute: {attribute}"
256            ))
257        })
258}
259
260/// music21's `makeDuration`: a length, then its dots.
261fn duration_of(base: FloatType, dots: u32) -> Result<Duration> {
262    let plain = Duration::new(base)?;
263    Ok(match plain.type_and_dots() {
264        Some((kind, _)) => Duration::from_type_with_dots(kind, dots),
265        None => plain,
266    })
267}
268
269fn dots_of(element: &Xml) -> Result<u32> {
270    match element.get("dots") {
271        None => Ok(0),
272        Some(dots) => dots
273            .parse()
274            .map_err(|_| mei_error(format!("the dots {dots:?} are no number"))),
275    }
276}
277
278/// music21's `_makeArticList`: the marks an `artic` attribute names.
279fn articulations_of(attribute: &str) -> Result<Vec<Articulation>> {
280    let mut marks = Vec::new();
281    for name in attribute.split(' ') {
282        let classes: &[&str] = match name {
283            "marc-stacc" => &["StrongAccent", "Staccato"],
284            "ten-stacc" => &["Tenuto", "Staccato"],
285            "acc" => &["Accent"],
286            "stacc" => &["Staccato"],
287            "ten" => &["Tenuto"],
288            "stacciss" => &["Staccatissimo"],
289            "marc" => &["StrongAccent"],
290            "spicc" => &["Spiccato"],
291            "doit" => &["Doit"],
292            "plop" => &["Plop"],
293            "fall" => &["Falloff"],
294            "dnbow" => &["DownBow"],
295            "upbow" => &["UpBow"],
296            "harm" => &["Harmonic"],
297            "snap" => &["SnapPizzicato"],
298            "stop" => &["Stopped"],
299            "open" => &["OpenString"],
300            "dbltongue" => &["DoubleTongue"],
301            "toe" => &["OrganToe"],
302            "trpltongue" => &["TripleTongue"],
303            "heel" => &["OrganHeel"],
304            "tap" | "lhpizz" | "dot" | "stroke" | "rip" | "bend" | "flip" | "smear"
305            | "fingernail" | "damp" | "dampall" => &["Articulation"],
306            other => {
307                return Err(mei_error(format!(
308                    "Unexpected value for \"artic\" attribute: {other}"
309                )));
310            }
311        };
312        for class in classes {
313            let kind = ArticulationKind::from_class_name(class)
314                .ok_or_else(|| mei_error(format!("no articulation called {class}")))?;
315            marks.push(Articulation::of_kind(kind));
316        }
317    }
318    Ok(marks)
319}
320
321/// music21's `_barlineFromAttr`: a barline, or the two a repeat both ways
322/// is, the one closing a measure and the one opening the next.
323fn barline_of(attribute: &str) -> Result<(Barline, Option<Barline>)> {
324    Ok(match attribute {
325        "rptboth" => (
326            Barline::repeat(RepeatDirection::End, Some(2)),
327            Some(Barline::repeat(RepeatDirection::Start, None)),
328        ),
329        "rptend" => (Barline::repeat(RepeatDirection::End, Some(2)), None),
330        other if other.starts_with("rpt") => (Barline::repeat(RepeatDirection::Start, None), None),
331        other => {
332            let kind = match other {
333                "dashed" => BarlineType::Dashed,
334                "dotted" => BarlineType::Dotted,
335                "dbl" => BarlineType::Double,
336                "end" => BarlineType::Final,
337                "invis" => BarlineType::None,
338                "single" => BarlineType::Regular,
339                other => {
340                    return Err(mei_error(format!(
341                        "Unexpected value for \"right\" attribute: {other}"
342                    )));
343                }
344            };
345            (Barline::new(kind), None)
346        }
347    })
348}
349
350fn tie_of(attribute: &str) -> Tie {
351    let has = |mark: char| attribute.contains(mark);
352    Tie::new(if has('m') || (has('t') && has('i')) {
353        TieType::Continue
354    } else if has('i') {
355        TieType::Start
356    } else {
357        TieType::Stop
358    })
359}
360
361fn meter_of(element: &Xml) -> Result<TimeSignature> {
362    TimeSignature::from_ratio_string(&format!(
363        "{}/{}",
364        element.get("meter.count").unwrap_or("None"),
365        element.get("meter.unit").unwrap_or("None")
366    ))
367}
368
369/// music21's `_keySigFromAttrs`: a key named by its tonic, or by how many
370/// sharps or flats it is written with.
371fn key_of(element: &Xml) -> Result<Key> {
372    if let Some(step) = element.get("key.pname") {
373        let tonic = format!(
374            "{step}{}",
375            accidental_of(element.get("key.accid"))?.unwrap_or("")
376        );
377        return Key::from_tonic_mode(
378            &tonic,
379            element.get("key.mode").filter(|mode| !mode.is_empty()),
380        );
381    }
382    let signature = element.get("key.sig").unwrap_or("0");
383    let count = || -> Result<IntegerType> {
384        signature
385            .get(..1)
386            .unwrap_or_default()
387            .parse()
388            .map_err(|_| mei_error(format!("the key signature {signature:?} has no number")))
389    };
390    let sharps = if signature.starts_with('0') {
391        0
392    } else if signature.ends_with('s') {
393        count()?
394    } else {
395        -count()?
396    };
397    Ok(KeySignature::new(sharps).as_key(element.get("key.mode").unwrap_or("major")))
398}
399
400/// music21's `_transpositionFromAttrs`: the interval an instrument sounds
401/// away from where it is written.
402fn transposition_of(element: &Xml) -> Result<Interval> {
403    let read = |name: &str| -> Result<IntegerType> {
404        match element.get(name) {
405            None => Ok(0),
406            Some(text) => text
407                .parse()
408                .map_err(|_| mei_error(format!("{name} is no number: {text:?}"))),
409        }
410    };
411    // Reckoned in i64, where the least i32 has a positive.
412    let mut diatonic = i64::from(read("trans.diat")?);
413    let semitones = read("trans.semi")?;
414    let wide = i64::from(semitones);
415    // A transposition of more than an octave written with its steps inside
416    // one has the octaves put back.
417    if (wide - diatonic).abs() > 5 * (wide.abs() / 12 + 1) {
418        if wide < 0 {
419            diatonic -= 7 * (wide.abs() / 12);
420        } else if wide > 0 {
421            diatonic += 7 * (wide.abs() / 12);
422        }
423    }
424    diatonic += diatonic.signum();
425    let diatonic = IntegerType::try_from(diatonic)
426        .map_err(|_| mei_error(format!("a transposition of {diatonic} steps is too far")))?;
427    Interval::from_generic_and_chromatic(diatonic, semitones)
428}
429
430fn clef_of(
431    shape: Option<&str>,
432    line: Option<&str>,
433    displaced: Option<&str>,
434    place: Option<&str>,
435) -> Result<Clef> {
436    match shape {
437        Some("perc") => Ok(Clef::of_kind(ClefKind::PercussionClef)),
438        Some("TAB") => Ok(Clef::of_kind(ClefKind::TabClef)),
439        _ => {
440            let octaves = match displaced {
441                None => 0,
442                Some("8") => 1,
443                Some("15") => 2,
444                Some("22") => 3,
445                Some(other) => {
446                    return Err(mei_error(format!("a clef displaced by {other}")));
447                }
448            };
449            let shift = if place == Some("below") {
450                -octaves
451            } else {
452                octaves
453            };
454            let (Some(shape), Some(line)) = (shape, line) else {
455                return Err(mei_error("a clef with no shape or no line"));
456            };
457            Clef::from_string(&format!("{shape}{line}"), shift)
458        }
459    }
460}
461
462fn clef_element(element: &Xml) -> Result<Clef> {
463    clef_of(
464        element.get("shape"),
465        element.get("line"),
466        element.get("dis"),
467        element.get("dis.place"),
468    )
469}
470
471/// Whether a length is written with a flag, and so may be beamed.
472fn is_beamable(duration: &Duration) -> Option<DurationType> {
473    match duration.components().as_slice() {
474        [(kind, _)] if kind.quarter_length() < 1.0 => Some(*kind),
475        _ => None,
476    }
477}
478
479fn with_duration(element: &mut StreamElement, change: impl FnOnce(&mut Duration)) {
480    let Some(mut duration) = element.duration().cloned() else {
481        return;
482    };
483    change(&mut duration);
484    match element {
485        StreamElement::Note(note) => note.set_duration(duration),
486        StreamElement::Chord(chord) => chord.set_duration(duration),
487        StreamElement::Rest(rest) => rest.set_duration(duration),
488        _ => {}
489    }
490}
491
492fn is_sounding(element: &StreamElement) -> bool {
493    matches!(
494        element,
495        StreamElement::Note(_) | StreamElement::Chord(_) | StreamElement::Rest(_)
496    )
497}
498
499fn mark_first_tuplet(element: &mut StreamElement, kind: TupletType) {
500    with_duration(element, |duration| {
501        let mut tuplets = duration.tuplets();
502        if let Some(first) = tuplets.first_mut() {
503            first.set_tuplet_type(Some(kind));
504        }
505        duration.set_tuplets(tuplets);
506    });
507}
508
509/// music21's `scaleToTuplet` for a tuplet whose numbers are known: so many
510/// notes in the time of so many, of the value the note is written in.
511fn scale_to_tuplet(element: &mut StreamElement, number: u32, base: u32) {
512    if !is_sounding(element) {
513        return;
514    }
515    with_duration(element, |duration| {
516        let kind = match duration.components().as_slice() {
517            [(kind, _)] => *kind,
518            _ => DurationType::Quarter,
519        };
520        duration.append_tuplet(Tuplet::new(number, base, kind, 0));
521    });
522}
523
524/// music21's `beamTogether`: the first thing that can carry a beam starts
525/// it, those after carry it on, and the last ends it.
526fn beam_together(things: &mut [Thing]) -> Result<()> {
527    let mut last: Option<usize> = None;
528    for (index, thing) in things.iter_mut().enumerate() {
529        let (beams, duration) = match &thing.element {
530            StreamElement::Note(note) => (note.beams().clone(), note.duration().cloned()),
531            StreamElement::Chord(chord) => (chord.beams().clone(), chord.duration().cloned()),
532            _ => continue,
533        };
534        let Some(kind) = duration.as_ref().and_then(is_beamable) else {
535            continue;
536        };
537        if !beams.is_empty() {
538            continue;
539        }
540        let mut filled = beams;
541        filled.fill(
542            kind,
543            Some(if last.is_none() {
544                BeamType::Start
545            } else {
546                BeamType::Continue
547            }),
548        )?;
549        match &mut thing.element {
550            StreamElement::Note(note) => note.set_beams(filled),
551            StreamElement::Chord(chord) => chord.set_beams(filled),
552            _ => {}
553        }
554        last = Some(index);
555    }
556    // Where nothing was beamed music21 reaches for the last thing of all.
557    let closing = last.or(things.len().checked_sub(1));
558    if let Some(thing) = closing.and_then(|index| things.get_mut(index)) {
559        match &mut thing.element {
560            StreamElement::Note(note) => {
561                let mut beams = note.beams().clone();
562                beams.set_all(BeamType::Stop, None);
563                note.set_beams(beams);
564            }
565            StreamElement::Chord(chord) => {
566                let mut beams = chord.beams().clone();
567                beams.set_all(BeamType::Stop, None);
568                chord.set_beams(beams);
569            }
570            _ => {}
571        }
572    }
573    Ok(())
574}
575
576impl Reader {
577    /// An attribute as music21 reads it once the spanning elements have
578    /// written theirs onto the notes: what the element says, then what was
579    /// said of it.
580    fn attribute(&self, element: &Xml, name: &str) -> Option<String> {
581        let added = element
582            .get("xml:id")
583            .and_then(|id| self.extra.get(id))
584            .and_then(|extra| {
585                extra
586                    .iter()
587                    .find(|(held, _)| *held == name)
588                    .map(|(_, value)| value.clone())
589            });
590        match (element.get(name), added) {
591            (Some(own), Some(added)) => Some(format!("{own}{added}")),
592            (Some(own), None) => Some(own.to_string()),
593            (None, added) => added,
594        }
595    }
596
597    fn set(&mut self, id: &str, name: &'static str, value: String) {
598        let extra = self.extra.entry(without_hash(id).to_string()).or_default();
599        match extra.iter_mut().find(|(held, _)| *held == name) {
600            Some((_, held)) => *held = value,
601            None => extra.push((name, value)),
602        }
603    }
604
605    /// music21's `_ppSlurs`, `_ppTies`, `_ppBeams` and `_ppTuplets`: what
606    /// the spanning elements of the score say, written against the ids of
607    /// the notes they name.
608    fn preprocess(&mut self, score: &Xml) {
609        let mut found = Vec::new();
610        descendants(score, "slur", &mut found);
611        for slur in std::mem::take(&mut found) {
612            if let (Some(start), Some(end)) = (slur.get("startid"), slur.get("endid")) {
613                let name = fresh_uuid(self.next_slur);
614                self.next_slur += 1;
615                self.slurs.push((name.clone(), Vec::new()));
616                self.set(start, "m21SlurStart", name.clone());
617                self.set(end, "m21SlurEnd", name);
618            }
619        }
620        descendants(score, "tie", &mut found);
621        for tie in std::mem::take(&mut found) {
622            if let (Some(start), Some(end)) = (tie.get("startid"), tie.get("endid")) {
623                self.set(start, "tie", "i".to_string());
624                self.set(end, "tie", "t".to_string());
625            }
626        }
627        descendants(score, "beamSpan", &mut found);
628        for beam in std::mem::take(&mut found) {
629            let (Some(start), Some(end)) = (beam.get("startid"), beam.get("endid")) else {
630                continue;
631            };
632            self.set(start, "m21Beam", "start".to_string());
633            self.set(end, "m21Beam", "stop".to_string());
634            for id in beam.get("plist").unwrap_or("").split(' ') {
635                let id = without_hash(id);
636                let has = self
637                    .extra
638                    .get(id)
639                    .is_some_and(|extra| extra.iter().any(|(name, _)| *name == "m21Beam"));
640                if !has {
641                    self.set(id, "m21Beam", "continue".to_string());
642                }
643            }
644        }
645        descendants(score, "tupletSpan", &mut found);
646        for tuplet in found {
647            let number = tuplet.get("num").unwrap_or("None").to_string();
648            let base = tuplet.get("numbase").unwrap_or("None").to_string();
649            if let Some(list) = tuplet.get("plist") {
650                for id in list.split(' ') {
651                    if !without_hash(id).is_empty() {
652                        self.set(id, "m21TupletNum", number.clone());
653                        self.set(id, "m21TupletNumbase", base.clone());
654                    }
655                }
656            } else if let (Some(start), Some(end)) = (tuplet.get("startid"), tuplet.get("endid")) {
657                for (id, which) in [(start, "start"), (end, "end")] {
658                    self.set(id, "m21TupletSearch", which.to_string());
659                    self.set(id, "m21TupletNum", number.clone());
660                    self.set(id, "m21TupletNumbase", base.clone());
661                }
662            }
663        }
664    }
665
666    fn uid(&mut self) -> usize {
667        self.next_uid += 1;
668        self.next_uid - 1
669    }
670
671    /// music21's `addSlurs`: the slurs an element starts or ends.
672    fn add_slurs(&mut self, element: &Xml, uid: usize) -> Result<()> {
673        let join = |slurs: &mut Vec<(String, Vec<usize>)>, name: &str| {
674            if let Some((_, held)) = slurs.iter_mut().find(|(held, _)| held == name) {
675                held.push(uid);
676            }
677        };
678        if let Some(name) = self.attribute(element, "m21SlurStart") {
679            join(&mut self.slurs, &name);
680        }
681        if let Some(name) = self.attribute(element, "m21SlurEnd") {
682            join(&mut self.slurs, &name);
683        }
684        if let Some(slurs) = element.get("slur") {
685            for slur in slurs.split(' ') {
686                let chars: Vec<char> = slur.chars().collect();
687                let [number, kind] = chars.as_slice() else {
688                    return Err(mei_error(format!("cannot read the slur {slur:?}")));
689                };
690                let name = number.to_string();
691                match kind {
692                    'i' => self.slurs.push((name, vec![uid])),
693                    't' => join(&mut self.slurs, &name),
694                    _ => {}
695                }
696            }
697        }
698        Ok(())
699    }
700
701    /// What the tuplet numbers written against an element do to it:
702    /// music21's `scaleToTuplet`.
703    fn tuplet(&self, element: &Xml, thing: &mut Thing) -> Result<()> {
704        let Some(number) = self.attribute(element, "m21TupletNum") else {
705            return Ok(());
706        };
707        let base = self
708            .attribute(element, "m21TupletNumbase")
709            .unwrap_or_default();
710        let read = |text: &str| -> Result<u32> {
711            text.parse()
712                .map_err(|_| mei_error(format!("a tuplet of {text:?} notes")))
713        };
714        let (number, base) = (read(&number)?, read(&base)?);
715        match self.attribute(element, "m21TupletSearch").as_deref() {
716            Some(end) => {
717                thing.search = Some(Search {
718                    end: if end.contains("start") {
719                        "start"
720                    } else {
721                        "end"
722                    },
723                    number,
724                    base,
725                });
726            }
727            None => {
728                scale_to_tuplet(&mut thing.element, number, base);
729                if let Some(written) = element.get("tuplet") {
730                    if written.starts_with('i') {
731                        mark_first_tuplet(&mut thing.element, TupletType::Start);
732                    } else if written.starts_with('t') {
733                        mark_first_tuplet(&mut thing.element, TupletType::Stop);
734                    }
735                }
736            }
737        }
738        Ok(())
739    }
740
741    /// music21's `noteFromElement`. The second answer is the number slurs
742    /// know the note by.
743    fn note(&mut self, element: &Xml) -> Result<(Note, usize)> {
744        let name = element.get("pname").unwrap_or("");
745        let mut pitch = if name.is_empty() {
746            Pitch::from_name("C4")?
747        } else {
748            let step = name
749                .chars()
750                .next()
751                .map(|c| c.to_ascii_uppercase())
752                .ok_or_else(|| mei_error("a note with no name"))?;
753            let mut options = PitchOptions::new().step(step);
754            if let Some(octave) = element.get("oct").filter(|octave| !octave.is_empty()) {
755                options = options.octave(
756                    octave
757                        .parse()
758                        .map_err(|_| mei_error(format!("the octave {octave:?} is no number")))?,
759                );
760            }
761            options.build()?
762        };
763        if let Some(accidental) = accidental_of(element.get("accid"))? {
764            pitch.set_written_accidental(Some(Accidental::new(accidental)?));
765        }
766        let length = length_of(element.get("dur"))?;
767        let mut note =
768            Note::from_pitch(pitch).with_duration(duration_of(length, dots_of(element)?)?);
769
770        let mut dot_elements = 0;
771        for held in &element.children {
772            match local(&held.tag) {
773                "dot" => dot_elements += 1,
774                "artic" => {
775                    if let Some(marks) = held.get("artic") {
776                        note.articulations_mut().extend(articulations_of(marks)?);
777                    }
778                }
779                "accid" => {
780                    let accidental = match held.get("accid.ges") {
781                        Some(gestural) => Some(gestural_accidental_of(gestural)?),
782                        None => accidental_of(held.get("accid"))?,
783                    };
784                    if let Some(accidental) = accidental {
785                        let mut pitch = note.pitch().clone();
786                        pitch.set_written_accidental(Some(Accidental::new(accidental)?));
787                        note.set_pitch(pitch);
788                    }
789                }
790                "syl" => *note.lyrics_mut() = vec![syllable_of(held)?],
791                _ => {}
792            }
793        }
794        if let Some(gestural) = element.get("accid.ges") {
795            let mut pitch = note.pitch().clone();
796            pitch.set_written_accidental(Some(Accidental::new(gestural_accidental_of(gestural)?)?));
797            note.set_pitch(pitch);
798        }
799        let uid = self.uid();
800        self.add_slurs(element, uid)?;
801        if let Some(id) = element.get("xml:id") {
802            note.set_id(Some(id.to_string()));
803        }
804        if let Some(marks) = element.get("artic") {
805            note.articulations_mut().extend(articulations_of(marks)?);
806        }
807        if let Some(tie) = self.attribute(element, "tie") {
808            note.set_tie(Some(tie_of(&tie)));
809        }
810        if dot_elements > 0 {
811            note.set_duration(duration_of(length, dot_elements)?);
812        }
813        if element.get("grace").is_some() {
814            let mut grace = note
815                .duration()
816                .map(Duration::grace_duration)
817                .unwrap_or_default();
818            // music21's `GraceDuration(quarterLength)`, read off a length.
819            grace.set_expression_is_inferred(true);
820            note.set_duration(grace);
821        }
822        if let Some(beam) = self.attribute(element, "m21Beam")
823            && let Some(kind) = note.duration().and_then(is_beamable)
824        {
825            let mut beams = note.beams().clone();
826            beams.fill(kind, Some(beam_type_of(&beam)?))?;
827            note.set_beams(beams);
828        }
829        let verses: Vec<&Xml> = children(element, "verse").collect();
830        if !verses.is_empty() {
831            let mut lyrics = Vec::new();
832            for (index, verse) in verses.iter().enumerate() {
833                let number = match verse.get("n") {
834                    Some(number) => number.parse::<IntegerType>().ok(),
835                    None => Some(index as IntegerType + 1),
836                };
837                for syllable in children(verse, "syl") {
838                    let mut lyric = syllable_of(syllable)?;
839                    if let Some(number) = number {
840                        lyric.set_number(number);
841                    }
842                    lyrics.push(lyric);
843                }
844            }
845            *note.lyrics_mut() = lyrics;
846        }
847        Ok((note, uid))
848    }
849
850    fn note_thing(&mut self, element: &Xml) -> Result<Thing> {
851        let (note, uid) = self.note(element)?;
852        let mut thing = Thing {
853            element: note.into(),
854            uid,
855            search: None,
856            whole_measure: false,
857        };
858        self.tuplet(element, &mut thing)?;
859        Ok(thing)
860    }
861
862    /// music21's `chordFromElement`.
863    fn chord(&mut self, element: &Xml) -> Result<Thing> {
864        let mut notes = Vec::new();
865        for held in children(element, "note") {
866            // A note of a chord takes its own tuplet, as music21 gives it.
867            let thing = self.note_thing(held)?;
868            if let StreamElement::Note(note) = thing.element {
869                notes.push(note);
870            }
871        }
872        let mut chord = Chord::new(notes)?.with_duration(duration_of(
873            length_of(element.get("dur"))?,
874            dots_of(element)?,
875        )?);
876        for held in children(element, "artic") {
877            if let Some(marks) = held.get("artic") {
878                chord.articulations_mut().extend(articulations_of(marks)?);
879            }
880        }
881        let uid = self.uid();
882        self.add_slurs(element, uid)?;
883        if let Some(id) = element.get("xml:id") {
884            chord.set_id(Some(id.to_string()));
885        }
886        if let Some(marks) = element.get("artic") {
887            chord.articulations_mut().extend(articulations_of(marks)?);
888        }
889        if let Some(tie) = self.attribute(element, "tie") {
890            chord.set_tie(Some(tie_of(&tie)));
891        }
892        if element.get("grace").is_some() {
893            let mut grace = chord
894                .duration()
895                .map(Duration::grace_duration)
896                .unwrap_or_default();
897            // music21's `GraceDuration(quarterLength)`, read off a length.
898            grace.set_expression_is_inferred(true);
899            chord.set_duration(grace);
900        }
901        if let Some(beam) = self.attribute(element, "m21Beam")
902            && let Some(kind) = chord.duration().and_then(is_beamable)
903        {
904            let mut beams = chord.beams().clone();
905            beams.fill(kind, Some(beam_type_of(&beam)?))?;
906            chord.set_beams(beams);
907        }
908        let mut thing = Thing {
909            element: chord.into(),
910            uid,
911            search: None,
912            whole_measure: false,
913        };
914        self.tuplet(element, &mut thing)?;
915        Ok(thing)
916    }
917
918    /// music21's `restFromElement` and `spaceFromElement`: a rest, hidden
919    /// where it is only space.
920    fn rest(&mut self, element: &Xml, hidden: bool, whole_measure: bool) -> Result<Thing> {
921        let mut rest = Rest::new(duration_of(
922            length_of(element.get("dur"))?,
923            dots_of(element)?,
924        )?);
925        rest.set_hidden(hidden);
926        if let Some(id) = element.get("xml:id") {
927            rest.set_id(Some(id.to_string()));
928        }
929        let mut thing = Thing {
930            element: rest.into(),
931            uid: self.uid(),
932            search: None,
933            whole_measure: whole_measure && element.get("dur").is_none(),
934        };
935        self.tuplet(element, &mut thing)?;
936        Ok(thing)
937    }
938
939    /// What a layer, a beam or a tuplet holds, in order.
940    fn contents(&mut self, element: &Xml, in_layer: bool) -> Result<Vec<Thing>> {
941        let mut things = Vec::new();
942        for held in &element.children {
943            match local(&held.tag) {
944                "clef" => things.push(Thing {
945                    element: clef_element(held)?.into(),
946                    uid: self.uid(),
947                    search: None,
948                    whole_measure: false,
949                }),
950                "chord" => things.push(self.chord(held)?),
951                "note" => things.push(self.note_thing(held)?),
952                "rest" => things.push(self.rest(held, false, false)?),
953                "mRest" if in_layer => things.push(self.rest(held, false, true)?),
954                "space" => things.push(self.rest(held, true, false)?),
955                "mSpace" if in_layer => things.push(self.rest(held, true, true)?),
956                "beam" => {
957                    let mut beamed = self.contents(held, false)?;
958                    beam_together(&mut beamed)?;
959                    things.extend(beamed);
960                }
961                "tuplet" => things.extend(self.tuplet_element(held)?),
962                "bTrem" => things.extend(self.tremolo(held)?),
963                // A barline inside a layer is checked and then has nowhere
964                // to stand.
965                "barLine" => {
966                    let _ = barline_of(held.get("rend").unwrap_or("single"))?;
967                }
968                _ => {}
969            }
970        }
971        Ok(things)
972    }
973
974    /// music21's `tupletFromElement`.
975    fn tuplet_element(&mut self, element: &Xml) -> Result<Vec<Thing>> {
976        let (Some(number), Some(base)) = (element.get("num"), element.get("numbase")) else {
977            return Err(mei_error(
978                "Both @num and @numbase attributes are required on <tuplet> tags.",
979            ));
980        };
981        let read = |text: &str| -> Result<u32> {
982            text.parse()
983                .map_err(|_| mei_error(format!("a tuplet of {text:?} notes")))
984        };
985        let (number, base) = (read(number)?, read(base)?);
986        let mut members = self.contents(element, false)?;
987        for member in &mut members {
988            scale_to_tuplet(&mut member.element, number, base);
989        }
990        let sounding: Vec<usize> = (0..members.len())
991            .filter(|index| is_sounding(&members[*index].element))
992            .collect();
993        let first = *sounding
994            .first()
995            .ok_or_else(|| mei_error("a tuplet with no notes in it"))?;
996        mark_first_tuplet(&mut members[first].element, TupletType::Start);
997        let last = sounding.last().copied().filter(|last| *last != first);
998        mark_first_tuplet(
999            &mut members[last.unwrap_or(first)].element,
1000            TupletType::Stop,
1001        );
1002        beam_together(&mut members)?;
1003        Ok(members)
1004    }
1005
1006    /// music21's `bTremFromElement`: notes played as repeated strokes.
1007    fn tremolo(&mut self, element: &Xml) -> Result<Vec<Thing>> {
1008        let mut things = Vec::new();
1009        for held in &element.children {
1010            match local(&held.tag) {
1011                "chord" => things.push(self.chord(held)?),
1012                "note" => things.push(self.note_thing(held)?),
1013                _ => {}
1014            }
1015        }
1016        let marks = match element.get("unitdur") {
1017            Some("8") => Some(1),
1018            Some("16") => Some(2),
1019            Some("32") => Some(3),
1020            Some("64") => Some(4),
1021            Some("128") => Some(5),
1022            Some("256") => Some(6),
1023            Some("512") => Some(7),
1024            Some("1024") => Some(8),
1025            _ => None,
1026        };
1027        if let Some(marks) = marks {
1028            for thing in &mut things {
1029                let mut tremolo = Ornament::of_kind(OrnamentKind::Tremolo);
1030                tremolo.set_number_of_marks(marks)?;
1031                let expression = Expression::from(tremolo);
1032                match &mut thing.element {
1033                    StreamElement::Note(note) => note.expressions_mut().push(expression),
1034                    StreamElement::Chord(chord) => chord.expressions_mut().push(expression),
1035                    _ => {}
1036                }
1037            }
1038        }
1039        Ok(things)
1040    }
1041
1042    /// music21's `layerFromElement`, with `_guessTuplets`: the notes between
1043    /// the two a tuplet span names are in the tuplet too.
1044    fn layer(&mut self, element: &Xml) -> Result<Vec<Thing>> {
1045        let mut things = self.contents(element, true)?;
1046        let mut active: Option<(u32, u32)> = None;
1047        for thing in &mut things {
1048            if !is_sounding(&thing.element) {
1049                continue;
1050            }
1051            let search = thing.search.take();
1052            if let Some(search) = &search
1053                && search.end == "start"
1054            {
1055                active = Some((search.number, search.base));
1056            }
1057            if let Some((number, base)) = active {
1058                scale_to_tuplet(&mut thing.element, number, base);
1059                if search.is_some_and(|search| search.end == "end") {
1060                    mark_first_tuplet(&mut thing.element, TupletType::Stop);
1061                    active = None;
1062                }
1063            }
1064        }
1065        Ok(things)
1066    }
1067
1068    /// music21's `staffDefFromElement`.
1069    fn staff_def(&mut self, element: &Xml) -> Result<StaffDef> {
1070        let instrument = match child(element, "instrDef") {
1071            Some(definition) => Some(match definition.get("midi.instrnum") {
1072                Some(number) => Instrument::from_midi_program(number.parse().map_err(|_| {
1073                    mei_error(format!("the MIDI program {number:?} is no number"))
1074                })?)?,
1075                None => {
1076                    let name = definition.get("midi.instrname");
1077                    name.and_then(|name| Instrument::from_name(name, SearchLanguage::All).ok())
1078                        .unwrap_or_else(|| {
1079                            let mut generic = Instrument::new();
1080                            generic.set_part_name(Some(name.unwrap_or("").to_string()));
1081                            generic
1082                        })
1083                }
1084            }),
1085            None => {
1086                Instrument::from_name(element.get("label").unwrap_or(""), SearchLanguage::All).ok()
1087            }
1088        };
1089        let mut found = StaffDef {
1090            instrument,
1091            ..StaffDef::default()
1092        };
1093        if let Some(instrument) = &mut found.instrument {
1094            instrument.set_part_name(element.get("label").map(str::to_string));
1095            instrument.set_part_abbreviation(element.get("label.abbr").map(str::to_string));
1096            instrument.set_part_id(element.get("n").map(str::to_string));
1097        }
1098        if element.get("trans.semi").is_some() {
1099            found
1100                .instrument
1101                .get_or_insert_with(Instrument::new)
1102                .set_transposition(Some(transposition_of(element)?));
1103        }
1104        if element.get("meter.count").is_some() {
1105            found.meter = Some(meter_of(element)?);
1106        }
1107        if element.get("key.pname").is_some() || element.get("key.sig").is_some() {
1108            found.key = Some(key_of(element)?);
1109        }
1110        if element.get("clef.shape").is_some() {
1111            found.clef = Some(clef_of(
1112                element.get("clef.shape"),
1113                element.get("clef.line"),
1114                element.get("clef.dis"),
1115                element.get("clef.dis.place"),
1116            )?);
1117        }
1118        for held in children(element, "clef") {
1119            found.clef = Some(clef_element(held)?);
1120        }
1121        Ok(found)
1122    }
1123
1124    /// music21's `measureFromElement`: a measure of every part.
1125    fn measure(
1126        &mut self,
1127        element: &Xml,
1128        backup: IntegerType,
1129        parts: &[String],
1130        meter: Option<&TimeSignature>,
1131    ) -> Result<(HashMap<String, Measure>, Option<Barline>)> {
1132        let number = match element.get("n") {
1133            Some(number) => number
1134                .parse()
1135                .map_err(|_| mei_error(format!("the measure number {number:?} is no number")))?,
1136            None => backup,
1137        };
1138        let mut staves: HashMap<String, Measure> = HashMap::new();
1139        let mut waiting: Vec<(String, StaffDef)> = Vec::new();
1140        let mut longest: Option<FloatType> = None;
1141        for held in &element.children {
1142            match local(&held.tag) {
1143                "staff" => {
1144                    let mut voices = Vec::new();
1145                    for (count, layer) in children(held, "layer").enumerate() {
1146                        voices.push(((count + 1).to_string(), self.layer(layer)?));
1147                    }
1148                    let length = voices
1149                        .iter()
1150                        .map(|(_, things)| {
1151                            things
1152                                .iter()
1153                                .map(|thing| thing.element.quarter_length())
1154                                .sum::<FloatType>()
1155                        })
1156                        .fold(0.0, FloatType::max);
1157                    longest = Some(longest.map_or(length, |held| held.max(length)));
1158                    staves.insert(
1159                        held.get("n").unwrap_or("").to_string(),
1160                        Measure {
1161                            number,
1162                            voices,
1163                            own: Vec::new(),
1164                            left: None,
1165                            right: None,
1166                            length: None,
1167                        },
1168                    );
1169                }
1170                "staffDef" => {
1171                    if let Some(name) = held.get("n") {
1172                        waiting.push((name.to_string(), self.staff_def(held)?));
1173                    }
1174                }
1175                _ => {}
1176            }
1177        }
1178        for (name, definition) in waiting {
1179            let measure = staves.get_mut(&name).ok_or_else(|| {
1180                mei_error(format!("a <staffDef> for staff {name}, which is not here"))
1181            })?;
1182            measure.own.extend(definition.elements());
1183        }
1184        // A part with nothing written for this measure rests through it.
1185        for name in parts {
1186            if !staves.contains_key(name) {
1187                let length = longest.ok_or_else(|| mei_error("a measure with no staff in it"))?;
1188                staves.insert(
1189                    name.clone(),
1190                    Measure {
1191                        number,
1192                        voices: vec![(
1193                            "1".to_string(),
1194                            vec![Thing {
1195                                element: Rest::new(Duration::new(length)?).into(),
1196                                uid: self.uid(),
1197                                search: None,
1198                                whole_measure: true,
1199                            }],
1200                        )],
1201                        own: Vec::new(),
1202                        left: None,
1203                        right: None,
1204                        length: None,
1205                    },
1206                );
1207            }
1208        }
1209        // A measure rest lasts as long as the longest staff, or the bar
1210        // where no staff says.
1211        let target = match (longest, meter) {
1212            (Some(longest), Some(meter))
1213                if longest == NO_DURATION && longest != meter.bar_quarter_length() =>
1214            {
1215                Some(meter.bar_quarter_length())
1216            }
1217            (longest, _) => longest,
1218        };
1219        if let Some(target) = target {
1220            for measure in staves.values_mut() {
1221                for (_, things) in &mut measure.voices {
1222                    for thing in things {
1223                        if std::mem::take(&mut thing.whole_measure) {
1224                            let duration = Duration::new(target)?;
1225                            with_duration(&mut thing.element, |held| *held = duration);
1226                            measure.length = Some(target);
1227                        }
1228                    }
1229                }
1230            }
1231        }
1232        let mut next_left = None;
1233        if let Some(left) = element.get("left") {
1234            let (first, second) = barline_of(left)?;
1235            let barline = second.unwrap_or(first);
1236            for measure in staves.values_mut() {
1237                measure.left = Some(barline.clone());
1238            }
1239        }
1240        if let Some(right) = element.get("right") {
1241            let (barline, next) = barline_of(right)?;
1242            next_left = next;
1243            for measure in staves.values_mut() {
1244                measure.right = Some(barline.clone());
1245            }
1246        }
1247        Ok((staves, next_left))
1248    }
1249
1250    /// music21's `sectionScoreCore`: what a `<score>` or a `<section>`
1251    /// holds, part by part.
1252    fn section(
1253        &mut self,
1254        element: &Xml,
1255        parts: &[String],
1256        state: &mut SectionState,
1257    ) -> Result<HashMap<String, Vec<Held>>> {
1258        let in_section = local(&element.tag) == "section";
1259        let mut parsed: HashMap<String, Vec<Held>> = parts
1260            .iter()
1261            .map(|name| (name.clone(), Vec::new()))
1262            .collect();
1263        let mut next: HashMap<String, Vec<StreamElement>> = parts
1264            .iter()
1265            .map(|name| (name.clone(), Vec::new()))
1266            .collect();
1267        for held in &element.children {
1268            match local(&held.tag) {
1269                "measure" if in_section => {
1270                    state.backup += 1;
1271                    let (mut staves, next_left) =
1272                        self.measure(held, state.backup, parts, state.meter.as_ref())?;
1273                    for name in parts {
1274                        let measure = staves
1275                            .get_mut(name)
1276                            .ok_or_else(|| mei_error(format!("no staff {name} in a measure")))?;
1277                        measure
1278                            .own
1279                            .extend(std::mem::take(next.entry(name.clone()).or_default()));
1280                        if let Some(left) = &state.next_left {
1281                            measure.left = Some(left.clone());
1282                        }
1283                        if let Some(measure) = staves.remove(name) {
1284                            parsed
1285                                .entry(name.clone())
1286                                .or_default()
1287                                .push(Held::Measure(Box::new(measure)));
1288                        }
1289                    }
1290                    state.next_left = next_left;
1291                }
1292                "scoreDef" => {
1293                    let mut everywhere: Vec<StreamElement> = Vec::new();
1294                    if held.get("meter.count").is_some() {
1295                        let meter = meter_of(held)?;
1296                        state.meter = Some(meter.clone());
1297                        everywhere.push(meter.into());
1298                    }
1299                    if held.get("key.pname").is_some() || held.get("key.sig").is_some() {
1300                        everywhere.push(StreamElement::Key(key_of(held)?));
1301                    }
1302                    let mut definitions: Vec<&Xml> = Vec::new();
1303                    for group in children(held, "staffGrp") {
1304                        descendants_in_groups(group, &mut definitions);
1305                    }
1306                    let mut own: HashMap<String, StaffDef> = HashMap::new();
1307                    for definition in definitions {
1308                        own.insert(
1309                            definition.get("n").unwrap_or("").to_string(),
1310                            self.staff_def(definition)?,
1311                        );
1312                    }
1313                    for name in parts {
1314                        let waiting = next.entry(name.clone()).or_default();
1315                        waiting.extend(everywhere.iter().cloned());
1316                        if let Some(definition) = own.get(name) {
1317                            waiting.extend(definition.elements());
1318                        }
1319                    }
1320                }
1321                "staffDef" => {
1322                    if let Some(name) = held.get("n") {
1323                        let definition = self.staff_def(held)?;
1324                        if let Some(meter) = &definition.meter {
1325                            state.meter = Some(meter.clone());
1326                        }
1327                        next.get_mut(name)
1328                            .ok_or_else(|| mei_error(format!("a <staffDef> for no part: {name}")))?
1329                            .extend(definition.elements());
1330                    }
1331                }
1332                "section" => {
1333                    let inner = self.section(held, parts, state)?;
1334                    for name in parts {
1335                        let mut list = inner.get(name).cloned().unwrap_or_default();
1336                        let mut waiting = std::mem::take(next.entry(name.clone()).or_default());
1337                        if !waiting.is_empty() {
1338                            // The instrument stands before the measures, and
1339                            // the rest at the start of the first of them.
1340                            if let Some(at) = waiting
1341                                .iter()
1342                                .position(|thing| matches!(thing, StreamElement::Instrument(_)))
1343                                && let StreamElement::Instrument(instrument) = waiting.remove(at)
1344                            {
1345                                list.insert(0, Held::Instrument(instrument));
1346                            }
1347                            if let Some(Held::Measure(first)) = list
1348                                .iter_mut()
1349                                .find(|thing| matches!(thing, Held::Measure(_)))
1350                            {
1351                                first.own.extend(waiting);
1352                            }
1353                        }
1354                        parsed.entry(name.clone()).or_default().extend(list);
1355                    }
1356                }
1357                _ => {}
1358            }
1359        }
1360        Ok(parsed)
1361    }
1362}
1363
1364/// What carries from one section to the next: the meter in force, the
1365/// barline the next measure opens with, and the measure count.
1366#[derive(Default)]
1367struct SectionState {
1368    meter: Option<TimeSignature>,
1369    next_left: Option<Barline>,
1370    backup: IntegerType,
1371}
1372
1373/// The `<staffDef>`s of a group and of the groups inside it.
1374fn descendants_in_groups<'a>(group: &'a Xml, out: &mut Vec<&'a Xml>) {
1375    for held in &group.children {
1376        match local(&held.tag) {
1377            "staffDef" => out.push(held),
1378            "staffGrp" => descendants_in_groups(held, out),
1379            _ => {}
1380        }
1381    }
1382}
1383
1384fn beam_type_of(text: &str) -> Result<BeamType> {
1385    match text {
1386        "start" => Ok(BeamType::Start),
1387        "continue" => Ok(BeamType::Continue),
1388        "stop" => Ok(BeamType::Stop),
1389        other => Err(mei_error(format!("a beam that does {other:?}"))),
1390    }
1391}
1392
1393/// music21's `sylFromElement`: a syllable, with the hyphen its place in the
1394/// word gives it.
1395fn syllable_of(element: &Xml) -> Result<Lyric> {
1396    let text = element
1397        .text()
1398        .ok_or_else(|| mei_error("a <syl> with no text"))?;
1399    let joiner = match element.get("con") {
1400        Some("s") => " ",
1401        Some("d") | None => "-",
1402        Some("t") => "~",
1403        Some("u") => "_",
1404        Some(other) => {
1405            return Err(mei_error(format!("a syllable joined by {other:?}")));
1406        }
1407    };
1408    let (text, syllabic) = match element.get("wordpos") {
1409        Some("i") => (format!("{text}{joiner}"), Some(Syllabic::Begin)),
1410        Some("m") => (format!("{joiner}{text}{joiner}"), Some(Syllabic::Middle)),
1411        Some("t") => (format!("{joiner}{text}"), Some(Syllabic::End)),
1412        None => (text.to_string(), None),
1413        Some(other) => {
1414            return Err(mei_error(format!("a syllable placed at {other:?}")));
1415        }
1416    };
1417    Ok(match syllabic {
1418        Some(syllabic) => {
1419            let mut lyric = Lyric::new(text);
1420            lyric.set_syllabic(syllabic);
1421            lyric
1422        }
1423        None => Lyric::from_raw_text(&text),
1424    })
1425}
1426
1427/// music21's `makeMetadata`: the title, composer and date of the first
1428/// `<work>`.
1429fn metadata_of(root: &Xml) -> Metadata {
1430    let mut metadata = Metadata::new();
1431    let mut works = Vec::new();
1432    descendants(root, "work", &mut works);
1433    let Some(work) = works.first() else {
1434        return metadata;
1435    };
1436    let statement = child(work, "titleStmt");
1437    let mut title: Option<String> = None;
1438    let mut subtitle: Option<String> = None;
1439    for held in statement
1440        .into_iter()
1441        .flat_map(|held| children(held, "title"))
1442    {
1443        let text = held.text().map(str::to_string);
1444        if held.get("type") == Some("subtitle") {
1445            subtitle = text;
1446        } else if title.is_none() {
1447            title = text;
1448        }
1449    }
1450    if let Some(subtitle) = subtitle.filter(|subtitle| !subtitle.is_empty()) {
1451        title = Some(format!(
1452            "{} ({subtitle})",
1453            title.as_deref().unwrap_or("None")
1454        ));
1455    }
1456    if let Some(title) = title {
1457        metadata.add_text("title", title);
1458    }
1459    if let Some(tempo) = child(work, "tempo") {
1460        metadata.add_text("movementName", tempo.text().unwrap_or("None"));
1461    }
1462    let mut composers: Vec<String> = Vec::new();
1463    if let Some(statement) = statement {
1464        for responsibility in children(statement, "respStmt") {
1465            for person in children(responsibility, "persName") {
1466                if person.get("role") == Some("composer")
1467                    && let Some(text) = person.text().filter(|text| !text.is_empty())
1468                {
1469                    composers.push(text.to_string());
1470                }
1471            }
1472        }
1473        for composer in children(statement, "composer") {
1474            let text = composer
1475                .text()
1476                .filter(|text| !text.is_empty())
1477                .or_else(|| child(composer, "persName").and_then(Xml::text));
1478            if let Some(text) = text.filter(|text| !text.is_empty()) {
1479                composers.push(text.to_string());
1480            }
1481        }
1482    }
1483    for composer in composers {
1484        metadata.add_contributor("composer", composer);
1485    }
1486    let date = child(work, "history")
1487        .and_then(|history| child(history, "creation"))
1488        .and_then(|creation| child(creation, "date"));
1489    if let Some(date) = date {
1490        let written = date
1491            .get("isodate")
1492            .filter(|text| !text.is_empty())
1493            .or(date.text().filter(|text| !text.is_empty()));
1494        // A date as music21 writes one: year, month and day, with two
1495        // hyphens for what is not said.
1496        let said = |written: &str| -> Option<String> {
1497            let parts: Vec<&str> = written.split(['-', '/']).collect();
1498            if parts.len() > 3 {
1499                return None;
1500            }
1501            let mut fields = Vec::new();
1502            for (index, part) in parts.iter().enumerate() {
1503                let number: u32 = part.parse().ok()?;
1504                fields.push(if index == 0 {
1505                    format!("{number:04}")
1506                } else {
1507                    format!("{number:02}")
1508                });
1509            }
1510            fields.resize(3, "--".to_string());
1511            Some(fields.join("/"))
1512        };
1513        if let Some(written) = written {
1514            if let Some(date) = said(written) {
1515                metadata.add_text("dateCreated", date);
1516            }
1517        } else {
1518            let start = date.get("notbefore").or(date.get("startdate"));
1519            let end = date.get("notafter").or(date.get("enddate"));
1520            if let (Some(start), Some(end)) = (start, end)
1521                && let (Some(start), Some(end)) = (said(start), said(end))
1522            {
1523                metadata.add_text("dateCreated", format!("{start} to {end}"));
1524            }
1525        }
1526    }
1527    metadata
1528}
1529
1530/// Reads an MEI document into a score: music21's `converter.parse` of one.
1531///
1532/// Every `<staffDef>` number is a part. A measure holds a voice for each
1533/// `<layer>`; a part with no staff in a measure rests through it, and a
1534/// measure rest lasts what the longest staff of its measure lasts. Beams,
1535/// tuplets, ties and slurs are read where they are written on the notes and
1536/// where they stand apart and name the notes by `xml:id`.
1537///
1538/// The text is the document's own, already decoded: the library opens no
1539/// file. A barline written inside a layer is passed over.
1540///
1541/// ```
1542/// use music21::mei::from_mei;
1543///
1544/// let score = from_mei(
1545///     r#"<mei xmlns="http://www.music-encoding.org/ns/mei"><music><score>
1546///     <scoreDef meter.count="2" meter.unit="4">
1547///       <staffGrp><staffDef n="1" clef.shape="G" clef.line="2"/></staffGrp>
1548///     </scoreDef>
1549///     <section><measure n="1"><staff n="1"><layer n="1">
1550///       <note pname="c" oct="4" dur="4"/><note pname="e" oct="4" dur="4" accid="f"/>
1551///     </layer></staff></measure></section>
1552///     </score></music></mei>"#,
1553/// )?;
1554/// let names: Vec<String> = score.parts()[0]
1555///     .pitches()
1556///     .iter()
1557///     .map(|pitch| pitch.name_with_octave())
1558///     .collect();
1559/// assert_eq!(names, ["C4", "Eb4"]);
1560/// # Ok::<(), music21::Error>(())
1561/// ```
1562pub fn from_mei(document: &str) -> Result<Stream> {
1563    // music21's words for it, at the place the XML reader stopped.
1564    let root = Xml::parse(document).map_err(|read| {
1565        let refused =
1566            mei_error("MEI document is not valid XML.").of_kind(FormatErrorKind::Malformed);
1567        match read.position() {
1568            Some(position) => refused.placed(|| position.clone()),
1569            None => refused,
1570        }
1571    })?;
1572    if local(&root.tag) != "mei" {
1573        return Err(mei_error(format!(
1574            "Root element should be <mei> in the MEI namespace, not <{}>.",
1575            root.tag
1576        )));
1577    }
1578    let score = child(&root, "music")
1579        .and_then(|music| {
1580            let mut found = Vec::new();
1581            descendants(music, "score", &mut found);
1582            found.first().copied()
1583        })
1584        .ok_or_else(|| mei_error("an MEI document with no <score> in its <music>"))?;
1585
1586    let mut reader = Reader {
1587        extra: HashMap::new(),
1588        slurs: Vec::new(),
1589        next_uid: 0,
1590        next_slur: 0,
1591    };
1592    reader.preprocess(score);
1593
1594    // music21's `allPartsPresent`: every staff number, in the order met.
1595    let mut definitions = Vec::new();
1596    descendants(score, "staffDef", &mut definitions);
1597    let mut parts: Vec<String> = Vec::new();
1598    for definition in definitions {
1599        let name = definition.get("n").unwrap_or("").to_string();
1600        if !parts.contains(&name) {
1601            parts.push(name);
1602        }
1603    }
1604    if parts.is_empty() {
1605        return Err(mei_error(
1606            "There appear to be no <staffDef> tags in this score.",
1607        ));
1608    }
1609
1610    let mut state = SectionState::default();
1611    let parsed = reader.section(score, &parts, &mut state)?;
1612
1613    // The parts, and the place among the score's leaves of every note a
1614    // slur may name.
1615    let mut events = Vec::new();
1616    let mut uids: Vec<Option<usize>> = Vec::new();
1617    // Where the longest part ends, which is where music21 appends the
1618    // slurs to the score.
1619    let mut end: FloatType = 0.0;
1620    for name in &parts {
1621        let mut held = Vec::new();
1622        let mut offset = 0.0;
1623        for thing in parsed.get(name).cloned().unwrap_or_default() {
1624            match thing {
1625                Held::Instrument(instrument) => {
1626                    uids.push(None);
1627                    held.push(StreamEvent::new(offset, *instrument));
1628                }
1629                Held::Measure(measure) => {
1630                    // What stands at the start sorts by its class, ahead of
1631                    // the voices.
1632                    let mut own: Vec<StreamEvent> = measure
1633                        .own
1634                        .into_iter()
1635                        .map(|element| StreamEvent::new(0.0, element))
1636                        .collect();
1637                    own.sort_by_key(|event| event.element().class_sort_order());
1638                    uids.extend(own.iter().map(|_| None));
1639                    let mut length: FloatType = 0.0;
1640                    for (id, things) in measure.voices {
1641                        let mut at = 0.0;
1642                        let mut inner = Vec::new();
1643                        for thing in things {
1644                            uids.push(Some(thing.uid));
1645                            let lasts = thing.element.quarter_length();
1646                            inner.push(StreamEvent::new(at, thing.element));
1647                            at = op_frac(at + lasts);
1648                        }
1649                        length = length.max(at);
1650                        let mut voice = Stream::with_kind(StreamKind::Voice).with_events(inner);
1651                        voice.set_id(Some(id));
1652                        own.push(StreamEvent::new(0.0, voice));
1653                    }
1654                    let mut stream = Stream::with_kind(StreamKind::Measure).with_events(own);
1655                    stream.set_number(measure.number);
1656                    stream.set_left_barline(measure.left);
1657                    stream.set_right_barline(measure.right);
1658                    held.push(StreamEvent::new(offset, stream));
1659                    offset = op_frac(offset + measure.length.unwrap_or(length));
1660                }
1661            }
1662        }
1663        end = end.max(offset);
1664        let mut part = Stream::with_kind(StreamKind::Part).with_events(held);
1665        // music21 says an MEI part is at written pitch.
1666        part.set_at_sounding_pitch(Some(false));
1667        events.push(StreamEvent::new(0.0, part));
1668    }
1669    let mut made = Stream::with_kind(StreamKind::Score).with_events(events);
1670    made.set_metadata(Some(metadata_of(&root)));
1671    for (name, joined) in reader.slurs {
1672        let positions: Vec<Option<usize>> = joined
1673            .iter()
1674            .map(|uid| uids.iter().position(|held| *held == Some(*uid)))
1675            .collect();
1676        let mut slur = Spanner::with_unplaced(SpannerKind::Slur, positions);
1677        slur.set_id_local(Some(name));
1678        slur.set_stands_in_score(true);
1679        slur.set_offset(end);
1680        made.add_spanner(slur);
1681    }
1682    Ok(made)
1683}
1684
1685#[cfg(test)]
1686mod tests {
1687    use super::*;
1688
1689    fn document(body: &str) -> String {
1690        format!(
1691            r#"<mei xmlns="http://www.music-encoding.org/ns/mei"><music><score>
1692            <scoreDef meter.count="4" meter.unit="4"><staffGrp>
1693            <staffDef n="1" clef.shape="G" clef.line="2"/>
1694            <staffDef n="2" clef.shape="F" clef.line="4"/>
1695            </staffGrp></scoreDef><section>{body}</section></score></music></mei>"#
1696        )
1697    }
1698
1699    #[test]
1700    fn a_transposition_past_any_interval_is_refused() {
1701        for (steps, semitones) in [
1702            ("2147483647", "0"),
1703            ("-2147483648", "0"),
1704            ("0", "-2147483648"),
1705            ("-2147483648", "2147483647"),
1706        ] {
1707            let written = format!("<staffDef trans.diat=\"{steps}\" trans.semi=\"{semitones}\"/>");
1708            let staff = Xml::parse(&written).unwrap();
1709            assert!(transposition_of(&staff).is_err(), "{written}");
1710        }
1711        let staff = Xml::parse("<staffDef trans.diat=\"-1\" trans.semi=\"-2\"/>").unwrap();
1712        assert_eq!(transposition_of(&staff).unwrap().directed_name(), "M-2");
1713    }
1714
1715    #[test]
1716    fn a_staff_with_nothing_written_rests_through_the_measure() {
1717        let score = from_mei(&document(
1718            r#"<measure n="1"><staff n="1"><layer n="1">
1719            <note pname="c" oct="4" dur="2"/><note pname="d" oct="4" dur="2"/>
1720            </layer></staff></measure>"#,
1721        ))
1722        .unwrap();
1723        let parts = score.parts();
1724        assert_eq!(parts.len(), 2);
1725        let rests: Vec<FloatType> = parts[1]
1726            .recurse()
1727            .into_iter()
1728            .filter(|(_, element)| matches!(element, StreamElement::Rest(_)))
1729            .map(|(_, element)| element.quarter_length())
1730            .collect();
1731        assert_eq!(rests, [4.0]);
1732    }
1733
1734    #[test]
1735    fn a_beam_runs_from_its_first_note_to_its_last() {
1736        let score = from_mei(&document(
1737            r#"<measure n="1"><staff n="1"><layer n="1"><beam>
1738            <note pname="c" oct="4" dur="8"/><note pname="d" oct="4" dur="8"/>
1739            <note pname="e" oct="4" dur="8"/></beam></layer></staff>
1740            <staff n="2"><layer n="1"><mRest/></layer></staff></measure>"#,
1741        ))
1742        .unwrap();
1743        let beams: Vec<Option<BeamType>> = score.parts()[0]
1744            .recurse()
1745            .into_iter()
1746            .filter_map(|(_, element)| match element {
1747                StreamElement::Note(note) => {
1748                    Some(note.beams().by_number(1).and_then(|beam| beam.beam_type()))
1749                }
1750                _ => None,
1751            })
1752            .collect();
1753        assert_eq!(
1754            beams,
1755            [
1756                Some(BeamType::Start),
1757                Some(BeamType::Continue),
1758                Some(BeamType::Stop)
1759            ]
1760        );
1761    }
1762
1763    #[test]
1764    fn a_tuplet_scales_its_notes_and_brackets_them() {
1765        let score = from_mei(&document(
1766            r#"<measure n="1"><staff n="1"><layer n="1"><tuplet num="3" numbase="2">
1767            <note pname="c" oct="4" dur="4"/><note pname="d" oct="4" dur="4"/>
1768            <note pname="e" oct="4" dur="4"/></tuplet></layer></staff></measure>"#,
1769        ))
1770        .unwrap();
1771        let lengths: Vec<FloatType> = score.parts()[0]
1772            .notes()
1773            .into_iter()
1774            .map(|(_, element)| element.quarter_length())
1775            .collect();
1776        assert_eq!(lengths.len(), 3);
1777        assert!(
1778            lengths
1779                .iter()
1780                .all(|length| (length - 2.0 / 3.0).abs() < 1e-9)
1781        );
1782    }
1783
1784    #[test]
1785    fn a_tie_written_apart_names_its_notes() {
1786        let score = from_mei(&document(
1787            r##"<measure n="1"><staff n="1"><layer n="1">
1788            <note xml:id="a" pname="c" oct="4" dur="2"/><note xml:id="b" pname="c" oct="4" dur="2"/>
1789            </layer></staff><tie startid="#a" endid="#b"/></measure>"##,
1790        ))
1791        .unwrap();
1792        let ties: Vec<Option<TieType>> = score.parts()[0]
1793            .notes()
1794            .into_iter()
1795            .filter_map(|(_, element)| match element {
1796                StreamElement::Note(note) => Some(note.tie().map(Tie::tie_type)),
1797                _ => None,
1798            })
1799            .collect();
1800        assert_eq!(ties, [Some(TieType::Start), Some(TieType::Stop)]);
1801    }
1802
1803    #[test]
1804    fn a_chord_and_a_rest_keep_their_ids() {
1805        let score = from_mei(&document(
1806            r#"<measure n="1"><staff n="1"><layer n="1">
1807            <chord xml:id="c1" dur="2"><note pname="c" oct="4"/><note pname="e" oct="4"/></chord>
1808            <rest xml:id="r1" dur="2"/></layer></staff></measure>"#,
1809        ))
1810        .unwrap();
1811        let ids: Vec<Option<&str>> = score.parts()[0]
1812            .recurse()
1813            .into_iter()
1814            .filter_map(|(_, element)| match element {
1815                StreamElement::Chord(chord) => Some(chord.id()),
1816                StreamElement::Rest(rest) => Some(rest.id()),
1817                _ => None,
1818            })
1819            .collect();
1820        assert_eq!(ids, [Some("c1"), Some("r1")]);
1821    }
1822
1823    #[test]
1824    fn slurs_stand_in_the_score_after_its_last_measure() {
1825        let score = from_mei(&document(
1826            r##"<measure n="1"><staff n="1"><layer n="1">
1827            <note xml:id="a" pname="c" oct="4" dur="2" slur="1i"/>
1828            <note xml:id="b" pname="d" oct="4" dur="2" slur="1t"/>
1829            </layer></staff><slur startid="#a" endid="#b"/></measure>"##,
1830        ))
1831        .unwrap();
1832        let slurs = score.spanners();
1833        assert_eq!(slurs.len(), 2);
1834        assert!(slurs.iter().all(Spanner::stands_in_score));
1835        assert!(slurs.iter().all(|slur| slur.offset() == 4.0));
1836        // One written apart is named afresh each read, as music21 names it
1837        // with a random UUID; one written on its notes keeps its number.
1838        let apart = slurs[0].id_local().unwrap();
1839        assert_eq!(apart.len(), 36);
1840        assert_eq!(apart.as_bytes()[14], b'4');
1841        assert_eq!(slurs[1].id_local(), Some("1"));
1842    }
1843
1844    /// music21 makes an MEI grace note's duration from its length, which
1845    /// leaves the way it is written inferred, where the note's own `dur`
1846    /// was written.
1847    #[test]
1848    fn a_grace_notes_value_is_inferred() {
1849        let score = from_mei(&document(
1850            r#"<measure n="1"><staff n="1"><layer n="1">
1851            <note pname="c" oct="4" dur="8" grace="unacc"/><note pname="d" oct="4" dur="1"/>
1852            </layer></staff></measure>"#,
1853        ))
1854        .unwrap();
1855        let inferred: Vec<bool> = score.parts()[0]
1856            .notes()
1857            .into_iter()
1858            .filter_map(|(_, element)| element.duration().map(Duration::expression_is_inferred))
1859            .collect();
1860        assert_eq!(inferred, [true, false]);
1861    }
1862
1863    #[test]
1864    fn what_is_no_mei_is_refused() {
1865        assert!(from_mei("<score-partwise/>").is_err());
1866        assert!(from_mei("not xml at all").is_err());
1867    }
1868
1869    fn with_key(attributes: &str) -> String {
1870        format!(
1871            r#"<mei xmlns="http://www.music-encoding.org/ns/mei"><music><score>
1872            <scoreDef meter.count="4" meter.unit="4"><staffGrp>
1873            <staffDef n="1" clef.shape="G" clef.line="2" {attributes}/>
1874            </staffGrp></scoreDef><section><measure n="1"><staff n="1"><layer n="1">
1875            <note pname="c" oct="4" dur="1"/></layer></staff></measure></section>
1876            </score></music></mei>"#
1877        )
1878    }
1879
1880    #[test]
1881    fn a_key_in_a_mode_music21_has_no_scale_for_is_refused() {
1882        assert!(from_mei(&with_key(r#"key.pname="c" key.mode="dorian""#)).is_ok());
1883        assert!(
1884            from_mei(&with_key(
1885                r#"key.pname="c" key.mode='major #(system "touch x") %'"#
1886            ))
1887            .is_err()
1888        );
1889    }
1890
1891    #[test]
1892    fn a_key_signature_with_no_count_is_refused() {
1893        assert!(from_mei(&with_key(r#"key.sig="2s""#)).is_ok());
1894        for signature in ["", "és", "x"] {
1895            assert!(
1896                from_mei(&with_key(&format!(r#"key.sig="{signature}""#))).is_err(),
1897                "{signature:?}"
1898            );
1899        }
1900    }
1901}