1use 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, 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
38fn 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
57fn 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
67fn without_hash(id: &str) -> &str {
68 id.strip_prefix('#').unwrap_or(id)
69}
70
71#[derive(Clone, Debug)]
74struct Search {
75 end: &'static str,
76 number: u32,
77 base: u32,
78}
79
80#[derive(Clone, Debug)]
83struct Thing {
84 element: StreamElement,
85 uid: usize,
87 search: Option<Search>,
88 whole_measure: bool,
90}
91
92#[derive(Clone, Debug, Default)]
95struct StaffDef {
96 instrument: Option<Instrument>,
97 meter: Option<TimeSignature>,
98 key: Option<Key>,
99 clef: Option<Clef>,
100}
101
102impl StaffDef {
103 fn elements(&self) -> Vec<StreamElement> {
104 let mut out: Vec<StreamElement> = Vec::new();
105 if let Some(instrument) = &self.instrument {
106 out.push(instrument.clone().into());
107 }
108 if let Some(meter) = &self.meter {
109 out.push(meter.clone().into());
110 }
111 if let Some(key) = &self.key {
112 out.push(StreamElement::Key(key.clone()));
113 }
114 if let Some(clef) = &self.clef {
115 out.push(clef.clone().into());
116 }
117 out
118 }
119}
120
121#[derive(Clone, Debug)]
123struct Measure {
124 number: IntegerType,
125 voices: Vec<(String, Vec<Thing>)>,
127 own: Vec<StreamElement>,
129 left: Option<Barline>,
130 right: Option<Barline>,
131 length: Option<FloatType>,
133}
134
135#[derive(Clone, Debug)]
138enum Held {
139 Instrument(Box<Instrument>),
140 Measure(Box<Measure>),
141}
142
143struct Reader {
146 extra: HashMap<String, Vec<(&'static str, String)>>,
148 slurs: Vec<(String, Vec<usize>)>,
150 next_uid: usize,
151 next_slur: usize,
152}
153
154const DURATIONS: [(&str, FloatType); 14] = [
155 ("long", 16.0),
156 ("breve", 8.0),
157 ("1", 4.0),
158 ("2", 2.0),
159 ("4", 1.0),
160 ("8", 0.5),
161 ("16", 0.25),
162 ("32", 0.125),
163 ("64", 0.0625),
164 ("128", 0.03125),
165 ("256", 0.015625),
166 ("512", 0.0078125),
167 ("1024", 0.00390625),
168 ("2048", 0.001953125),
169];
170
171const NO_DURATION: FloatType = 0.00390625;
174
175fn accidental_of(attribute: Option<&str>) -> Result<Option<&'static str>> {
176 let Some(attribute) = attribute else {
177 return Ok(None);
178 };
179 Ok(Some(match attribute {
180 "s" | "ns" => "#",
181 "f" | "nf" => "-",
182 "ss" | "x" => "##",
183 "ff" => "--",
184 "xs" | "ts" => "###",
185 "tf" => "---",
186 "n" => "n",
187 "su" => "#~",
188 "sd" | "nu" => "~",
189 "fu" | "nd" => "`",
190 "fd" => "-`",
191 other => {
192 return Err(mei_error(format!(
193 "Unexpected value for \"accid\" attribute: {other}"
194 )));
195 }
196 }))
197}
198
199fn gestural_accidental_of(attribute: &str) -> Result<&'static str> {
200 Ok(match attribute {
201 "s" => "#",
202 "f" => "-",
203 "ss" => "##",
204 "ff" => "--",
205 "n" => "n",
206 "su" => "#~",
207 "sd" => "~",
208 "fu" => "`",
209 "fd" => "-`",
210 other => {
211 return Err(mei_error(format!(
212 "Unexpected value for \"accid.ges\" attribute: {other}"
213 )));
214 }
215 })
216}
217
218fn length_of(attribute: Option<&str>) -> Result<FloatType> {
219 let Some(attribute) = attribute else {
220 return Ok(NO_DURATION);
221 };
222 DURATIONS
223 .iter()
224 .find(|(name, _)| *name == attribute)
225 .map(|(_, length)| *length)
226 .ok_or_else(|| {
227 mei_error(format!(
228 "Unexpected value for \"dur\" attribute: {attribute}"
229 ))
230 })
231}
232
233fn duration_of(base: FloatType, dots: u32) -> Result<Duration> {
235 let plain = Duration::new(base)?;
236 Ok(match plain.type_and_dots() {
237 Some((kind, _)) => Duration::from_type_with_dots(kind, dots),
238 None => plain,
239 })
240}
241
242fn dots_of(element: &Xml) -> Result<u32> {
243 match element.get("dots") {
244 None => Ok(0),
245 Some(dots) => dots
246 .parse()
247 .map_err(|_| mei_error(format!("the dots {dots:?} are no number"))),
248 }
249}
250
251fn articulations_of(attribute: &str) -> Result<Vec<Articulation>> {
253 let mut marks = Vec::new();
254 for name in attribute.split(' ') {
255 let classes: &[&str] = match name {
256 "marc-stacc" => &["StrongAccent", "Staccato"],
257 "ten-stacc" => &["Tenuto", "Staccato"],
258 "acc" => &["Accent"],
259 "stacc" => &["Staccato"],
260 "ten" => &["Tenuto"],
261 "stacciss" => &["Staccatissimo"],
262 "marc" => &["StrongAccent"],
263 "spicc" => &["Spiccato"],
264 "doit" => &["Doit"],
265 "plop" => &["Plop"],
266 "fall" => &["Falloff"],
267 "dnbow" => &["DownBow"],
268 "upbow" => &["UpBow"],
269 "harm" => &["Harmonic"],
270 "snap" => &["SnapPizzicato"],
271 "stop" => &["Stopped"],
272 "open" => &["OpenString"],
273 "dbltongue" => &["DoubleTongue"],
274 "toe" => &["OrganToe"],
275 "trpltongue" => &["TripleTongue"],
276 "heel" => &["OrganHeel"],
277 "tap" | "lhpizz" | "dot" | "stroke" | "rip" | "bend" | "flip" | "smear"
278 | "fingernail" | "damp" | "dampall" => &["Articulation"],
279 other => {
280 return Err(mei_error(format!(
281 "Unexpected value for \"artic\" attribute: {other}"
282 )));
283 }
284 };
285 for class in classes {
286 let kind = ArticulationKind::from_class_name(class)
287 .ok_or_else(|| mei_error(format!("no articulation called {class}")))?;
288 marks.push(Articulation::of_kind(kind));
289 }
290 }
291 Ok(marks)
292}
293
294fn barline_of(attribute: &str) -> Result<(Barline, Option<Barline>)> {
297 Ok(match attribute {
298 "rptboth" => (
299 Barline::repeat(RepeatDirection::End, Some(2)),
300 Some(Barline::repeat(RepeatDirection::Start, None)),
301 ),
302 "rptend" => (Barline::repeat(RepeatDirection::End, Some(2)), None),
303 other if other.starts_with("rpt") => (Barline::repeat(RepeatDirection::Start, None), None),
304 other => {
305 let kind = match other {
306 "dashed" => BarlineType::Dashed,
307 "dotted" => BarlineType::Dotted,
308 "dbl" => BarlineType::Double,
309 "end" => BarlineType::Final,
310 "invis" => BarlineType::None,
311 "single" => BarlineType::Regular,
312 other => {
313 return Err(mei_error(format!(
314 "Unexpected value for \"right\" attribute: {other}"
315 )));
316 }
317 };
318 (Barline::new(kind), None)
319 }
320 })
321}
322
323fn tie_of(attribute: &str) -> Tie {
324 let has = |mark: char| attribute.contains(mark);
325 Tie::new(if has('m') || (has('t') && has('i')) {
326 TieType::Continue
327 } else if has('i') {
328 TieType::Start
329 } else {
330 TieType::Stop
331 })
332}
333
334fn meter_of(element: &Xml) -> Result<TimeSignature> {
335 TimeSignature::from_ratio_string(&format!(
336 "{}/{}",
337 element.get("meter.count").unwrap_or("None"),
338 element.get("meter.unit").unwrap_or("None")
339 ))
340}
341
342fn key_of(element: &Xml) -> Result<Key> {
345 if let Some(step) = element.get("key.pname") {
346 let tonic = format!(
347 "{step}{}",
348 accidental_of(element.get("key.accid"))?.unwrap_or("")
349 );
350 return Key::from_tonic_mode(
351 &tonic,
352 element.get("key.mode").filter(|mode| !mode.is_empty()),
353 );
354 }
355 let signature = element.get("key.sig").unwrap_or("0");
356 let count = || -> Result<IntegerType> {
357 signature[..1]
358 .parse()
359 .map_err(|_| mei_error(format!("the key signature {signature:?} has no number")))
360 };
361 let sharps = if signature.starts_with('0') {
362 0
363 } else if signature.ends_with('s') {
364 count()?
365 } else {
366 -count()?
367 };
368 Ok(KeySignature::new(sharps).as_key(element.get("key.mode").unwrap_or("major")))
369}
370
371fn transposition_of(element: &Xml) -> Result<Interval> {
374 let read = |name: &str| -> Result<IntegerType> {
375 match element.get(name) {
376 None => Ok(0),
377 Some(text) => text
378 .parse()
379 .map_err(|_| mei_error(format!("{name} is no number: {text:?}"))),
380 }
381 };
382 let mut diatonic = read("trans.diat")?;
383 let semitones = read("trans.semi")?;
384 if (semitones - diatonic).abs() > 5 * (semitones.abs() / 12 + 1) {
387 if semitones < 0 {
388 diatonic -= 7 * (semitones.abs() / 12);
389 } else if semitones > 0 {
390 diatonic += 7 * (semitones.abs() / 12);
391 }
392 }
393 diatonic += diatonic.signum();
394 Interval::from_generic_and_chromatic(diatonic, semitones)
395}
396
397fn clef_of(
398 shape: Option<&str>,
399 line: Option<&str>,
400 displaced: Option<&str>,
401 place: Option<&str>,
402) -> Result<Clef> {
403 match shape {
404 Some("perc") => Ok(Clef::of_kind(ClefKind::PercussionClef)),
405 Some("TAB") => Ok(Clef::of_kind(ClefKind::TabClef)),
406 _ => {
407 let octaves = match displaced {
408 None => 0,
409 Some("8") => 1,
410 Some("15") => 2,
411 Some("22") => 3,
412 Some(other) => {
413 return Err(mei_error(format!("a clef displaced by {other}")));
414 }
415 };
416 let shift = if place == Some("below") {
417 -octaves
418 } else {
419 octaves
420 };
421 let (Some(shape), Some(line)) = (shape, line) else {
422 return Err(mei_error("a clef with no shape or no line"));
423 };
424 Clef::from_string(&format!("{shape}{line}"), shift)
425 }
426 }
427}
428
429fn clef_element(element: &Xml) -> Result<Clef> {
430 clef_of(
431 element.get("shape"),
432 element.get("line"),
433 element.get("dis"),
434 element.get("dis.place"),
435 )
436}
437
438fn is_beamable(duration: &Duration) -> Option<DurationType> {
440 match duration.components().as_slice() {
441 [(kind, _)] if kind.quarter_length() < 1.0 => Some(*kind),
442 _ => None,
443 }
444}
445
446fn with_duration(element: &mut StreamElement, change: impl FnOnce(&mut Duration)) {
447 let Some(mut duration) = element.duration().cloned() else {
448 return;
449 };
450 change(&mut duration);
451 match element {
452 StreamElement::Note(note) => note.set_duration(duration),
453 StreamElement::Chord(chord) => chord.set_duration(duration),
454 StreamElement::Rest(rest) => rest.set_duration(duration),
455 _ => {}
456 }
457}
458
459fn is_sounding(element: &StreamElement) -> bool {
460 matches!(
461 element,
462 StreamElement::Note(_) | StreamElement::Chord(_) | StreamElement::Rest(_)
463 )
464}
465
466fn mark_first_tuplet(element: &mut StreamElement, kind: TupletType) {
467 with_duration(element, |duration| {
468 let mut tuplets = duration.tuplets();
469 if let Some(first) = tuplets.first_mut() {
470 first.set_tuplet_type(Some(kind));
471 }
472 duration.set_tuplets(tuplets);
473 });
474}
475
476fn scale_to_tuplet(element: &mut StreamElement, number: u32, base: u32) {
479 if !is_sounding(element) {
480 return;
481 }
482 with_duration(element, |duration| {
483 let kind = match duration.components().as_slice() {
484 [(kind, _)] => *kind,
485 _ => DurationType::Quarter,
486 };
487 duration.append_tuplet(Tuplet::new(number, base, kind, 0));
488 });
489}
490
491fn beam_together(things: &mut [Thing]) -> Result<()> {
494 let mut last: Option<usize> = None;
495 for (index, thing) in things.iter_mut().enumerate() {
496 let (beams, duration) = match &thing.element {
497 StreamElement::Note(note) => (note.beams().clone(), note.duration().cloned()),
498 StreamElement::Chord(chord) => (chord.beams().clone(), chord.duration().cloned()),
499 _ => continue,
500 };
501 let Some(kind) = duration.as_ref().and_then(is_beamable) else {
502 continue;
503 };
504 if !beams.is_empty() {
505 continue;
506 }
507 let mut filled = beams;
508 filled.fill(
509 kind,
510 Some(if last.is_none() {
511 BeamType::Start
512 } else {
513 BeamType::Continue
514 }),
515 )?;
516 match &mut thing.element {
517 StreamElement::Note(note) => note.set_beams(filled),
518 StreamElement::Chord(chord) => chord.set_beams(filled),
519 _ => {}
520 }
521 last = Some(index);
522 }
523 let closing = last.or(things.len().checked_sub(1));
525 if let Some(thing) = closing.and_then(|index| things.get_mut(index)) {
526 match &mut thing.element {
527 StreamElement::Note(note) => {
528 let mut beams = note.beams().clone();
529 beams.set_all(BeamType::Stop, None);
530 note.set_beams(beams);
531 }
532 StreamElement::Chord(chord) => {
533 let mut beams = chord.beams().clone();
534 beams.set_all(BeamType::Stop, None);
535 chord.set_beams(beams);
536 }
537 _ => {}
538 }
539 }
540 Ok(())
541}
542
543impl Reader {
544 fn attribute(&self, element: &Xml, name: &str) -> Option<String> {
548 let added = element
549 .get("xml:id")
550 .and_then(|id| self.extra.get(id))
551 .and_then(|extra| {
552 extra
553 .iter()
554 .find(|(held, _)| *held == name)
555 .map(|(_, value)| value.clone())
556 });
557 match (element.get(name), added) {
558 (Some(own), Some(added)) => Some(format!("{own}{added}")),
559 (Some(own), None) => Some(own.to_string()),
560 (None, added) => added,
561 }
562 }
563
564 fn set(&mut self, id: &str, name: &'static str, value: String) {
565 let extra = self.extra.entry(without_hash(id).to_string()).or_default();
566 match extra.iter_mut().find(|(held, _)| *held == name) {
567 Some((_, held)) => *held = value,
568 None => extra.push((name, value)),
569 }
570 }
571
572 fn preprocess(&mut self, score: &Xml) {
576 let mut found = Vec::new();
577 descendants(score, "slur", &mut found);
578 for slur in std::mem::take(&mut found) {
579 if let (Some(start), Some(end)) = (slur.get("startid"), slur.get("endid")) {
580 let name = format!("slur-{}", self.next_slur);
581 self.next_slur += 1;
582 self.slurs.push((name.clone(), Vec::new()));
583 self.set(start, "m21SlurStart", name.clone());
584 self.set(end, "m21SlurEnd", name);
585 }
586 }
587 descendants(score, "tie", &mut found);
588 for tie in std::mem::take(&mut found) {
589 if let (Some(start), Some(end)) = (tie.get("startid"), tie.get("endid")) {
590 self.set(start, "tie", "i".to_string());
591 self.set(end, "tie", "t".to_string());
592 }
593 }
594 descendants(score, "beamSpan", &mut found);
595 for beam in std::mem::take(&mut found) {
596 let (Some(start), Some(end)) = (beam.get("startid"), beam.get("endid")) else {
597 continue;
598 };
599 self.set(start, "m21Beam", "start".to_string());
600 self.set(end, "m21Beam", "stop".to_string());
601 for id in beam.get("plist").unwrap_or("").split(' ') {
602 let id = without_hash(id);
603 let has = self
604 .extra
605 .get(id)
606 .is_some_and(|extra| extra.iter().any(|(name, _)| *name == "m21Beam"));
607 if !has {
608 self.set(id, "m21Beam", "continue".to_string());
609 }
610 }
611 }
612 descendants(score, "tupletSpan", &mut found);
613 for tuplet in found {
614 let number = tuplet.get("num").unwrap_or("None").to_string();
615 let base = tuplet.get("numbase").unwrap_or("None").to_string();
616 if let Some(list) = tuplet.get("plist") {
617 for id in list.split(' ') {
618 if !without_hash(id).is_empty() {
619 self.set(id, "m21TupletNum", number.clone());
620 self.set(id, "m21TupletNumbase", base.clone());
621 }
622 }
623 } else if let (Some(start), Some(end)) = (tuplet.get("startid"), tuplet.get("endid")) {
624 for (id, which) in [(start, "start"), (end, "end")] {
625 self.set(id, "m21TupletSearch", which.to_string());
626 self.set(id, "m21TupletNum", number.clone());
627 self.set(id, "m21TupletNumbase", base.clone());
628 }
629 }
630 }
631 }
632
633 fn uid(&mut self) -> usize {
634 self.next_uid += 1;
635 self.next_uid - 1
636 }
637
638 fn add_slurs(&mut self, element: &Xml, uid: usize) -> Result<()> {
640 let join = |slurs: &mut Vec<(String, Vec<usize>)>, name: &str| {
641 if let Some((_, held)) = slurs.iter_mut().find(|(held, _)| held == name) {
642 held.push(uid);
643 }
644 };
645 if let Some(name) = self.attribute(element, "m21SlurStart") {
646 join(&mut self.slurs, &name);
647 }
648 if let Some(name) = self.attribute(element, "m21SlurEnd") {
649 join(&mut self.slurs, &name);
650 }
651 if let Some(slurs) = element.get("slur") {
652 for slur in slurs.split(' ') {
653 let chars: Vec<char> = slur.chars().collect();
654 let [number, kind] = chars.as_slice() else {
655 return Err(mei_error(format!("cannot read the slur {slur:?}")));
656 };
657 let name = number.to_string();
658 match kind {
659 'i' => self.slurs.push((name, vec![uid])),
660 't' => join(&mut self.slurs, &name),
661 _ => {}
662 }
663 }
664 }
665 Ok(())
666 }
667
668 fn tuplet(&self, element: &Xml, thing: &mut Thing) -> Result<()> {
671 let Some(number) = self.attribute(element, "m21TupletNum") else {
672 return Ok(());
673 };
674 let base = self
675 .attribute(element, "m21TupletNumbase")
676 .unwrap_or_default();
677 let read = |text: &str| -> Result<u32> {
678 text.parse()
679 .map_err(|_| mei_error(format!("a tuplet of {text:?} notes")))
680 };
681 let (number, base) = (read(&number)?, read(&base)?);
682 match self.attribute(element, "m21TupletSearch").as_deref() {
683 Some(end) => {
684 thing.search = Some(Search {
685 end: if end.contains("start") {
686 "start"
687 } else {
688 "end"
689 },
690 number,
691 base,
692 });
693 }
694 None => {
695 scale_to_tuplet(&mut thing.element, number, base);
696 if let Some(written) = element.get("tuplet") {
697 if written.starts_with('i') {
698 mark_first_tuplet(&mut thing.element, TupletType::Start);
699 } else if written.starts_with('t') {
700 mark_first_tuplet(&mut thing.element, TupletType::Stop);
701 }
702 }
703 }
704 }
705 Ok(())
706 }
707
708 fn note(&mut self, element: &Xml) -> Result<(Note, usize)> {
711 let name = element.get("pname").unwrap_or("");
712 let mut pitch = if name.is_empty() {
713 Pitch::from_name("C4")?
714 } else {
715 let step = name
716 .chars()
717 .next()
718 .map(|c| c.to_ascii_uppercase())
719 .ok_or_else(|| mei_error("a note with no name"))?;
720 let mut options = PitchOptions::new().step(step);
721 if let Some(octave) = element.get("oct").filter(|octave| !octave.is_empty()) {
722 options = options.octave(
723 octave
724 .parse()
725 .map_err(|_| mei_error(format!("the octave {octave:?} is no number")))?,
726 );
727 }
728 options.build()?
729 };
730 if let Some(accidental) = accidental_of(element.get("accid"))? {
731 pitch.set_written_accidental(Some(Accidental::new(accidental)?));
732 }
733 let length = length_of(element.get("dur"))?;
734 let mut note =
735 Note::from_pitch(pitch).with_duration(duration_of(length, dots_of(element)?)?);
736
737 let mut dot_elements = 0;
738 for held in &element.children {
739 match local(&held.tag) {
740 "dot" => dot_elements += 1,
741 "artic" => {
742 if let Some(marks) = held.get("artic") {
743 note.articulations_mut().extend(articulations_of(marks)?);
744 }
745 }
746 "accid" => {
747 let accidental = match held.get("accid.ges") {
748 Some(gestural) => Some(gestural_accidental_of(gestural)?),
749 None => accidental_of(held.get("accid"))?,
750 };
751 if let Some(accidental) = accidental {
752 let mut pitch = note.pitch().clone();
753 pitch.set_written_accidental(Some(Accidental::new(accidental)?));
754 note.set_pitch(pitch);
755 }
756 }
757 "syl" => *note.lyrics_mut() = vec![syllable_of(held)?],
758 _ => {}
759 }
760 }
761 if let Some(gestural) = element.get("accid.ges") {
762 let mut pitch = note.pitch().clone();
763 pitch.set_written_accidental(Some(Accidental::new(gestural_accidental_of(gestural)?)?));
764 note.set_pitch(pitch);
765 }
766 let uid = self.uid();
767 self.add_slurs(element, uid)?;
768 if let Some(id) = element.get("xml:id") {
769 note.set_id(Some(id.to_string()));
770 }
771 if let Some(marks) = element.get("artic") {
772 note.articulations_mut().extend(articulations_of(marks)?);
773 }
774 if let Some(tie) = self.attribute(element, "tie") {
775 note.set_tie(Some(tie_of(&tie)));
776 }
777 if dot_elements > 0 {
778 note.set_duration(duration_of(length, dot_elements)?);
779 }
780 if element.get("grace").is_some() {
781 let grace = note
782 .duration()
783 .map(Duration::grace_duration)
784 .unwrap_or_default();
785 note.set_duration(grace);
786 }
787 if let Some(beam) = self.attribute(element, "m21Beam")
788 && let Some(kind) = note.duration().and_then(is_beamable)
789 {
790 let mut beams = note.beams().clone();
791 beams.fill(kind, Some(beam_type_of(&beam)?))?;
792 note.set_beams(beams);
793 }
794 let verses: Vec<&Xml> = children(element, "verse").collect();
795 if !verses.is_empty() {
796 let mut lyrics = Vec::new();
797 for (index, verse) in verses.iter().enumerate() {
798 let number = match verse.get("n") {
799 Some(number) => number.parse::<IntegerType>().ok(),
800 None => Some(index as IntegerType + 1),
801 };
802 for syllable in children(verse, "syl") {
803 let mut lyric = syllable_of(syllable)?;
804 if let Some(number) = number {
805 lyric.set_number(number);
806 }
807 lyrics.push(lyric);
808 }
809 }
810 *note.lyrics_mut() = lyrics;
811 }
812 Ok((note, uid))
813 }
814
815 fn note_thing(&mut self, element: &Xml) -> Result<Thing> {
816 let (note, uid) = self.note(element)?;
817 let mut thing = Thing {
818 element: note.into(),
819 uid,
820 search: None,
821 whole_measure: false,
822 };
823 self.tuplet(element, &mut thing)?;
824 Ok(thing)
825 }
826
827 fn chord(&mut self, element: &Xml) -> Result<Thing> {
829 let mut notes = Vec::new();
830 for held in children(element, "note") {
831 let thing = self.note_thing(held)?;
833 if let StreamElement::Note(note) = thing.element {
834 notes.push(note);
835 }
836 }
837 let mut chord = Chord::new(notes)?.with_duration(duration_of(
838 length_of(element.get("dur"))?,
839 dots_of(element)?,
840 )?);
841 for held in children(element, "artic") {
842 if let Some(marks) = held.get("artic") {
843 chord.articulations_mut().extend(articulations_of(marks)?);
844 }
845 }
846 let uid = self.uid();
847 self.add_slurs(element, uid)?;
848 if let Some(marks) = element.get("artic") {
849 chord.articulations_mut().extend(articulations_of(marks)?);
850 }
851 if let Some(tie) = self.attribute(element, "tie") {
852 chord.set_tie(Some(tie_of(&tie)));
853 }
854 if element.get("grace").is_some() {
855 let grace = chord
856 .duration()
857 .map(Duration::grace_duration)
858 .unwrap_or_default();
859 chord.set_duration(grace);
860 }
861 if let Some(beam) = self.attribute(element, "m21Beam")
862 && let Some(kind) = chord.duration().and_then(is_beamable)
863 {
864 let mut beams = chord.beams().clone();
865 beams.fill(kind, Some(beam_type_of(&beam)?))?;
866 chord.set_beams(beams);
867 }
868 let mut thing = Thing {
869 element: chord.into(),
870 uid,
871 search: None,
872 whole_measure: false,
873 };
874 self.tuplet(element, &mut thing)?;
875 Ok(thing)
876 }
877
878 fn rest(&mut self, element: &Xml, hidden: bool, whole_measure: bool) -> Result<Thing> {
881 let mut rest = Rest::new(duration_of(
882 length_of(element.get("dur"))?,
883 dots_of(element)?,
884 )?);
885 rest.set_hidden(hidden);
886 let mut thing = Thing {
887 element: rest.into(),
888 uid: self.uid(),
889 search: None,
890 whole_measure: whole_measure && element.get("dur").is_none(),
891 };
892 self.tuplet(element, &mut thing)?;
893 Ok(thing)
894 }
895
896 fn contents(&mut self, element: &Xml, in_layer: bool) -> Result<Vec<Thing>> {
898 let mut things = Vec::new();
899 for held in &element.children {
900 match local(&held.tag) {
901 "clef" => things.push(Thing {
902 element: clef_element(held)?.into(),
903 uid: self.uid(),
904 search: None,
905 whole_measure: false,
906 }),
907 "chord" => things.push(self.chord(held)?),
908 "note" => things.push(self.note_thing(held)?),
909 "rest" => things.push(self.rest(held, false, false)?),
910 "mRest" if in_layer => things.push(self.rest(held, false, true)?),
911 "space" => things.push(self.rest(held, true, false)?),
912 "mSpace" if in_layer => things.push(self.rest(held, true, true)?),
913 "beam" => {
914 let mut beamed = self.contents(held, false)?;
915 beam_together(&mut beamed)?;
916 things.extend(beamed);
917 }
918 "tuplet" => things.extend(self.tuplet_element(held)?),
919 "bTrem" => things.extend(self.tremolo(held)?),
920 "barLine" => {
923 let _ = barline_of(held.get("rend").unwrap_or("single"))?;
924 }
925 _ => {}
926 }
927 }
928 Ok(things)
929 }
930
931 fn tuplet_element(&mut self, element: &Xml) -> Result<Vec<Thing>> {
933 let (Some(number), Some(base)) = (element.get("num"), element.get("numbase")) else {
934 return Err(mei_error(
935 "Both @num and @numbase attributes are required on <tuplet> tags.",
936 ));
937 };
938 let read = |text: &str| -> Result<u32> {
939 text.parse()
940 .map_err(|_| mei_error(format!("a tuplet of {text:?} notes")))
941 };
942 let (number, base) = (read(number)?, read(base)?);
943 let mut members = self.contents(element, false)?;
944 for member in &mut members {
945 scale_to_tuplet(&mut member.element, number, base);
946 }
947 let sounding: Vec<usize> = (0..members.len())
948 .filter(|index| is_sounding(&members[*index].element))
949 .collect();
950 let first = *sounding
951 .first()
952 .ok_or_else(|| mei_error("a tuplet with no notes in it"))?;
953 mark_first_tuplet(&mut members[first].element, TupletType::Start);
954 let last = sounding.last().copied().filter(|last| *last != first);
955 mark_first_tuplet(
956 &mut members[last.unwrap_or(first)].element,
957 TupletType::Stop,
958 );
959 beam_together(&mut members)?;
960 Ok(members)
961 }
962
963 fn tremolo(&mut self, element: &Xml) -> Result<Vec<Thing>> {
965 let mut things = Vec::new();
966 for held in &element.children {
967 match local(&held.tag) {
968 "chord" => things.push(self.chord(held)?),
969 "note" => things.push(self.note_thing(held)?),
970 _ => {}
971 }
972 }
973 let marks = match element.get("unitdur") {
974 Some("8") => Some(1),
975 Some("16") => Some(2),
976 Some("32") => Some(3),
977 Some("64") => Some(4),
978 Some("128") => Some(5),
979 Some("256") => Some(6),
980 Some("512") => Some(7),
981 Some("1024") => Some(8),
982 _ => None,
983 };
984 if let Some(marks) = marks {
985 for thing in &mut things {
986 let mut tremolo = Ornament::of_kind(OrnamentKind::Tremolo);
987 tremolo.set_number_of_marks(marks)?;
988 let expression = Expression::from(tremolo);
989 match &mut thing.element {
990 StreamElement::Note(note) => note.expressions_mut().push(expression),
991 StreamElement::Chord(chord) => chord.expressions_mut().push(expression),
992 _ => {}
993 }
994 }
995 }
996 Ok(things)
997 }
998
999 fn layer(&mut self, element: &Xml) -> Result<Vec<Thing>> {
1002 let mut things = self.contents(element, true)?;
1003 let mut active: Option<(u32, u32)> = None;
1004 for thing in &mut things {
1005 if !is_sounding(&thing.element) {
1006 continue;
1007 }
1008 let search = thing.search.take();
1009 if let Some(search) = &search
1010 && search.end == "start"
1011 {
1012 active = Some((search.number, search.base));
1013 }
1014 if let Some((number, base)) = active {
1015 scale_to_tuplet(&mut thing.element, number, base);
1016 if search.is_some_and(|search| search.end == "end") {
1017 mark_first_tuplet(&mut thing.element, TupletType::Stop);
1018 active = None;
1019 }
1020 }
1021 }
1022 Ok(things)
1023 }
1024
1025 fn staff_def(&mut self, element: &Xml) -> Result<StaffDef> {
1027 let instrument = match child(element, "instrDef") {
1028 Some(definition) => Some(match definition.get("midi.instrnum") {
1029 Some(number) => Instrument::from_midi_program(number.parse().map_err(|_| {
1030 mei_error(format!("the MIDI program {number:?} is no number"))
1031 })?)?,
1032 None => {
1033 let name = definition.get("midi.instrname");
1034 name.and_then(|name| Instrument::from_name(name, SearchLanguage::All).ok())
1035 .unwrap_or_else(|| {
1036 let mut generic = Instrument::new();
1037 generic.set_part_name(Some(name.unwrap_or("").to_string()));
1038 generic
1039 })
1040 }
1041 }),
1042 None => {
1043 Instrument::from_name(element.get("label").unwrap_or(""), SearchLanguage::All).ok()
1044 }
1045 };
1046 let mut found = StaffDef {
1047 instrument,
1048 ..StaffDef::default()
1049 };
1050 if let Some(instrument) = &mut found.instrument {
1051 instrument.set_part_name(element.get("label").map(str::to_string));
1052 instrument.set_part_abbreviation(element.get("label.abbr").map(str::to_string));
1053 instrument.set_part_id(element.get("n").map(str::to_string));
1054 }
1055 if element.get("trans.semi").is_some() {
1056 found
1057 .instrument
1058 .get_or_insert_with(Instrument::new)
1059 .set_transposition(Some(transposition_of(element)?));
1060 }
1061 if element.get("meter.count").is_some() {
1062 found.meter = Some(meter_of(element)?);
1063 }
1064 if element.get("key.pname").is_some() || element.get("key.sig").is_some() {
1065 found.key = Some(key_of(element)?);
1066 }
1067 if element.get("clef.shape").is_some() {
1068 found.clef = Some(clef_of(
1069 element.get("clef.shape"),
1070 element.get("clef.line"),
1071 element.get("clef.dis"),
1072 element.get("clef.dis.place"),
1073 )?);
1074 }
1075 for held in children(element, "clef") {
1076 found.clef = Some(clef_element(held)?);
1077 }
1078 Ok(found)
1079 }
1080
1081 fn measure(
1083 &mut self,
1084 element: &Xml,
1085 backup: IntegerType,
1086 parts: &[String],
1087 meter: Option<&TimeSignature>,
1088 ) -> Result<(HashMap<String, Measure>, Option<Barline>)> {
1089 let number = match element.get("n") {
1090 Some(number) => number
1091 .parse()
1092 .map_err(|_| mei_error(format!("the measure number {number:?} is no number")))?,
1093 None => backup,
1094 };
1095 let mut staves: HashMap<String, Measure> = HashMap::new();
1096 let mut waiting: Vec<(String, StaffDef)> = Vec::new();
1097 let mut longest: Option<FloatType> = None;
1098 for held in &element.children {
1099 match local(&held.tag) {
1100 "staff" => {
1101 let mut voices = Vec::new();
1102 for (count, layer) in children(held, "layer").enumerate() {
1103 voices.push(((count + 1).to_string(), self.layer(layer)?));
1104 }
1105 let length = voices
1106 .iter()
1107 .map(|(_, things)| {
1108 things
1109 .iter()
1110 .map(|thing| thing.element.quarter_length())
1111 .sum::<FloatType>()
1112 })
1113 .fold(0.0, FloatType::max);
1114 longest = Some(longest.map_or(length, |held| held.max(length)));
1115 staves.insert(
1116 held.get("n").unwrap_or("").to_string(),
1117 Measure {
1118 number,
1119 voices,
1120 own: Vec::new(),
1121 left: None,
1122 right: None,
1123 length: None,
1124 },
1125 );
1126 }
1127 "staffDef" => {
1128 if let Some(name) = held.get("n") {
1129 waiting.push((name.to_string(), self.staff_def(held)?));
1130 }
1131 }
1132 _ => {}
1133 }
1134 }
1135 for (name, definition) in waiting {
1136 let measure = staves.get_mut(&name).ok_or_else(|| {
1137 mei_error(format!("a <staffDef> for staff {name}, which is not here"))
1138 })?;
1139 measure.own.extend(definition.elements());
1140 }
1141 for name in parts {
1143 if !staves.contains_key(name) {
1144 let length = longest.ok_or_else(|| mei_error("a measure with no staff in it"))?;
1145 staves.insert(
1146 name.clone(),
1147 Measure {
1148 number,
1149 voices: vec![(
1150 "1".to_string(),
1151 vec![Thing {
1152 element: Rest::new(Duration::new(length)?).into(),
1153 uid: self.uid(),
1154 search: None,
1155 whole_measure: true,
1156 }],
1157 )],
1158 own: Vec::new(),
1159 left: None,
1160 right: None,
1161 length: None,
1162 },
1163 );
1164 }
1165 }
1166 let target = match (longest, meter) {
1169 (Some(longest), Some(meter))
1170 if longest == NO_DURATION && longest != meter.bar_quarter_length() =>
1171 {
1172 Some(meter.bar_quarter_length())
1173 }
1174 (longest, _) => longest,
1175 };
1176 if let Some(target) = target {
1177 for measure in staves.values_mut() {
1178 for (_, things) in &mut measure.voices {
1179 for thing in things {
1180 if std::mem::take(&mut thing.whole_measure) {
1181 let duration = Duration::new(target)?;
1182 with_duration(&mut thing.element, |held| *held = duration);
1183 measure.length = Some(target);
1184 }
1185 }
1186 }
1187 }
1188 }
1189 let mut next_left = None;
1190 if let Some(left) = element.get("left") {
1191 let (first, second) = barline_of(left)?;
1192 let barline = second.unwrap_or(first);
1193 for measure in staves.values_mut() {
1194 measure.left = Some(barline.clone());
1195 }
1196 }
1197 if let Some(right) = element.get("right") {
1198 let (barline, next) = barline_of(right)?;
1199 next_left = next;
1200 for measure in staves.values_mut() {
1201 measure.right = Some(barline.clone());
1202 }
1203 }
1204 Ok((staves, next_left))
1205 }
1206
1207 fn section(
1210 &mut self,
1211 element: &Xml,
1212 parts: &[String],
1213 state: &mut SectionState,
1214 ) -> Result<HashMap<String, Vec<Held>>> {
1215 let in_section = local(&element.tag) == "section";
1216 let mut parsed: HashMap<String, Vec<Held>> = parts
1217 .iter()
1218 .map(|name| (name.clone(), Vec::new()))
1219 .collect();
1220 let mut next: HashMap<String, Vec<StreamElement>> = parts
1221 .iter()
1222 .map(|name| (name.clone(), Vec::new()))
1223 .collect();
1224 for held in &element.children {
1225 match local(&held.tag) {
1226 "measure" if in_section => {
1227 state.backup += 1;
1228 let (mut staves, next_left) =
1229 self.measure(held, state.backup, parts, state.meter.as_ref())?;
1230 for name in parts {
1231 let measure = staves
1232 .get_mut(name)
1233 .ok_or_else(|| mei_error(format!("no staff {name} in a measure")))?;
1234 measure
1235 .own
1236 .extend(std::mem::take(next.entry(name.clone()).or_default()));
1237 if let Some(left) = &state.next_left {
1238 measure.left = Some(left.clone());
1239 }
1240 if let Some(measure) = staves.remove(name) {
1241 parsed
1242 .entry(name.clone())
1243 .or_default()
1244 .push(Held::Measure(Box::new(measure)));
1245 }
1246 }
1247 state.next_left = next_left;
1248 }
1249 "scoreDef" => {
1250 let mut everywhere: Vec<StreamElement> = Vec::new();
1251 if held.get("meter.count").is_some() {
1252 let meter = meter_of(held)?;
1253 state.meter = Some(meter.clone());
1254 everywhere.push(meter.into());
1255 }
1256 if held.get("key.pname").is_some() || held.get("key.sig").is_some() {
1257 everywhere.push(StreamElement::Key(key_of(held)?));
1258 }
1259 let mut definitions: Vec<&Xml> = Vec::new();
1260 for group in children(held, "staffGrp") {
1261 descendants_in_groups(group, &mut definitions);
1262 }
1263 let mut own: HashMap<String, StaffDef> = HashMap::new();
1264 for definition in definitions {
1265 own.insert(
1266 definition.get("n").unwrap_or("").to_string(),
1267 self.staff_def(definition)?,
1268 );
1269 }
1270 for name in parts {
1271 let waiting = next.entry(name.clone()).or_default();
1272 waiting.extend(everywhere.iter().cloned());
1273 if let Some(definition) = own.get(name) {
1274 waiting.extend(definition.elements());
1275 }
1276 }
1277 }
1278 "staffDef" => {
1279 if let Some(name) = held.get("n") {
1280 let definition = self.staff_def(held)?;
1281 if let Some(meter) = &definition.meter {
1282 state.meter = Some(meter.clone());
1283 }
1284 next.get_mut(name)
1285 .ok_or_else(|| mei_error(format!("a <staffDef> for no part: {name}")))?
1286 .extend(definition.elements());
1287 }
1288 }
1289 "section" => {
1290 let inner = self.section(held, parts, state)?;
1291 for name in parts {
1292 let mut list = inner.get(name).cloned().unwrap_or_default();
1293 let mut waiting = std::mem::take(next.entry(name.clone()).or_default());
1294 if !waiting.is_empty() {
1295 if let Some(at) = waiting
1298 .iter()
1299 .position(|thing| matches!(thing, StreamElement::Instrument(_)))
1300 && let StreamElement::Instrument(instrument) = waiting.remove(at)
1301 {
1302 list.insert(0, Held::Instrument(instrument));
1303 }
1304 if let Some(Held::Measure(first)) = list
1305 .iter_mut()
1306 .find(|thing| matches!(thing, Held::Measure(_)))
1307 {
1308 first.own.extend(waiting);
1309 }
1310 }
1311 parsed.entry(name.clone()).or_default().extend(list);
1312 }
1313 }
1314 _ => {}
1315 }
1316 }
1317 Ok(parsed)
1318 }
1319}
1320
1321#[derive(Default)]
1324struct SectionState {
1325 meter: Option<TimeSignature>,
1326 next_left: Option<Barline>,
1327 backup: IntegerType,
1328}
1329
1330fn descendants_in_groups<'a>(group: &'a Xml, out: &mut Vec<&'a Xml>) {
1332 for held in &group.children {
1333 match local(&held.tag) {
1334 "staffDef" => out.push(held),
1335 "staffGrp" => descendants_in_groups(held, out),
1336 _ => {}
1337 }
1338 }
1339}
1340
1341fn beam_type_of(text: &str) -> Result<BeamType> {
1342 match text {
1343 "start" => Ok(BeamType::Start),
1344 "continue" => Ok(BeamType::Continue),
1345 "stop" => Ok(BeamType::Stop),
1346 other => Err(mei_error(format!("a beam that does {other:?}"))),
1347 }
1348}
1349
1350fn syllable_of(element: &Xml) -> Result<Lyric> {
1353 let text = element
1354 .text()
1355 .ok_or_else(|| mei_error("a <syl> with no text"))?;
1356 let joiner = match element.get("con") {
1357 Some("s") => " ",
1358 Some("d") | None => "-",
1359 Some("t") => "~",
1360 Some("u") => "_",
1361 Some(other) => {
1362 return Err(mei_error(format!("a syllable joined by {other:?}")));
1363 }
1364 };
1365 let (text, syllabic) = match element.get("wordpos") {
1366 Some("i") => (format!("{text}{joiner}"), Some(Syllabic::Begin)),
1367 Some("m") => (format!("{joiner}{text}{joiner}"), Some(Syllabic::Middle)),
1368 Some("t") => (format!("{joiner}{text}"), Some(Syllabic::End)),
1369 None => (text.to_string(), None),
1370 Some(other) => {
1371 return Err(mei_error(format!("a syllable placed at {other:?}")));
1372 }
1373 };
1374 Ok(match syllabic {
1375 Some(syllabic) => {
1376 let mut lyric = Lyric::new(text);
1377 lyric.set_syllabic(syllabic);
1378 lyric
1379 }
1380 None => Lyric::from_raw_text(&text),
1381 })
1382}
1383
1384fn metadata_of(root: &Xml) -> Metadata {
1387 let mut metadata = Metadata::new();
1388 let mut works = Vec::new();
1389 descendants(root, "work", &mut works);
1390 let Some(work) = works.first() else {
1391 return metadata;
1392 };
1393 let statement = child(work, "titleStmt");
1394 let mut title: Option<String> = None;
1395 let mut subtitle: Option<String> = None;
1396 for held in statement
1397 .into_iter()
1398 .flat_map(|held| children(held, "title"))
1399 {
1400 let text = held.text().map(str::to_string);
1401 if held.get("type") == Some("subtitle") {
1402 subtitle = text;
1403 } else if title.is_none() {
1404 title = text;
1405 }
1406 }
1407 if let Some(subtitle) = subtitle.filter(|subtitle| !subtitle.is_empty()) {
1408 title = Some(format!(
1409 "{} ({subtitle})",
1410 title.as_deref().unwrap_or("None")
1411 ));
1412 }
1413 if let Some(title) = title {
1414 metadata.add_text("title", title);
1415 }
1416 if let Some(tempo) = child(work, "tempo") {
1417 metadata.add_text("movementName", tempo.text().unwrap_or("None"));
1418 }
1419 let mut composers: Vec<String> = Vec::new();
1420 if let Some(statement) = statement {
1421 for responsibility in children(statement, "respStmt") {
1422 for person in children(responsibility, "persName") {
1423 if person.get("role") == Some("composer")
1424 && let Some(text) = person.text().filter(|text| !text.is_empty())
1425 {
1426 composers.push(text.to_string());
1427 }
1428 }
1429 }
1430 for composer in children(statement, "composer") {
1431 let text = composer
1432 .text()
1433 .filter(|text| !text.is_empty())
1434 .or_else(|| child(composer, "persName").and_then(Xml::text));
1435 if let Some(text) = text.filter(|text| !text.is_empty()) {
1436 composers.push(text.to_string());
1437 }
1438 }
1439 }
1440 for composer in composers {
1441 metadata.add_contributor("composer", composer);
1442 }
1443 let date = child(work, "history")
1444 .and_then(|history| child(history, "creation"))
1445 .and_then(|creation| child(creation, "date"));
1446 if let Some(date) = date {
1447 let written = date
1448 .get("isodate")
1449 .filter(|text| !text.is_empty())
1450 .or(date.text().filter(|text| !text.is_empty()));
1451 let said = |written: &str| -> Option<String> {
1454 let parts: Vec<&str> = written.split(['-', '/']).collect();
1455 if parts.len() > 3 {
1456 return None;
1457 }
1458 let mut fields = Vec::new();
1459 for (index, part) in parts.iter().enumerate() {
1460 let number: u32 = part.parse().ok()?;
1461 fields.push(if index == 0 {
1462 format!("{number:04}")
1463 } else {
1464 format!("{number:02}")
1465 });
1466 }
1467 fields.resize(3, "--".to_string());
1468 Some(fields.join("/"))
1469 };
1470 if let Some(written) = written {
1471 if let Some(date) = said(written) {
1472 metadata.add_text("dateCreated", date);
1473 }
1474 } else {
1475 let start = date.get("notbefore").or(date.get("startdate"));
1476 let end = date.get("notafter").or(date.get("enddate"));
1477 if let (Some(start), Some(end)) = (start, end)
1478 && let (Some(start), Some(end)) = (said(start), said(end))
1479 {
1480 metadata.add_text("dateCreated", format!("{start} to {end}"));
1481 }
1482 }
1483 }
1484 metadata
1485}
1486
1487pub fn from_mei(document: &str) -> Result<Stream> {
1520 let root = Xml::parse(document).map_err(|_| mei_error("MEI document is not valid XML."))?;
1521 if local(&root.tag) != "mei" {
1522 return Err(mei_error(format!(
1523 "Root element should be <mei> in the MEI namespace, not <{}>.",
1524 root.tag
1525 )));
1526 }
1527 let score = child(&root, "music")
1528 .and_then(|music| {
1529 let mut found = Vec::new();
1530 descendants(music, "score", &mut found);
1531 found.first().copied()
1532 })
1533 .ok_or_else(|| mei_error("an MEI document with no <score> in its <music>"))?;
1534
1535 let mut reader = Reader {
1536 extra: HashMap::new(),
1537 slurs: Vec::new(),
1538 next_uid: 0,
1539 next_slur: 0,
1540 };
1541 reader.preprocess(score);
1542
1543 let mut definitions = Vec::new();
1545 descendants(score, "staffDef", &mut definitions);
1546 let mut parts: Vec<String> = Vec::new();
1547 for definition in definitions {
1548 let name = definition.get("n").unwrap_or("").to_string();
1549 if !parts.contains(&name) {
1550 parts.push(name);
1551 }
1552 }
1553 if parts.is_empty() {
1554 return Err(mei_error(
1555 "There appear to be no <staffDef> tags in this score.",
1556 ));
1557 }
1558
1559 let mut state = SectionState::default();
1560 let parsed = reader.section(score, &parts, &mut state)?;
1561
1562 let mut events = Vec::new();
1565 let mut uids: Vec<Option<usize>> = Vec::new();
1566 for name in &parts {
1567 let mut held = Vec::new();
1568 let mut offset = 0.0;
1569 for thing in parsed.get(name).cloned().unwrap_or_default() {
1570 match thing {
1571 Held::Instrument(instrument) => {
1572 uids.push(None);
1573 held.push(StreamEvent::new(offset, *instrument));
1574 }
1575 Held::Measure(measure) => {
1576 let mut own: Vec<StreamEvent> = measure
1579 .own
1580 .into_iter()
1581 .map(|element| StreamEvent::new(0.0, element))
1582 .collect();
1583 own.sort_by_key(|event| event.element().class_sort_order());
1584 uids.extend(own.iter().map(|_| None));
1585 let mut length: FloatType = 0.0;
1586 for (id, things) in measure.voices {
1587 let mut at = 0.0;
1588 let mut inner = Vec::new();
1589 for thing in things {
1590 uids.push(Some(thing.uid));
1591 let lasts = thing.element.quarter_length();
1592 inner.push(StreamEvent::new(at, thing.element));
1593 at = op_frac(at + lasts);
1594 }
1595 length = length.max(at);
1596 let mut voice = Stream::with_kind(StreamKind::Voice).with_events(inner);
1597 voice.set_id(Some(id));
1598 own.push(StreamEvent::new(0.0, voice));
1599 }
1600 let mut stream = Stream::with_kind(StreamKind::Measure).with_events(own);
1601 stream.set_number(measure.number);
1602 stream.set_left_barline(measure.left);
1603 stream.set_right_barline(measure.right);
1604 held.push(StreamEvent::new(offset, stream));
1605 offset = op_frac(offset + measure.length.unwrap_or(length));
1606 }
1607 }
1608 }
1609 let mut part = Stream::with_kind(StreamKind::Part).with_events(held);
1610 part.set_at_sounding_pitch(Some(false));
1612 events.push(StreamEvent::new(0.0, part));
1613 }
1614 let mut made = Stream::with_kind(StreamKind::Score).with_events(events);
1615 made.set_metadata(Some(metadata_of(&root)));
1616 for (_, joined) in reader.slurs {
1617 let positions: Vec<Option<usize>> = joined
1618 .iter()
1619 .map(|uid| uids.iter().position(|held| *held == Some(*uid)))
1620 .collect();
1621 made.add_spanner(Spanner::with_unplaced(SpannerKind::Slur, positions));
1622 }
1623 Ok(made)
1624}
1625
1626#[cfg(test)]
1627mod tests {
1628 use super::*;
1629
1630 fn document(body: &str) -> String {
1631 format!(
1632 r#"<mei xmlns="http://www.music-encoding.org/ns/mei"><music><score>
1633 <scoreDef meter.count="4" meter.unit="4"><staffGrp>
1634 <staffDef n="1" clef.shape="G" clef.line="2"/>
1635 <staffDef n="2" clef.shape="F" clef.line="4"/>
1636 </staffGrp></scoreDef><section>{body}</section></score></music></mei>"#
1637 )
1638 }
1639
1640 #[test]
1641 fn a_staff_with_nothing_written_rests_through_the_measure() {
1642 let score = from_mei(&document(
1643 r#"<measure n="1"><staff n="1"><layer n="1">
1644 <note pname="c" oct="4" dur="2"/><note pname="d" oct="4" dur="2"/>
1645 </layer></staff></measure>"#,
1646 ))
1647 .unwrap();
1648 let parts = score.parts();
1649 assert_eq!(parts.len(), 2);
1650 let rests: Vec<FloatType> = parts[1]
1651 .recurse()
1652 .into_iter()
1653 .filter(|(_, element)| matches!(element, StreamElement::Rest(_)))
1654 .map(|(_, element)| element.quarter_length())
1655 .collect();
1656 assert_eq!(rests, [4.0]);
1657 }
1658
1659 #[test]
1660 fn a_beam_runs_from_its_first_note_to_its_last() {
1661 let score = from_mei(&document(
1662 r#"<measure n="1"><staff n="1"><layer n="1"><beam>
1663 <note pname="c" oct="4" dur="8"/><note pname="d" oct="4" dur="8"/>
1664 <note pname="e" oct="4" dur="8"/></beam></layer></staff>
1665 <staff n="2"><layer n="1"><mRest/></layer></staff></measure>"#,
1666 ))
1667 .unwrap();
1668 let beams: Vec<Option<BeamType>> = score.parts()[0]
1669 .recurse()
1670 .into_iter()
1671 .filter_map(|(_, element)| match element {
1672 StreamElement::Note(note) => {
1673 Some(note.beams().by_number(1).and_then(|beam| beam.beam_type()))
1674 }
1675 _ => None,
1676 })
1677 .collect();
1678 assert_eq!(
1679 beams,
1680 [
1681 Some(BeamType::Start),
1682 Some(BeamType::Continue),
1683 Some(BeamType::Stop)
1684 ]
1685 );
1686 }
1687
1688 #[test]
1689 fn a_tuplet_scales_its_notes_and_brackets_them() {
1690 let score = from_mei(&document(
1691 r#"<measure n="1"><staff n="1"><layer n="1"><tuplet num="3" numbase="2">
1692 <note pname="c" oct="4" dur="4"/><note pname="d" oct="4" dur="4"/>
1693 <note pname="e" oct="4" dur="4"/></tuplet></layer></staff></measure>"#,
1694 ))
1695 .unwrap();
1696 let lengths: Vec<FloatType> = score.parts()[0]
1697 .notes()
1698 .into_iter()
1699 .map(|(_, element)| element.quarter_length())
1700 .collect();
1701 assert_eq!(lengths.len(), 3);
1702 assert!(
1703 lengths
1704 .iter()
1705 .all(|length| (length - 2.0 / 3.0).abs() < 1e-9)
1706 );
1707 }
1708
1709 #[test]
1710 fn a_tie_written_apart_names_its_notes() {
1711 let score = from_mei(&document(
1712 r##"<measure n="1"><staff n="1"><layer n="1">
1713 <note xml:id="a" pname="c" oct="4" dur="2"/><note xml:id="b" pname="c" oct="4" dur="2"/>
1714 </layer></staff><tie startid="#a" endid="#b"/></measure>"##,
1715 ))
1716 .unwrap();
1717 let ties: Vec<Option<TieType>> = score.parts()[0]
1718 .notes()
1719 .into_iter()
1720 .filter_map(|(_, element)| match element {
1721 StreamElement::Note(note) => Some(note.tie().map(Tie::tie_type)),
1722 _ => None,
1723 })
1724 .collect();
1725 assert_eq!(ties, [Some(TieType::Start), Some(TieType::Stop)]);
1726 }
1727
1728 #[test]
1729 fn what_is_no_mei_is_refused() {
1730 assert!(from_mei("<score-partwise/>").is_err());
1731 assert!(from_mei("not xml at all").is_err());
1732 }
1733}