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, 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
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 fresh_uuid(count: usize) -> String {
70 use std::hash::{BuildHasher, Hasher};
71
72 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#[derive(Clone, Debug)]
101struct Search {
102 end: &'static str,
103 number: u32,
104 base: u32,
105}
106
107#[derive(Clone, Debug)]
110struct Thing {
111 element: StreamElement,
112 uid: usize,
114 search: Option<Search>,
115 whole_measure: bool,
117}
118
119#[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#[derive(Clone, Debug)]
150struct Measure {
151 number: IntegerType,
152 voices: Vec<(String, Vec<Thing>)>,
154 own: Vec<StreamElement>,
156 left: Option<Barline>,
157 right: Option<Barline>,
158 length: Option<FloatType>,
160}
161
162#[derive(Clone, Debug)]
165enum Held {
166 Instrument(Box<Instrument>),
167 Measure(Box<Measure>),
168}
169
170struct Reader {
173 extra: HashMap<String, Vec<(&'static str, String)>>,
175 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
198const 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
260fn 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
278fn 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
321fn 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
369fn 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
400fn 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 let mut diatonic = i64::from(read("trans.diat")?);
413 let semitones = read("trans.semi")?;
414 let wide = i64::from(semitones);
415 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
471fn 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
509fn 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
524fn 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 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 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 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 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 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 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 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 fn chord(&mut self, element: &Xml) -> Result<Thing> {
864 let mut notes = Vec::new();
865 for held in children(element, "note") {
866 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 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 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 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 "barLine" => {
966 let _ = barline_of(held.get("rend").unwrap_or("single"))?;
967 }
968 _ => {}
969 }
970 }
971 Ok(things)
972 }
973
974 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 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 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 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 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 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 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 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 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#[derive(Default)]
1367struct SectionState {
1368 meter: Option<TimeSignature>,
1369 next_left: Option<Barline>,
1370 backup: IntegerType,
1371}
1372
1373fn 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
1393fn 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
1427fn 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 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
1530pub fn from_mei(document: &str) -> Result<Stream> {
1563 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 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 let mut events = Vec::new();
1616 let mut uids: Vec<Option<usize>> = Vec::new();
1617 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 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 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 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 #[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}