Skip to main content

music21_rs/musescore/
read.rs

1//! MuseScore's `.mscx`, read into a score.
2//!
3//! A MuseScore file keeps a score's parts apart from what is written on
4//! their staves: each `<Part>` names its instrument and how many staves it
5//! has, and after the parts comes one `<Staff>` for every staff of the
6//! score, holding its measures. A measure holds a `<voice>` for each of up
7//! to four voices, and a voice is its notes and rests in order, with the
8//! clefs, signatures, texts and marks standing between them. Nothing in the
9//! file says where a note starts; that is worked out by adding up the
10//! lengths of what comes before it, a `<location>` moving the place along
11//! where a mark stands between two notes.
12
13use std::collections::HashMap;
14
15use num::rational::Ratio;
16use num::{One, ToPrimitive, Zero};
17
18use super::beams::{self, BeamMode, Member};
19use crate::articulations::{Articulation, ArticulationKind, Finger};
20use crate::bar::{Barline, BarlineType, Ending, RepeatDirection};
21use crate::chord::Chord;
22use crate::chordsymbol::ChordSymbol;
23use crate::clef::Clef;
24use crate::defaults::{FloatType, IntegerType};
25use crate::duration::{
26    Duration, DurationType, Grace, Tuplet, TupletBracket, TupletShow, TupletType,
27};
28use crate::dynamics::Dynamic;
29use crate::error::{Error, Result};
30use crate::expressions::{
31    ArpeggioType, Expression, Fermata, FermataType, Ornament, OrnamentDelay, OrnamentKind,
32    TextExpression,
33};
34use crate::instrument::{Instrument, SearchLanguage};
35use crate::interval::Interval;
36use crate::key::KeySignature;
37use crate::makenotation::op_frac;
38use crate::metadata::{Metadata, MetadataValue};
39use crate::meter::TimeSignature;
40use crate::notation::{
41    Beams, Lyric, NoteSize, Notehead, Placement, StemDirection, Syllabic, Tie, TieType,
42};
43use crate::note::Note;
44use crate::pitch::{Accidental, Pitch};
45use crate::repeat::{RepeatExpression, RepeatExpressionKind};
46use crate::rest::Rest;
47use crate::spanner::{Pedal, PedalForm, PedalType, Spanner, SpannerKind};
48use crate::stream::{BarTogether, StaffGroup, Stream, StreamElement, StreamEvent, StreamKind};
49use crate::tempo::MetronomeMark;
50use crate::volume::Volume;
51use crate::xml::Xml;
52
53/// A length or a place in time, in whole notes, as MuseScore counts.
54type Frac = Ratio<i64>;
55
56fn mscx_error(message: impl Into<String>) -> Error {
57    Error::MuseScore(message.into())
58}
59
60fn refused(what: impl std::fmt::Display) -> Error {
61    mscx_error(format!("{what} cannot be read yet"))
62}
63
64/// A fraction as MuseScore writes one: `3/4`, or a whole number.
65fn fraction(text: &str) -> Result<Frac> {
66    let text = text.trim();
67    let bad = || mscx_error(format!("{text:?} is not a fraction"));
68    match text.split_once('/') {
69        Some((numerator, denominator)) => {
70            let numerator: i64 = numerator.trim().parse().map_err(|_| bad())?;
71            let denominator: i64 = denominator.trim().parse().map_err(|_| bad())?;
72            if denominator == 0 {
73                return Err(bad());
74            }
75            Ok(Frac::new(numerator, denominator))
76        }
77        None => Ok(Frac::from_integer(text.parse().map_err(|_| bad())?)),
78    }
79}
80
81fn integer(element: &Xml) -> Result<i64> {
82    let text = element.stripped();
83    text.parse()
84        .map_err(|_| mscx_error(format!("<{}> holds {text:?}, not a number", element.tag)))
85}
86
87fn child_integer(element: &Xml, tag: &str) -> Result<Option<i64>> {
88    element.find(tag).map(integer).transpose()
89}
90
91fn flag(element: &Xml, tag: &str) -> bool {
92    element
93        .find(tag)
94        .is_some_and(|found| found.stripped() != "0" && found.stripped() != "false")
95}
96
97/// A length in quarter notes, snapped as music21 snaps one.
98fn quarters(value: Frac) -> FloatType {
99    op_frac((value * 4).to_f64().unwrap_or(0.0))
100}
101
102/// A place in MuseScore's ticks, 480 to a quarter.
103fn ticks(value: Frac) -> i64 {
104    (value * beams::WHOLE).floor().to_integer()
105}
106
107/// Text as MuseScore writes it, its formatting taken off and each symbol
108/// read as the character that draws it.
109fn plain_text(element: &Xml) -> Result<String> {
110    let mut out = String::new();
111    plain_into(element, &mut out)?;
112    Ok(out)
113}
114
115fn plain_into(element: &Xml, out: &mut String) -> Result<()> {
116    if element.tag == "sym" {
117        out.push(symbol_named(element.text().unwrap_or("").trim())?);
118        return Ok(());
119    }
120    // An older file wrote a name as a small HTML page.
121    if matches!(element.tag.as_str(), "head" | "style" | "meta" | "title") {
122        return Ok(());
123    }
124    if element.tag == "br" {
125        out.push('\n');
126        return Ok(());
127    }
128    if let Some(text) = element.text() {
129        out.push_str(text);
130    }
131    for child in &element.children {
132        plain_into(child, out)?;
133        if let Some(tail) = child.tail() {
134            out.push_str(tail);
135        }
136    }
137    Ok(())
138}
139
140/// The character a symbol inside a text is drawn with: its place in the
141/// Standard Music Font Layout, which is what MuseScore names its symbols by.
142fn symbol_named(name: &str) -> Result<char> {
143    Ok(match name {
144        "segno" => '\u{E047}',
145        "coda" => '\u{E048}',
146        "codaSquare" => '\u{E049}',
147        "segnoSerpent1" => '\u{E04A}',
148        "segnoSerpent2" => '\u{E04B}',
149        "accidentalFlat" => '\u{E260}',
150        "accidentalNatural" => '\u{E261}',
151        "accidentalSharp" => '\u{E262}',
152        "accidentalDoubleSharp" => '\u{E263}',
153        "accidentalDoubleFlat" => '\u{E264}',
154        "dynamicPiano" => '\u{E520}',
155        "dynamicMezzo" => '\u{E521}',
156        "dynamicForte" => '\u{E522}',
157        "dynamicRinforzando" => '\u{E523}',
158        "dynamicSforzando" => '\u{E524}',
159        "dynamicZ" => '\u{E525}',
160        "dynamicNiente" => '\u{E526}',
161        "keyboardPedalPed" => '\u{E650}',
162        "keyboardPedalUp" => '\u{E655}',
163        "metNoteDoubleWhole" => '\u{ECA0}',
164        "metNoteWhole" => '\u{ECA2}',
165        "metNoteHalfUp" => '\u{ECA3}',
166        "metNoteHalfDown" => '\u{ECA4}',
167        "metNoteQuarterUp" => '\u{ECA5}',
168        "metNoteQuarterDown" => '\u{ECA6}',
169        "metNote8thUp" => '\u{ECA7}',
170        "metNote8thDown" => '\u{ECA8}',
171        "metNote16thUp" => '\u{ECA9}',
172        "metNote16thDown" => '\u{ECAA}',
173        "metAugmentationDot" => '\u{ECB7}',
174        "space" => ' ',
175        other => return Err(refused(format!("The symbol {other:?} in a text"))),
176    })
177}
178
179// ------------------------------------------------------------ vocabulary
180
181/// A written value by MuseScore's name for it, with its length in whole
182/// notes and its place in MuseScore's order of values.
183fn duration_named(name: &str) -> Result<(DurationType, Frac, u8)> {
184    Ok(match name {
185        "long" => (DurationType::Longa, Frac::from_integer(4), 0),
186        "breve" => (DurationType::Breve, Frac::from_integer(2), 1),
187        "whole" => (DurationType::Whole, Frac::one(), 2),
188        "half" => (DurationType::Half, Frac::new(1, 2), 3),
189        "quarter" => (DurationType::Quarter, Frac::new(1, 4), 4),
190        "eighth" => (DurationType::Eighth, Frac::new(1, 8), 5),
191        "16th" => (DurationType::Sixteenth, Frac::new(1, 16), 6),
192        "32nd" => (DurationType::ThirtySecond, Frac::new(1, 32), 7),
193        "64th" => (DurationType::SixtyFourth, Frac::new(1, 64), 8),
194        "128th" => (DurationType::HundredTwentyEighth, Frac::new(1, 128), 9),
195        "256th" => (DurationType::TwoHundredFiftySixth, Frac::new(1, 256), 10),
196        "512th" => (DurationType::FiveHundredTwelfth, Frac::new(1, 512), 11),
197        "1024th" => (DurationType::TenTwentyFourth, Frac::new(1, 1024), 12),
198        other => return Err(mscx_error(format!("a note of the value {other:?}"))),
199    })
200}
201
202fn dotted(length: Frac, dots: u32) -> Frac {
203    let mut total = length;
204    let mut added = length;
205    for _ in 0..dots {
206        added /= 2;
207        total += added;
208    }
209    total
210}
211
212/// A clef by MuseScore's name: the sign and line MusicXML writes it with,
213/// and how many octaves it sounds away.
214fn clef_named(name: &str) -> Result<Clef> {
215    let (sign, line, octaves) = match name {
216        "G" | "G8vbp" | "C_19C" => ("G", 2, 0),
217        "G15mb" => ("G", 2, -2),
218        "G8vb" | "G8vbo" | "G8vbc" => ("G", 2, -1),
219        "G8va" => ("G", 2, 1),
220        "G15ma" => ("G", 2, 2),
221        "G1" => ("G", 1, 0),
222        "C1" | "C1_F18C" | "C1_F20C" => ("C", 1, 0),
223        "C2" => ("C", 2, 0),
224        "C3" | "C3_F18C" | "C3_F20C" => ("C", 3, 0),
225        "C4" | "C4_F18C" | "C4_F20C" => ("C", 4, 0),
226        "C4_8VB" => ("C", 4, -1),
227        "C5" => ("C", 5, 0),
228        "F" | "F_F18C" | "F_19C" => ("F", 4, 0),
229        "F15mb" => ("F", 4, -2),
230        "F8vb" => ("F", 4, -1),
231        "F8va" => ("F", 4, 1),
232        "F15ma" => ("F", 4, 2),
233        "F3" => ("F", 3, 0),
234        "F5" => ("F", 5, 0),
235        "PERC" | "PERC2" => return Clef::from_string("percussion", 0),
236        "TAB" | "TAB4" | "TAB2" | "TAB4_SERIF" => return Err(refused("A tablature clef")),
237        other => return Err(mscx_error(format!("a clef of the kind {other:?}"))),
238    };
239    Clef::from_string(&format!("{sign}{line}"), octaves)
240}
241
242/// The accidental a MuseScore accidental draws, by music21's name.
243fn accidental_named(subtype: &str) -> Result<&'static str> {
244    Ok(match subtype {
245        "accidentalSharp" => "sharp",
246        "accidentalFlat" => "flat",
247        "accidentalNatural" => "natural",
248        "accidentalDoubleSharp" | "accidentalSharpSharp" => "double-sharp",
249        "accidentalDoubleFlat" => "double-flat",
250        "accidentalTripleSharp" => "triple-sharp",
251        "accidentalTripleFlat" => "triple-flat",
252        "accidentalNaturalSharp" => "natural-sharp",
253        "accidentalNaturalFlat" => "natural-flat",
254        other => return Err(refused(format!("The accidental {other:?}"))),
255    })
256}
257
258/// The spelling a tonal pitch class stands for: MuseScore's `tpc`, a place on
259/// the line of fifths where C is fourteen.
260fn spelling(tpc: i64) -> Result<(char, i64)> {
261    if !(-1..=33).contains(&tpc) {
262        return Err(mscx_error(format!("the tonal pitch class {tpc}")));
263    }
264    let step = b"FCGDAEB"[((tpc + 1) % 7) as usize] as char;
265    let alter = (tpc + 1) / 7 - 2;
266    Ok((step, alter))
267}
268
269fn natural_semitone(step: char) -> i64 {
270    match step {
271        'C' => 0,
272        'D' => 2,
273        'E' => 4,
274        'F' => 5,
275        'G' => 7,
276        'A' => 9,
277        _ => 11,
278    }
279}
280
281/// The letter and octave of a pitch, from its MIDI number and its spelling.
282fn pitch_of(midi: i64, tpc: i64) -> Result<Pitch> {
283    let (step, alter) = spelling(tpc)?;
284    let natural = midi - alter;
285    let octave = (natural - natural_semitone(step)).div_euclid(12) - 1;
286    Pitch::from_name(format!("{step}{octave}"))
287}
288
289// ------------------------------------------------------------ what is read
290
291/// A tuplet of one voice of one measure.
292#[derive(Clone, Debug)]
293struct TupletRead {
294    actual: u32,
295    normal: u32,
296    base: (DurationType, u32),
297    /// MuseScore's `bracketType`: 0 as the beams decide, 1 a bracket, 2 none.
298    bracket: i64,
299    /// MuseScore's `numberType`: 0 the number, 1 the ratio, 2 nothing.
300    number: i64,
301    placement: Option<Placement>,
302    parent: Option<usize>,
303    /// What it holds in order: notes and rests by their index among the
304    /// voice's notes, tuplets by their own.
305    elements: Vec<Held>,
306}
307
308#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309enum Held {
310    Note(usize),
311    Tuplet(usize),
312}
313
314#[derive(Clone, Copy, Debug, PartialEq, Eq)]
315enum GraceKind {
316    Acciaccatura,
317    Appoggiatura,
318    Before,
319    After,
320}
321
322#[derive(Clone, Debug)]
323struct NoteRead {
324    pitch: Pitch,
325    tie_start: bool,
326    tie_stop: bool,
327    /// Which way the tie it starts curves, where the file says.
328    tie_placement: Option<Placement>,
329    /// How hard it is struck, of 127, where the file says.
330    velocity: Option<i64>,
331    hidden: bool,
332    small: bool,
333    /// The shape of its head, where it is not the usual one.
334    head: Option<Notehead>,
335    /// Whether its head is filled in, where the file fixes that.
336    head_filled: Option<bool>,
337    /// The fingerings written on it.
338    fingerings: Vec<Articulation>,
339    /// The colour it is drawn in, where that is not the usual one.
340    color: Option<String>,
341}
342
343#[derive(Clone, Debug)]
344struct LyricRead {
345    number: IntegerType,
346    syllabic: Option<Syllabic>,
347    text: String,
348}
349
350/// A note, chord or rest as it was read.
351#[derive(Clone, Debug)]
352struct ChordRest {
353    tick: Frac,
354    /// How long it lasts, in whole notes.
355    length: Frac,
356    value: Option<(DurationType, u32)>,
357    order: u8,
358    measure_rest: bool,
359    is_rest: bool,
360    tuplet: Option<usize>,
361    mode: BeamMode,
362    grace: Option<GraceKind>,
363    /// Its place among the grace notes of its note, as the file counts.
364    grace_index: usize,
365    graces_before: Vec<ChordRest>,
366    graces_after: Vec<ChordRest>,
367    notes: Vec<NoteRead>,
368    hidden: bool,
369    small: bool,
370    stem: StemDirection,
371    /// Whether it is drawn with no stem.
372    no_stem: bool,
373    /// The way the stems of the beam starting on it go, where a beam is
374    /// written out before it.
375    beam_stem: StemDirection,
376    lyrics: Vec<LyricRead>,
377    articulations: Vec<Articulation>,
378    /// Ornaments and an arpeggio, in the order written.
379    expressions: Vec<Expression>,
380    fermatas: Vec<Fermata>,
381    step_shift: IntegerType,
382    staff_move: i64,
383    /// What spanners know it by.
384    uid: usize,
385}
386
387/// A spanner as it was started: what it is, where it starts and where the
388/// file says it ends.
389#[derive(Clone, Debug)]
390struct SpannerRead {
391    kind: SpannerStart,
392    start: Position,
393    end: Position,
394}
395
396#[derive(Clone, Debug)]
397enum SpannerStart {
398    Slur(Option<Placement>, Option<&'static str>),
399    Wedge(SpannerKind),
400    Pedal(Pedal),
401    Volta { numbers: Vec<u32> },
402}
403
404/// A place in the score: a measure, a moment in it, a track.
405#[derive(Clone, Copy, Debug, PartialEq, Eq)]
406struct Position {
407    measure: i64,
408    tick: Frac,
409    track: usize,
410    /// Which of the grace notes leaning on the note there, where it is one
411    /// of them and not the note itself.
412    grace: Option<usize>,
413}
414
415#[derive(Clone, Debug)]
416enum What {
417    ChordRest(Box<ChordRest>),
418    Clef(Clef),
419    Key(StreamElement),
420    Meter(TimeSignature),
421    Element(StreamElement),
422    /// A barline, and whether a fermata stands on it.
423    Barline(Barline, bool),
424}
425
426#[derive(Clone, Debug)]
427struct Event {
428    tick: Frac,
429    what: What,
430}
431
432/// One voice of one measure of one staff.
433#[derive(Clone, Debug, Default)]
434struct VoiceRead {
435    events: Vec<Event>,
436    tuplets: Vec<TupletRead>,
437}
438
439/// One measure of one staff.
440#[derive(Clone, Debug, Default)]
441struct StaffMeasure {
442    voices: Vec<VoiceRead>,
443    len: Option<Frac>,
444    irregular: bool,
445    number_offset: i64,
446    start_repeat: bool,
447    end_repeat: Option<u32>,
448    /// Whether a section ends with it, the numbering starting again after.
449    section_break: bool,
450    /// Whether a section ended just before it.
451    starts_section: bool,
452    /// The signs and words saying where to go next: those standing at its
453    /// start, and those at its end.
454    marks_at_start: Vec<StreamElement>,
455    marks_at_end: Vec<StreamElement>,
456}
457
458/// A part, as the head of the file describes it.
459#[derive(Clone, Debug)]
460struct PartRead {
461    staves: usize,
462    /// The global index of its first staff.
463    first_staff: usize,
464    name: Option<String>,
465    abbreviation: Option<String>,
466    name_hidden: bool,
467    abbreviation_hidden: bool,
468    instrument: Instrument,
469    default_clefs: Vec<String>,
470    /// The brackets starting on its first staff, each its kind and how many
471    /// staves it joins, the innermost first.
472    brackets: Vec<(i64, usize)>,
473    /// Whether any of its staves starts a bracket.
474    bracket_found: bool,
475    /// How far the written notes stand from the sounding ones: diatonic
476    /// steps and semitones.
477    transposition: (i64, i64),
478}
479
480// ----------------------------------------------------------------- reading
481
482/// What reading a staff needs of the measures across the score.
483#[derive(Clone, Debug)]
484struct Grid {
485    /// Where each measure starts, in whole notes from the top.
486    starts: Vec<Frac>,
487    lengths: Vec<Frac>,
488    meters: Vec<(i64, i64)>,
489}
490
491struct Reader {
492    /// Whether the file is in a format older than 4.1.
493    old_format: bool,
494    /// Whether a marker is of the kind its label names. From format 4.6 on
495    /// it says its kind apart, and one that says none marks the end.
496    markers_by_label: bool,
497    next_uid: usize,
498    spanners: Vec<SpannerRead>,
499}
500
501impl Reader {
502    fn uid(&mut self) -> usize {
503        self.next_uid += 1;
504        self.next_uid
505    }
506
507    /// A staff's measures, each with its voices read.
508    fn staff(
509        &mut self,
510        staff: &Xml,
511        staff_index: usize,
512        transposition: (i64, i64),
513    ) -> Result<Vec<StaffMeasure>> {
514        let mut measures: Vec<StaffMeasure> = Vec::new();
515        let mut section_ended = false;
516        for element in &staff.children {
517            match element.tag.as_str() {
518                // The measure MuseScore draws for a run of empty ones stands
519                // in the file beside the measures it covers, which are the
520                // music.
521                "Measure" if element.find("multiMeasureRest").is_some() => {}
522                "Measure" => {
523                    let index = measures.len() as i64;
524                    let mut measure = self.measure(element, staff_index, index, transposition)?;
525                    measure.starts_section = std::mem::take(&mut section_ended);
526                    section_ended = measure.section_break;
527                    measures.push(measure);
528                }
529                // Frames hold titles and text for the page; a section may end
530                // on one.
531                "VBox" | "HBox" | "TBox" | "FBox" => {
532                    if element.find_all("LayoutBreak").any(ends_section) {
533                        section_ended = true;
534                    }
535                }
536                "eid" => {}
537                other => return Err(mscx_error(format!("<{other}> in a staff"))),
538            }
539        }
540        Ok(measures)
541    }
542
543    fn measure(
544        &mut self,
545        element: &Xml,
546        staff_index: usize,
547        index: i64,
548        transposition: (i64, i64),
549    ) -> Result<StaffMeasure> {
550        let mut measure = StaffMeasure {
551            len: element.get("len").map(fraction).transpose()?,
552            ..StaffMeasure::default()
553        };
554        let mut voice = 0usize;
555        for held in &element.children {
556            match held.tag.as_str() {
557                "voice" => {
558                    let track = staff_index * 4 + voice;
559                    let read = self.voice(held, index, track, transposition)?;
560                    measure.voices.push(read);
561                    voice += 1;
562                }
563                "irregular" => measure.irregular = held.stripped() != "0",
564                "noOffset" => measure.number_offset = integer(held)?,
565                "startRepeat" => measure.start_repeat = true,
566                "endRepeat" => measure.end_repeat = Some(integer(held)?.max(0) as u32),
567                "LayoutBreak" => {
568                    if ends_section(held) {
569                        measure.section_break = true;
570                    }
571                }
572                "measureRepeatCount" => {
573                    return Err(refused(format!("<{}>", held.tag)));
574                }
575                "Marker" if held.child_text("visible") != "0" => {
576                    match marker_of(held, self.markers_by_label)? {
577                        (false, mark) => measure.marks_at_start.push(mark),
578                        (true, mark) => measure.marks_at_end.push(mark),
579                    }
580                }
581                "Jump" if held.child_text("visible") != "0" => {
582                    measure.marks_at_end.push(jump_of(held)?);
583                }
584                "Marker" | "Jump" => {}
585                // What places the measure on the page.
586                "eid"
587                | "linkedMain"
588                | "stretch"
589                | "measureNumberMode"
590                | "breakMultiMeasureRest"
591                | "vspacer"
592                | "vspacerDown"
593                | "vspacerUp"
594                | "vspacerFixed"
595                | "visible"
596                | "stemless"
597                | "hideIfEmpty"
598                | "MeasureNumber"
599                | "MMRestRange"
600                | "SystemDivider"
601                | "Spacer"
602                | "StaffTypeChange" => {}
603                other => return Err(mscx_error(format!("<{other}> in a measure"))),
604            }
605        }
606        Ok(measure)
607    }
608
609    fn voice(
610        &mut self,
611        element: &Xml,
612        measure: i64,
613        track: usize,
614        transposition: (i64, i64),
615    ) -> Result<VoiceRead> {
616        let mut read = VoiceRead::default();
617        let mut tick = Frac::zero();
618        let mut tuplet: Option<usize> = None;
619        let mut graces: Vec<ChordRest> = Vec::new();
620        let mut fermatas: Vec<Fermata> = Vec::new();
621        let mut beam_stem = StemDirection::Unspecified;
622        let mut notes = 0usize;
623        for held in &element.children {
624            match held.tag.as_str() {
625                "location" => {
626                    if let Some(fractions) = held.find("fractions") {
627                        tick += fraction(fractions.stripped())?;
628                    }
629                    if held.find("measures").is_some() {
630                        return Err(mscx_error("a <location> in a voice that moves measures"));
631                    }
632                }
633                "Chord" | "Rest" => {
634                    let mut chord_rest =
635                        self.chord_rest(held, tick, tuplet, &read.tuplets, transposition)?;
636                    chord_rest.beam_stem =
637                        std::mem::replace(&mut beam_stem, StemDirection::Unspecified);
638                    let grace = chord_rest.grace.map(|_| graces.len());
639                    self.spanners_of(
640                        held,
641                        Position {
642                            measure,
643                            tick,
644                            track,
645                            grace,
646                        },
647                    )?;
648                    if let Some(index) = grace {
649                        chord_rest.grace_index = index;
650                        graces.push(*chord_rest);
651                        continue;
652                    }
653                    chord_rest.fermatas = std::mem::take(&mut fermatas);
654                    // Graces before the note come first, those after it
655                    // follow it.
656                    let (after, before): (Vec<ChordRest>, Vec<ChordRest>) =
657                        std::mem::take(&mut graces)
658                            .into_iter()
659                            .partition(|grace| grace.grace == Some(GraceKind::After));
660                    chord_rest.graces_before = before;
661                    // MuseScore keeps the graces after a note last first.
662                    chord_rest.graces_after = after.into_iter().rev().collect();
663                    if let Some(open) = tuplet {
664                        read.tuplets[open].elements.push(Held::Note(notes));
665                    }
666                    notes += 1;
667                    let length = chord_rest.length;
668                    read.events.push(Event {
669                        tick,
670                        what: What::ChordRest(chord_rest),
671                    });
672                    tick += length;
673                }
674                "Tuplet" => {
675                    let made = tuplet_of(held, tuplet)?;
676                    let index = read.tuplets.len();
677                    if let Some(open) = tuplet {
678                        read.tuplets[open].elements.push(Held::Tuplet(index));
679                    }
680                    read.tuplets.push(made);
681                    tuplet = Some(index);
682                }
683                "endTuplet" => {
684                    let open =
685                        tuplet.ok_or_else(|| mscx_error("an <endTuplet/> with no tuplet"))?;
686                    tuplet = read.tuplets[open].parent;
687                }
688                "Clef" => {
689                    let name = match held.find("concertClefType") {
690                        Some(clef) => clef.stripped(),
691                        None => held.child_text("subtype"),
692                    };
693                    let name = match held.find("transposingClefType") {
694                        Some(written) => written.stripped(),
695                        None => name,
696                    };
697                    read.events.push(Event {
698                        tick,
699                        what: What::Clef(clef_named(name)?),
700                    });
701                }
702                "KeySig" => {
703                    if !flag(held, "isCourtesy") {
704                        read.events.push(Event {
705                            tick,
706                            what: What::Key(key_of(held, transposition, self.old_format)?),
707                        });
708                    }
709                }
710                "TimeSig" => {
711                    if !flag(held, "isCourtesy") {
712                        read.events.push(Event {
713                            tick,
714                            what: What::Meter(meter_of(held)?),
715                        });
716                    }
717                }
718                "BarLine" => {
719                    // A fermata written before a barline stands on it.
720                    let fermata = !std::mem::take(&mut fermatas).is_empty();
721                    if let Some(barline) = barline_of(held)? {
722                        read.events.push(Event {
723                            tick,
724                            what: What::Barline(barline, fermata),
725                        });
726                    }
727                }
728                "Fermata" => fermatas.push(fermata_of(held)),
729                // A breath is taken after the note before it.
730                "Breath" => {
731                    let mark = breath_of(held)?;
732                    let before =
733                        read.events
734                            .iter_mut()
735                            .rev()
736                            .find_map(|event| match &mut event.what {
737                                What::ChordRest(before) => Some(before),
738                                _ => None,
739                            });
740                    match before {
741                        Some(before) => before.articulations.push(mark),
742                        None => return Err(mscx_error("a breath mark with no note before it")),
743                    }
744                }
745                "Sticking" | "PlayTechAnnotation" if held.child_text("visible") == "0" => {}
746                "Sticking" | "PlayTechAnnotation" => {
747                    let default = if held.tag == "Sticking" {
748                        Placement::Below
749                    } else {
750                        Placement::Above
751                    };
752                    if let Some(element) = words_of(held, default)? {
753                        read.events.push(Event {
754                            tick,
755                            what: What::Element(element),
756                        });
757                    }
758                }
759                // A mark that is hidden has nothing here to say so with, and
760                // is left out, as MuseScore leaves it out of what it
761                // exports.
762                "Dynamic" | "StaffText" | "SystemText" | "Expression" | "Text"
763                    if held.child_text("visible") == "0" => {}
764                "Dynamic" => {
765                    let mut dynamic = Dynamic::new(held.child_text("subtype"));
766                    dynamic.set_placement(Some(placement_of(held, Placement::Below)));
767                    read.events.push(Event {
768                        tick,
769                        what: What::Element(dynamic.into()),
770                    });
771                }
772                "Tempo" => {
773                    for element in tempo_of(held)? {
774                        read.events.push(Event {
775                            tick,
776                            what: What::Element(element),
777                        });
778                    }
779                }
780                "StaffText" | "SystemText" | "Expression" | "Text" => {
781                    let default = if held.tag == "Expression" {
782                        Placement::Below
783                    } else {
784                        Placement::Above
785                    };
786                    if let Some(element) = words_of(held, default)? {
787                        read.events.push(Event {
788                            tick,
789                            what: What::Element(element),
790                        });
791                    }
792                }
793                "Harmony" => {
794                    read.events.push(Event {
795                        tick,
796                        what: What::Element(harmony_of(held)?.into()),
797                    });
798                }
799                "Spanner" => self.spanner(
800                    held,
801                    Position {
802                        measure,
803                        tick,
804                        track,
805                        grace: None,
806                    },
807                )?,
808                // A beam written out says which way its stems go; which
809                // notes it joins is still the beam modes' to say.
810                "Beam" => {
811                    beam_stem = match held.child_text("StemDirection") {
812                        "up" => StemDirection::Up,
813                        "down" => StemDirection::Down,
814                        _ => StemDirection::Unspecified,
815                    };
816                }
817                // What is drawn and not played.
818                "Symbol" | "Image" | "RehearsalMark" | "StaffState" | "Ambitus" | "eid"
819                | "LayoutBreak" | "Segment" | "PlayCountText" => {}
820                other => return Err(refused(format!("A <{other}>"))),
821            }
822        }
823        if !graces.is_empty() {
824            return Err(mscx_error("grace notes with no note to lean on"));
825        }
826        Ok(read)
827    }
828
829    /// A `<Chord>` or `<Rest>`.
830    fn chord_rest(
831        &mut self,
832        element: &Xml,
833        tick: Frac,
834        tuplet: Option<usize>,
835        tuplets: &[TupletRead],
836        transposition: (i64, i64),
837    ) -> Result<Box<ChordRest>> {
838        let is_rest = element.tag == "Rest";
839        let written = element.child_text("durationType");
840        let dots = child_integer(element, "dots")?.unwrap_or(0).max(0) as u32;
841        let (value, base, order, measure_rest) = if written == "measure" {
842            let length = element
843                .find("duration")
844                .map(|duration| fraction(duration.stripped()))
845                .transpose()?
846                .ok_or_else(|| mscx_error("a measure rest that does not say how long it is"))?;
847            (None, length, 0, true)
848        } else {
849            let (kind, length, order) = duration_named(written)?;
850            (Some((kind, dots)), dotted(length, dots), order, false)
851        };
852        // A tuplet shortens what it holds by its ratio, and one inside
853        // another by both.
854        let mut length = base;
855        let mut open = tuplet;
856        while let Some(index) = open {
857            let held = &tuplets[index];
858            length = length * Frac::from_integer(i64::from(held.normal))
859                / Frac::from_integer(i64::from(held.actual));
860            open = held.parent;
861        }
862        let grace = [
863            ("acciaccatura", GraceKind::Acciaccatura),
864            ("appoggiatura", GraceKind::Appoggiatura),
865            ("grace4", GraceKind::Before),
866            ("grace16", GraceKind::Before),
867            ("grace32", GraceKind::Before),
868            ("grace8after", GraceKind::After),
869            ("grace16after", GraceKind::After),
870            ("grace32after", GraceKind::After),
871        ]
872        .into_iter()
873        .find(|(tag, _)| element.find(tag).is_some())
874        .map(|(_, kind)| kind);
875        let mut read = ChordRest {
876            tick,
877            length: if grace.is_some() {
878                Frac::zero()
879            } else {
880                length
881            },
882            value,
883            order,
884            measure_rest,
885            is_rest,
886            tuplet: if grace.is_some() { None } else { tuplet },
887            mode: BeamMode::Auto,
888            grace,
889            grace_index: 0,
890            graces_before: Vec::new(),
891            graces_after: Vec::new(),
892            notes: Vec::new(),
893            hidden: element.child_text("visible") == "0",
894            small: flag(element, "small"),
895            stem: StemDirection::Unspecified,
896            no_stem: false,
897            beam_stem: StemDirection::Unspecified,
898            lyrics: Vec::new(),
899            articulations: Vec::new(),
900            expressions: Vec::new(),
901            fermatas: Vec::new(),
902            step_shift: 0,
903            staff_move: child_integer(element, "staffMove")?.unwrap_or(0),
904            uid: self.uid(),
905        };
906        for held in &element.children {
907            match held.tag.as_str() {
908                "BeamMode" => {
909                    read.mode = BeamMode::from_name(held.stripped()).ok_or_else(|| {
910                        mscx_error(format!("the beam mode {:?}", held.stripped()))
911                    })?;
912                }
913                "StemDirection" => {
914                    read.stem = match held.stripped() {
915                        "up" => StemDirection::Up,
916                        "down" => StemDirection::Down,
917                        _ => StemDirection::Unspecified,
918                    };
919                }
920                "Stem" if held.child_text("visible") == "0" => read.no_stem = true,
921                "noStem" if held.stripped() != "0" => read.no_stem = true,
922                "Note" => read.notes.push(note_of(held, transposition)?),
923                "Lyrics" => read.lyrics.push(lyric_of(held)?),
924                "Articulation" => {
925                    if let Some(articulation) = articulation_of(held)? {
926                        read.articulations.push(articulation);
927                    }
928                }
929                "offset" if is_rest => {
930                    let y: FloatType = held.get("y").and_then(|y| y.parse().ok()).unwrap_or(0.0);
931                    let steps = -2.0 * y;
932                    read.step_shift = if steps > 0.0 {
933                        (steps + 0.5) as IntegerType
934                    } else {
935                        (steps - 0.5) as IntegerType
936                    };
937                }
938                "Ornament" => read.expressions.push(ornament_of(held)?),
939                "Arpeggio" => read.expressions.push(arpeggio_of(held)?),
940                "Tremolo" | "TremoloSingleChord" | "TremoloTwoChord" | "ChordLine" => {
941                    return Err(refused(format!("A <{}>", held.tag)));
942                }
943                // Read elsewhere, or only drawn.
944                "durationType" | "dots" | "duration" | "visible" | "small" | "staffMove"
945                | "acciaccatura" | "appoggiatura" | "grace4" | "grace16" | "grace32"
946                | "grace8after" | "grace16after" | "grace32after" | "Spanner" | "eid" | "Stem"
947                | "Hook" | "NoteDot" | "Beam" | "offset" | "linkedMain" | "stemDirection"
948                | "noStem" | "showStemSlash" | "combineVoice" | "ChordRest" | "StemSlash" => {}
949                other => return Err(refused(format!("A <{other}> in a chord"))),
950            }
951        }
952        if !is_rest && read.notes.is_empty() {
953            return Err(mscx_error("a chord with no notes"));
954        }
955        Ok(Box::new(read))
956    }
957
958    /// The spanners a note or rest starts: a slur written inside it.
959    fn spanners_of(&mut self, element: &Xml, here: Position) -> Result<()> {
960        for held in element.find_all("Spanner") {
961            self.spanner(held, here)?;
962        }
963        Ok(())
964    }
965
966    /// A `<Spanner>`: where one starts, with where it ends; the end itself
967    /// says nothing that the start did not.
968    fn spanner(&mut self, element: &Xml, here: Position) -> Result<()> {
969        let kind = element.get("type").unwrap_or("");
970        let Some(next) = element.find("next") else {
971            return Ok(());
972        };
973        let body = element.find(kind);
974        if matches!(kind, "HairPin" | "Pedal")
975            && body.is_some_and(|body| body.child_text("visible") == "0")
976        {
977            return Ok(());
978        }
979        let start = SpannerStart::from(kind, body)?;
980        let Some(start) = start else {
981            return Ok(());
982        };
983        let end = moved(here, next.find("location"))?;
984        self.spanners.push(SpannerRead {
985            kind: start,
986            start: here,
987            end,
988        });
989        Ok(())
990    }
991}
992
993impl SpannerStart {
994    fn from(kind: &str, body: Option<&Xml>) -> Result<Option<Self>> {
995        Ok(Some(match kind {
996            "Slur" => Self::Slur(
997                match body.map_or("", |body| body.child_text("up")) {
998                    "up" => Some(Placement::Above),
999                    "down" => Some(Placement::Below),
1000                    _ => None,
1001                },
1002                match body.map_or("", |body| body.child_text("lineType")) {
1003                    "1" => Some("dotted"),
1004                    "2" | "3" => Some("dashed"),
1005                    _ => None,
1006                },
1007            ),
1008            "HairPin" => {
1009                let subtype = body.map_or("0", |body| body.child_text("subtype"));
1010                match subtype {
1011                    "0" | "" => Self::Wedge(SpannerKind::Crescendo),
1012                    "1" => Self::Wedge(SpannerKind::Diminuendo),
1013                    other => {
1014                        return Err(refused(format!("A hairpin of the kind {other}")));
1015                    }
1016                }
1017            }
1018            "Volta" => {
1019                let body = body.ok_or_else(|| mscx_error("a volta that says nothing"))?;
1020                let numbers = body
1021                    .child_text("endings")
1022                    .split(',')
1023                    .map(|number| number.trim().parse::<u32>())
1024                    .collect::<std::result::Result<Vec<u32>, _>>()
1025                    .map_err(|_| {
1026                        mscx_error(format!(
1027                            "the volta endings {:?}",
1028                            body.child_text("endings")
1029                        ))
1030                    })?;
1031                Self::Volta { numbers }
1032            }
1033            "Pedal" => {
1034                let body = body.ok_or_else(|| mscx_error("a pedal line that says nothing"))?;
1035                if body.find("beginHookType").is_some() {
1036                    return Err(refused("A pedal line that starts with a hook"));
1037                }
1038                let text = body.find("beginText").map(Xml::all_text);
1039                if text.as_deref() == Some("") {
1040                    return Err(refused("A pedal line carried on from another"));
1041                }
1042                let sostenuto = body
1043                    .find("beginText")
1044                    .and_then(|text| text.find("sym"))
1045                    .is_some_and(|sym| {
1046                        matches!(sym.stripped(), "keyboardPedalSost" | "keyboardPedalS")
1047                    });
1048                Self::Pedal(Pedal {
1049                    pedal_type: Some(if sostenuto {
1050                        PedalType::Sostenuto
1051                    } else {
1052                        PedalType::Sustain
1053                    }),
1054                    form: Some(if body.child_text("lineVisible") == "0" {
1055                        PedalForm::Symbol
1056                    } else {
1057                        PedalForm::Line
1058                    }),
1059                    abbreviated: false,
1060                })
1061            }
1062            // A tie is read on its note.
1063            "Tie" | "LaissezVib" | "PartialTie" => return Ok(None),
1064            other => return Err(refused(format!("A {other} spanner"))),
1065        }))
1066    }
1067}
1068
1069/// A position moved by a relative `<location>`.
1070fn moved(from: Position, location: Option<&Xml>) -> Result<Position> {
1071    // A place names a grace note outright, and the note itself by naming
1072    // none.
1073    let mut to = Position {
1074        grace: None,
1075        ..from
1076    };
1077    let Some(location) = location else {
1078        return Ok(to);
1079    };
1080    to.grace = child_integer(location, "grace")?.and_then(|index| usize::try_from(index).ok());
1081    if let Some(measures) = child_integer(location, "measures")? {
1082        to.measure += measures;
1083    }
1084    if let Some(fractions) = location.find("fractions") {
1085        to.tick += fraction(fractions.stripped())?;
1086    }
1087    let staves = child_integer(location, "staves")?.unwrap_or(0);
1088    let voices = child_integer(location, "voices")?.unwrap_or(0);
1089    let track = from.track as i64 + staves * 4 + voices;
1090    to.track = usize::try_from(track).map_err(|_| mscx_error("a spanner ending on no staff"))?;
1091    Ok(to)
1092}
1093
1094fn tuplet_of(element: &Xml, parent: Option<usize>) -> Result<TupletRead> {
1095    let count = |tag: &str| -> Result<u32> {
1096        let value = child_integer(element, tag)?
1097            .ok_or_else(|| mscx_error(format!("a tuplet with no <{tag}>")))?;
1098        u32::try_from(value)
1099            .ok()
1100            .filter(|value| *value > 0)
1101            .ok_or_else(|| mscx_error(format!("a tuplet of {value}")))
1102    };
1103    let base_name = element.child_text("baseNote");
1104    let (kind, _, _) = duration_named(base_name)?;
1105    let base_dots = child_integer(element, "baseDots")?.unwrap_or(0).max(0) as u32;
1106    let placement = match element.child_text("direction") {
1107        "up" => Some(Placement::Above),
1108        "down" => Some(Placement::Below),
1109        _ => None,
1110    };
1111    Ok(TupletRead {
1112        actual: count("actualNotes")?,
1113        normal: count("normalNotes")?,
1114        base: (kind, base_dots),
1115        bracket: child_integer(element, "bracketType")?.unwrap_or(0),
1116        number: child_integer(element, "numberType")?.unwrap_or(0),
1117        placement,
1118        parent,
1119        elements: Vec::new(),
1120    })
1121}
1122
1123fn note_of(element: &Xml, transposition: (i64, i64)) -> Result<NoteRead> {
1124    let midi =
1125        child_integer(element, "pitch")?.ok_or_else(|| mscx_error("a note with no pitch"))?;
1126    let concert = child_integer(element, "tpc")?.ok_or_else(|| mscx_error("a note with no tpc"))?;
1127    // A transposing instrument's notes are written as it reads them.
1128    let written_tpc = child_integer(element, "tpc2")?.unwrap_or(concert);
1129    let (tpc, midi) = if transposition == (0, 0) {
1130        (concert, midi)
1131    } else {
1132        (written_tpc, midi - transposition.1)
1133    };
1134    let mut pitch = pitch_of(midi, tpc)?;
1135    let (_, alter) = spelling(tpc)?;
1136    match element.find("Accidental") {
1137        Some(written) => {
1138            let name = accidental_named(written.child_text("subtype"))?;
1139            let mut accidental = Accidental::natural();
1140            accidental.set_allowing_non_standard_value(name)?;
1141            accidental.set_display_status(Some(true));
1142            match written.child_text("bracket") {
1143                "1" => accidental.set_display_style("parentheses")?,
1144                "2" => accidental.set_display_style("bracket")?,
1145                _ => {}
1146            }
1147            pitch.set_written_accidental(Some(accidental));
1148        }
1149        None if alter != 0 => {
1150            let mut accidental = Accidental::new(alter as FloatType)?;
1151            accidental.set_display_status(Some(false));
1152            pitch.set_written_accidental(Some(accidental));
1153        }
1154        None => {}
1155    }
1156    let mut read = NoteRead {
1157        pitch,
1158        tie_start: false,
1159        tie_stop: false,
1160        tie_placement: None,
1161        velocity: child_integer(element, "velocity")?.filter(|velocity| *velocity != 0),
1162        hidden: element.child_text("visible") == "0",
1163        small: flag(element, "small"),
1164        head: None,
1165        head_filled: None,
1166        fingerings: Vec::new(),
1167        color: None,
1168    };
1169    for held in &element.children {
1170        match held.tag.as_str() {
1171            "head" => read.head = head_named(held.stripped())?,
1172            "headType" => {
1173                read.head_filled = match held.stripped() {
1174                    "quarter" => Some(true),
1175                    "half" | "whole" => Some(false),
1176                    "auto" | "breve" => None,
1177                    other => return Err(refused(format!("A notehead of the kind {other:?}"))),
1178                };
1179            }
1180            "Fingering" => {
1181                if let Some(fingering) = fingering_of(held)? {
1182                    read.fingerings.push(fingering);
1183                }
1184            }
1185            "color" => read.color = Some(color_of(held)?),
1186            // Shape notes are drawn by the degree of the scale a note is.
1187            "headScheme" => {
1188                if !matches!(held.stripped(), "auto" | "normal") {
1189                    return Err(refused("A note drawn as a shape note"));
1190                }
1191            }
1192            "tuning" => {
1193                if held
1194                    .stripped()
1195                    .parse::<FloatType>()
1196                    .is_ok_and(|cents| cents != 0.0)
1197                {
1198                    return Err(refused("A note tuned away from its pitch"));
1199                }
1200            }
1201            "Spanner" => match held.get("type") {
1202                Some("Tie" | "LaissezVib" | "PartialTie") => {}
1203                Some(other) => return Err(refused(format!("A {other} on a note"))),
1204                None => {}
1205            },
1206            // Read above or below, or only drawn or played.
1207            "pitch" | "tpc" | "tpc2" | "Accidental" | "Tie" | "endSpanner" | "visible"
1208            | "small" | "velocity" | "veloType" | "veloOffset" | "play" | "eid" | "NoteDot"
1209            | "Events" | "mirror" | "dotPosition" | "fixed" | "fixedLine" | "offset" | "linked"
1210            | "linkedMain" | "track" | "Symbol" | "fret" | "string" | "ghost" | "dead" | "z"
1211            | "autoplace" | "LaissezVib" | "PartialTie" => {}
1212            other => return Err(refused(format!("A <{other}> on a note"))),
1213        }
1214    }
1215    for held in element.find_all("Spanner") {
1216        if held.get("type") == Some("Tie") {
1217            if held.find("next").is_some() {
1218                read.tie_start = true;
1219                read.tie_placement = match held.find("Tie").map(|tie| tie.child_text("up")) {
1220                    Some("up") => Some(Placement::Above),
1221                    Some("down") => Some(Placement::Below),
1222                    _ => None,
1223                };
1224            }
1225            if held.find("prev").is_some() {
1226                read.tie_stop = true;
1227            }
1228        }
1229    }
1230    // MuseScore 3 wrote a tie as a `<Tie>` on the note it starts from.
1231    if element.find("Tie").is_some() {
1232        read.tie_start = true;
1233    }
1234    if element.find("endSpanner").is_some() {
1235        read.tie_stop = true;
1236    }
1237    Ok(read)
1238}
1239
1240/// The shape of a notehead by MuseScore's name for it; nothing for the
1241/// usual one.
1242fn head_named(name: &str) -> Result<Option<Notehead>> {
1243    let written = match name {
1244        "normal" => return Ok(None),
1245        "cross" => "x",
1246        "plus" => "cross",
1247        "xcircle" => "circle-x",
1248        "circled" => "circled",
1249        "triangle-up" => "triangle",
1250        "triangle-down" => "inverted triangle",
1251        "slashed1" => "slashed",
1252        "slashed2" => "back slashed",
1253        "diamond" | "slash" | "do" | "re" | "mi" | "la" | "ti" => name,
1254        "sol" => "so",
1255        other => return Err(refused(format!("A notehead of the shape {other:?}"))),
1256    };
1257    Notehead::from_name(written).map(Some)
1258}
1259
1260/// A colour as MuseScore's export writes one.
1261fn color_of(element: &Xml) -> Result<String> {
1262    let part = |name: &str| -> Result<i64> {
1263        element
1264            .get(name)
1265            .and_then(|text| text.parse::<i64>().ok())
1266            .filter(|value| (0..=255).contains(value))
1267            .ok_or_else(|| mscx_error(format!("a colour with no {name}")))
1268    };
1269    if part("a")? != 255 {
1270        return Err(refused("A colour that is partly transparent"));
1271    }
1272    Ok(format!(
1273        "#{:02X}{:02X}{:02X}",
1274        part("r")?,
1275        part("g")?,
1276        part("b")?
1277    ))
1278}
1279
1280/// A fingering written on a note: a finger, a plucking finger, or the
1281/// string it is played on.
1282fn fingering_of(element: &Xml) -> Result<Option<Articulation>> {
1283    if element.child_text("visible") == "0" {
1284        return Ok(None);
1285    }
1286    let text = element
1287        .find("text")
1288        .map(plain_text)
1289        .transpose()?
1290        .unwrap_or_default();
1291    let text = text.trim();
1292    let style = element.child_text("style");
1293    let made = |class: &str| {
1294        ArticulationKind::from_class_name(class)
1295            .map(Articulation::of_kind)
1296            .ok_or_else(|| mscx_error(format!("no articulation {class}")))
1297    };
1298    let plucked = matches!(text, "p" | "i" | "m" | "a" | "c");
1299    Ok(Some(match style {
1300        "String Number" | "string_number" => match text.parse::<IntegerType>() {
1301            Ok(0) => made("OpenString")?,
1302            Ok(number) if number > 0 => {
1303                let mut string = made("StringIndication")?;
1304                string.set_number(number);
1305                string
1306            }
1307            _ => return Ok(None),
1308        },
1309        "RH Guitar Fingering" | "guitar_fingering_rh" => made("FrettedPluck")?,
1310        "" | "Fingering" | "fingering" if plucked => made("FrettedPluck")?,
1311        "" | "Fingering" | "fingering" | "LH Guitar Fingering" | "guitar_fingering_lh" => {
1312            let mut fingering = made("Fingering")?;
1313            fingering.set_finger(Some(Finger::from_written(text)));
1314            fingering
1315        }
1316        other => return Err(refused(format!("A fingering in the style {other:?}"))),
1317    }))
1318}
1319
1320/// A breath mark or a caesura.
1321fn breath_of(element: &Xml) -> Result<Articulation> {
1322    let symbol = element.child_text("symbol");
1323    let made = |class: &str| {
1324        ArticulationKind::from_class_name(class)
1325            .map(Articulation::of_kind)
1326            .ok_or_else(|| mscx_error(format!("no articulation {class}")))
1327    };
1328    let mut mark = if symbol.contains("aesura") {
1329        made("Caesura")?
1330    } else {
1331        let mut breath = made("BreathMark")?;
1332        breath.set_symbol(Some(
1333            match symbol {
1334                "breathMarkTick" => "tick",
1335                "breathMarkUpbow" => "upbow",
1336                "breathMarkSalzedo" => "salzedo",
1337                _ => "comma",
1338            }
1339            .to_string(),
1340        ));
1341        breath
1342    };
1343    if element.child_text("placement") == "below" {
1344        mark.set_placement(Some("below".to_string()));
1345    }
1346    Ok(mark)
1347}
1348
1349fn lyric_of(element: &Xml) -> Result<LyricRead> {
1350    let number = child_integer(element, "no")?.unwrap_or(0) + 1;
1351    let syllabic = match element.child_text("syllabic") {
1352        "" => None,
1353        written => Some(Syllabic::from_name(written)?),
1354    };
1355    Ok(LyricRead {
1356        number: number as IntegerType,
1357        syllabic,
1358        text: element
1359            .find("text")
1360            .map(plain_text)
1361            .transpose()?
1362            .unwrap_or_default(),
1363    })
1364}
1365
1366fn articulation_of(element: &Xml) -> Result<Option<Articulation>> {
1367    let subtype = element.child_text("subtype");
1368    let base = subtype
1369        .strip_suffix("Above")
1370        .or_else(|| subtype.strip_suffix("Below"))
1371        .unwrap_or(subtype);
1372    let class = match base {
1373        "articAccent" => "Accent",
1374        "articStaccato" => "Staccato",
1375        "articStaccatissimo" | "articStaccatissimoWedge" => "Staccatissimo",
1376        "articStaccatissimoStroke" => "Spiccato",
1377        "articTenuto" => "Tenuto",
1378        "articMarcato" => "StrongAccent",
1379        "articTenutoStaccato" => "DetachedLegato",
1380        "articStress" => "Stress",
1381        "articUnstress" => "Unstress",
1382        "stringsUpBow" => "UpBow",
1383        "stringsDownBow" => "DownBow",
1384        "stringsHarmonic" => "StringHarmonic",
1385        "brassMuteOpen" => "OpenString",
1386        "stringsThumbPosition" => "StringThumbPosition",
1387        "brassMuteClosed" => "Stopped",
1388        "pluckedSnapPizzicatoAbove" | "pluckedSnapPizzicato" => "SnapPizzicato",
1389        other => return Err(refused(format!("The articulation {other:?}"))),
1390    };
1391    let kind = ArticulationKind::from_class_name(class)
1392        .ok_or_else(|| mscx_error(format!("no articulation {class}")))?;
1393    let mut articulation = Articulation::of_kind(kind);
1394    if class == "StrongAccent" {
1395        let up = !subtype.ends_with("Below");
1396        articulation.set_point_direction(Some(if up { "up" } else { "down" }.to_string()));
1397    } else {
1398        // Above, below, or wherever it falls; any other number is an older
1399        // file's, which MuseScore reads as below.
1400        match element.child_text("anchor") {
1401            "" | "2" => {}
1402            "0" => articulation.set_placement(Some("above".to_string())),
1403            _ => articulation.set_placement(Some("below".to_string())),
1404        }
1405    }
1406    Ok(Some(articulation))
1407}
1408
1409/// Whether a `<LayoutBreak>` ends a section, after which measures are
1410/// numbered from one again.
1411fn ends_section(element: &Xml) -> bool {
1412    element.child_text("subtype") == "section" && element.child_text("startWithMeasureOne") != "0"
1413}
1414
1415/// Words saying where to go next: a repeat mark where they are ones music21
1416/// reads as one, and plain words otherwise.
1417fn repeat_words(text: &str) -> StreamElement {
1418    let repeat = RepeatExpressionKind::ALL
1419        .into_iter()
1420        .find(|kind| RepeatExpression::new(*kind).is_valid_text(text));
1421    match repeat {
1422        Some(kind) => {
1423            let mut mark = RepeatExpression::new(kind);
1424            mark.set_text(text);
1425            // The words are placed, not the mark: one drawn as its sign, a
1426            // coda or a segno, stands where a sign stands.
1427            if !mark.use_symbol() {
1428                mark.set_placement(Some(Placement::Above));
1429            }
1430            mark.into()
1431        }
1432        None => {
1433            let mut words = TextExpression::new(text);
1434            words.set_placement(Some(Placement::Above));
1435            words.into()
1436        }
1437    }
1438}
1439
1440/// A `<Marker>`: a segno or a coda sign, which stands at the start of its
1441/// measure, or *Fine* or *To Coda*, which stand at its end. The first
1442/// answer is whether it stands at the end.
1443fn marker_of(element: &Xml, by_label: bool) -> Result<(bool, StreamElement)> {
1444    let sign = |kind: RepeatExpressionKind| (false, RepeatExpression::new(kind).into());
1445    let text = element
1446        .find("text")
1447        .map(plain_text)
1448        .transpose()?
1449        .unwrap_or_default();
1450    let kind = match element.child_text("markerType") {
1451        "" if by_label => element.child_text("label"),
1452        "" => "fine",
1453        kind => kind,
1454    };
1455    Ok(match kind {
1456        "segno" | "varsegno" => sign(RepeatExpressionKind::Segno),
1457        "codab" | "varcoda" | "codetta" => sign(RepeatExpressionKind::Coda),
1458        "fine" if !text.trim().is_empty() => (true, repeat_words(text.trim())),
1459        "coda" | "codasym" | "dacoda" | "dadblcoda" => (
1460            true,
1461            repeat_words(if text.trim().is_empty() {
1462                "To Coda"
1463            } else {
1464                text.trim()
1465            }),
1466        ),
1467        other => return Err(refused(format!("A marker of the kind {other:?}"))),
1468    })
1469}
1470
1471/// A `<Jump>`: *D.C.*, *D.S.* and their kin, in the words written or else
1472/// the words MuseScore has for where the jump goes.
1473fn jump_of(element: &Xml) -> Result<StreamElement> {
1474    let text = element
1475        .find("text")
1476        .map(plain_text)
1477        .transpose()?
1478        .unwrap_or_default();
1479    let text = text.trim();
1480    let to = (
1481        element.child_text("jumpTo"),
1482        element.child_text("playUntil"),
1483        element.child_text("continueAt"),
1484    );
1485    let words = match to {
1486        ("segno", "end", "") => "D.S.",
1487        _ if !text.is_empty() => text,
1488        ("start", "end", "") => "D.C.",
1489        ("start", "fine", "") => "D.C. al Fine",
1490        ("start", "coda", "codab") => "D.C. al Coda",
1491        ("segno", "coda", "codab") => "D.S. al Coda",
1492        ("segno", "fine", "") => "D.S. al Fine",
1493        _ => return Err(refused("A jump that does not say in words where it goes")),
1494    };
1495    Ok(repeat_words(words))
1496}
1497
1498fn ornament_of(element: &Xml) -> Result<Expression> {
1499    if element.find("Accidental").is_some() {
1500        return Err(refused("An ornament with an accidental"));
1501    }
1502    let subtype = element.child_text("subtype");
1503    let (class, turn) = match subtype {
1504        "ornamentTrill" => ("Trill", false),
1505        "ornamentTurn" => ("Turn", true),
1506        "ornamentTurnInverted" => ("InvertedTurn", true),
1507        "ornamentMordent"
1508        | "ornamentPrallMordent"
1509        | "ornamentUpMordent"
1510        | "ornamentDownMordent" => ("Mordent", false),
1511        "ornamentShortTrill"
1512        | "ornamentTremblement"
1513        | "ornamentUpPrall"
1514        | "ornamentPrecompMordentUpperPrefix"
1515        | "ornamentPrallDown"
1516        | "ornamentPrallUp"
1517        | "ornamentLinePrall" => ("InvertedMordent", false),
1518        "ornamentPrecompSlide" => ("Schleifer", false),
1519        other => return Err(refused(format!("The ornament {other:?}"))),
1520    };
1521    let kind = OrnamentKind::from_class_name(class)
1522        .ok_or_else(|| mscx_error(format!("no ornament {class}")))?;
1523    let mut ornament = Ornament::of_kind(kind);
1524    if turn {
1525        ornament.set_delay(OrnamentDelay::NoDelay);
1526    }
1527    Ok(ornament.into())
1528}
1529
1530/// An arpeggio on one chord. One drawn across staves joins chords, which
1531/// is not read.
1532fn arpeggio_of(element: &Xml) -> Result<Expression> {
1533    if child_integer(element, "span")?.is_some_and(|span| span > 1) {
1534        return Err(refused("An arpeggio across staves"));
1535    }
1536    Ok(Expression::Arpeggio(match element.child_text("subtype") {
1537        "0" | "" | "arpeggiato" => ArpeggioType::Normal,
1538        "1" | "4" | "up" | "upStraight" => ArpeggioType::Up,
1539        "2" | "5" | "down" | "downStraight" => ArpeggioType::Down,
1540        "3" | "bracket" => ArpeggioType::NonArpeggio,
1541        other => return Err(refused(format!("An arpeggio of the kind {other:?}"))),
1542    }))
1543}
1544
1545fn fermata_of(element: &Xml) -> Fermata {
1546    let mut fermata = Fermata::new();
1547    let subtype = element.child_text("subtype");
1548    if subtype.ends_with("Below") {
1549        fermata.set_fermata_type(FermataType::Inverted);
1550    } else {
1551        fermata.set_fermata_type(FermataType::Upright);
1552    }
1553    let shape = subtype
1554        .strip_suffix("Above")
1555        .or_else(|| subtype.strip_suffix("Below"))
1556        .unwrap_or(subtype);
1557    let shape = match shape {
1558        "fermata" => None,
1559        "fermataShort" => Some("angled"),
1560        "fermataLong" => Some("square"),
1561        "fermataVeryShort" => Some("double-angled"),
1562        "fermataVeryLong" => Some("double-square"),
1563        "fermataLongHenze" => Some("double-dot"),
1564        "fermataShortHenze" => Some("half-curve"),
1565        _ => None,
1566    };
1567    fermata.set_shape(shape.map(str::to_string));
1568    fermata
1569}
1570
1571/// Where a mark is placed: what it says, else its default.
1572fn placement_of(element: &Xml, default: Placement) -> Placement {
1573    match element.child_text("placement") {
1574        "above" => Placement::Above,
1575        "below" => Placement::Below,
1576        _ => match element.child_text("direction") {
1577            "up" => Placement::Above,
1578            "down" => Placement::Below,
1579            _ => default,
1580        },
1581    }
1582}
1583
1584/// A key signature as it is written, for a transposing instrument in the
1585/// key it reads.
1586fn key_of(element: &Xml, transposition: (i64, i64), old_format: bool) -> Result<StreamElement> {
1587    if flag(element, "custom") || element.find("KeySym").is_some() {
1588        return Err(refused("A key signature of its own making"));
1589    }
1590    // Before format 4.1 a signature said the key its staff is written in,
1591    // as `<accidental>`; since then it says the sounding key, and the
1592    // written one beside it where a transposing instrument has another.
1593    // MuseScore reads each format by its own rule and so does this.
1594    let mut sharps = if old_format {
1595        child_integer(element, "accidental")?.unwrap_or(0)
1596    } else {
1597        let concert = child_integer(element, "concertKey")?.unwrap_or(0);
1598        match child_integer(element, "actualKey")? {
1599            Some(actual) => actual,
1600            None => concert - 7 * transposition.1 + 12 * transposition.0,
1601        }
1602    };
1603    while sharps > 7 {
1604        sharps -= 12;
1605    }
1606    while sharps < -7 {
1607        sharps += 12;
1608    }
1609    let signature = KeySignature::new(sharps as IntegerType);
1610    let mode = element.child_text("mode");
1611    if !mode.is_empty()
1612        && mode != "none"
1613        && mode != "unknown"
1614        && let Ok(key) = signature.try_as_key(Some(mode), None)
1615    {
1616        return Ok(key.into());
1617    }
1618    Ok(signature.into())
1619}
1620
1621fn meter_of(element: &Xml) -> Result<TimeSignature> {
1622    let numerator =
1623        child_integer(element, "sigN")?.ok_or_else(|| mscx_error("a meter with no <sigN>"))?;
1624    let denominator =
1625        child_integer(element, "sigD")?.ok_or_else(|| mscx_error("a meter with no <sigD>"))?;
1626    let written = element.child_text("textN");
1627    let ratio = if written.is_empty() {
1628        format!("{numerator}/{denominator}")
1629    } else {
1630        format!("{written}/{denominator}")
1631    };
1632    let mut meter = TimeSignature::from_ratio_string(&ratio)
1633        .map_err(|_| mscx_error(format!("the meter {ratio}")))?;
1634    match element.child_text("subtype") {
1635        "1" => meter.set_symbol(Some("common".to_string())),
1636        "2" => meter.set_symbol(Some("cut".to_string())),
1637        _ => {}
1638    }
1639    Ok(meter)
1640}
1641
1642/// A barline written in a voice. A repeat is not one: that is the
1643/// measure's.
1644fn barline_of(element: &Xml) -> Result<Option<Barline>> {
1645    if element.child_text("visible") == "0" {
1646        return Ok(Some(Barline::new(BarlineType::None)));
1647    }
1648    let kind = match element.child_text("subtype") {
1649        "normal" | "" => BarlineType::Regular,
1650        "double" => BarlineType::Double,
1651        "end" => BarlineType::Final,
1652        "reverse-end" => BarlineType::HeavyLight,
1653        "heavy" => BarlineType::Heavy,
1654        "double-heavy" => BarlineType::HeavyHeavy,
1655        "dashed" => BarlineType::Dashed,
1656        "dotted" => BarlineType::Dotted,
1657        "start-repeat" | "end-repeat" | "end-start-repeat" => return Ok(None),
1658        other => return Err(mscx_error(format!("a barline of the kind {other:?}"))),
1659    };
1660    Ok(Some(Barline::new(kind)))
1661}
1662
1663/// A tempo mark: the mark, and whatever words stand beside it.
1664fn tempo_of(element: &Xml) -> Result<Vec<StreamElement>> {
1665    let per_second: FloatType = element
1666        .child_text("tempo")
1667        .parse()
1668        .map_err(|_| mscx_error("a tempo that is not a number"))?;
1669    let bpm = (per_second * 60.0 * 100.0).round() / 100.0;
1670    if element.child_text("visible") == "0" {
1671        return Ok(vec![
1672            MetronomeMark::default().with_number_sounding(bpm).into(),
1673        ]);
1674    }
1675    let placement = placement_of(element, Placement::Above);
1676    let text = element.find("text");
1677    let found = text.and_then(metronome_in);
1678    let mut out: Vec<StreamElement> = Vec::new();
1679    match found {
1680        Some((left, referent, number)) => {
1681            if !left.trim().is_empty() {
1682                let mut words = TextExpression::new(left.trim());
1683                words.set_placement(Some(placement));
1684                out.push(words.into());
1685            }
1686            let mut mark = MetronomeMark::default();
1687            mark.set_number(Some(number));
1688            mark.set_referent(referent);
1689            mark.set_placement(Some(placement));
1690            out.push(mark.into());
1691        }
1692        None => {
1693            if let Some(text) = text {
1694                let written = plain_text(text)?;
1695                if !written.trim().is_empty() {
1696                    let mut words = TextExpression::new(written.trim());
1697                    words.set_placement(Some(placement));
1698                    out.push(words.into());
1699                }
1700            }
1701            let mut mark = MetronomeMark::default().with_number_sounding(bpm);
1702            mark.set_placement(Some(placement));
1703            out.push(mark.into());
1704        }
1705    }
1706    Ok(out)
1707}
1708
1709/// The metronome mark in a tempo's text: the words before it, the note it
1710/// counts and how many to the minute.
1711fn metronome_in(text: &Xml) -> Option<(String, Duration, FloatType)> {
1712    let mut before = String::new();
1713    if let Some(leading) = text.text() {
1714        before.push_str(leading);
1715    }
1716    for (index, child) in text.children.iter().enumerate() {
1717        if child.tag == "sym" {
1718            let name = child.text().unwrap_or("").trim();
1719            let referent = match name {
1720                "metNoteWhole" => Duration::from_type(DurationType::Whole),
1721                "metNoteHalfUp" => Duration::from_type(DurationType::Half),
1722                "metNoteQuarterUp" => Duration::from_type(DurationType::Quarter),
1723                "metNote8thUp" => Duration::from_type(DurationType::Eighth),
1724                "metNote16thUp" => Duration::from_type(DurationType::Sixteenth),
1725                _ => return None,
1726            };
1727            let mut referent = referent;
1728            let mut rest = String::new();
1729            let mut dots = 0;
1730            if let Some(tail) = child.tail() {
1731                rest.push_str(tail);
1732            }
1733            for later in &text.children[index + 1..] {
1734                if later.tag == "sym" && later.text().unwrap_or("").trim() == "metAugmentationDot" {
1735                    dots += 1;
1736                } else {
1737                    rest.push_str(&plain_text(later).ok()?);
1738                }
1739                if let Some(tail) = later.tail() {
1740                    rest.push_str(tail);
1741                }
1742            }
1743            if dots > 0
1744                && let Some((kind, _)) = referent.type_and_dots()
1745            {
1746                referent = Duration::from_type_with_dots(kind, dots);
1747            }
1748            let rest = rest.trim_start();
1749            let rest = rest.strip_prefix('=')?.trim_start();
1750            let digits: String = rest
1751                .chars()
1752                .take_while(|c| c.is_ascii_digit() || *c == '.' || *c == ',')
1753                .collect();
1754            let number: FloatType = digits.replace(',', ".").parse().ok()?;
1755            let before = before.trim_end_matches('(').to_string();
1756            return Some((before, referent, number));
1757        }
1758        before.push_str(&plain_text(child).ok()?);
1759        if let Some(tail) = child.tail() {
1760            before.push_str(tail);
1761        }
1762    }
1763    None
1764}
1765
1766/// Words written over or under the staff; words saying where to go next
1767/// are a repeat mark.
1768fn words_of(element: &Xml, default: Placement) -> Result<Option<StreamElement>> {
1769    let text = element
1770        .find("text")
1771        .map(plain_text)
1772        .transpose()?
1773        .unwrap_or_default();
1774    let text = text.trim();
1775    if text.is_empty() {
1776        return Ok(None);
1777    }
1778    let placement = placement_of(element, default);
1779    let repeat = RepeatExpressionKind::ALL
1780        .into_iter()
1781        .find(|kind| RepeatExpression::new(*kind).is_valid_text(text));
1782    Ok(Some(match repeat {
1783        Some(kind) => {
1784            let mut mark = RepeatExpression::new(kind);
1785            mark.set_text(text);
1786            if !mark.use_symbol() {
1787                mark.set_placement(Some(placement));
1788            }
1789            mark.into()
1790        }
1791        None => {
1792            let mut words = TextExpression::new(text);
1793            words.set_placement(Some(placement));
1794            words.into()
1795        }
1796    }))
1797}
1798
1799/// A chord symbol: its root and bass as tonal pitch classes, and the name
1800/// of its kind as written, which is read as music21 reads a figure.
1801fn harmony_of(element: &Xml) -> Result<ChordSymbol> {
1802    let info = element.find("harmonyInfo").unwrap_or(element);
1803    let name = info.child_text("name");
1804    let Some(root) = child_integer(info, "root")? else {
1805        return Err(refused("A chord symbol with no root"));
1806    };
1807    let pitch = |tpc: i64| -> Result<(Pitch, String)> {
1808        let (step, alter) = spelling(tpc)?;
1809        let mut pitch = Pitch::from_name(step.to_string())?;
1810        if alter != 0 {
1811            pitch.set_written_accidental(Some(Accidental::new(alter as FloatType)?));
1812        }
1813        let written = match alter {
1814            -2 => "--",
1815            -1 => "-",
1816            1 => "#",
1817            2 => "##",
1818            _ => "",
1819        };
1820        Ok((pitch, format!("{step}{written}")))
1821    };
1822    let (root, root_name) = pitch(root)?;
1823    let bass = match child_integer(info, "bass")? {
1824        Some(bass) => Some(bass),
1825        None => child_integer(info, "base")?,
1826    }
1827    .map(pitch)
1828    .transpose()?;
1829    let mut figure = format!("{root_name}{name}");
1830    if let Some((_, bass_name)) = &bass {
1831        figure.push('/');
1832        figure.push_str(bass_name);
1833    }
1834    let unread = || refused(format!("The chord symbol {figure:?}"));
1835    let parsed = ChordSymbol::parse_music21(&figure).map_err(|_| unread())?;
1836    let kind = parsed
1837        .kind()
1838        .filter(|kind| !kind.is_empty())
1839        .ok_or_else(unread)?
1840        .to_string();
1841    // The text of the kind itself: the name up to where its added and
1842    // altered degrees begin.
1843    let mut kind_text = name;
1844    if !parsed.chord_step_modifications().is_empty() {
1845        kind_text = "";
1846        for (end, _) in name.char_indices().skip(1).chain([(name.len(), ' ')]) {
1847            let alone = ChordSymbol::parse_music21(format!("{root_name}{}", &name[..end]));
1848            if let Ok(alone) = alone
1849                && alone.kind() == Some(kind.as_str())
1850                && alone.chord_step_modifications().is_empty()
1851            {
1852                kind_text = &name[..end];
1853            }
1854        }
1855    }
1856    let mut symbol =
1857        ChordSymbol::from_kind(root, &kind, bass.map(|(pitch, _)| pitch)).map_err(|_| unread())?;
1858    symbol.set_kind_text(Some(kind_text.to_string()));
1859    symbol.set_chord_step_modifications(parsed.chord_step_modifications().to_vec());
1860    Ok(symbol)
1861}
1862
1863// ---------------------------------------------------------------- the head
1864
1865fn metadata_of(score: &Xml, program: &str) -> Metadata {
1866    let mut tags: Vec<(String, String)> = score
1867        .find_all("metaTag")
1868        .filter_map(|tag| {
1869            let name = tag.get("name")?.to_string();
1870            let value = tag.all_text();
1871            (!value.is_empty()).then_some((name, value))
1872        })
1873        .collect();
1874    // MuseScore keeps its tags sorted by name.
1875    tags.sort_by(|left, right| left.0.cmp(&right.0));
1876    let get = |name: &str| {
1877        tags.iter()
1878            .find(|(held, _)| held == name)
1879            .map(|(_, value)| value.clone())
1880    };
1881    let mut metadata = Metadata::new();
1882    if let Some(number) = get("workNumber") {
1883        metadata.add_text("number", number);
1884    }
1885    if let Some(number) = get("movementNumber") {
1886        metadata.add_text("movementNumber", number);
1887    }
1888    // A work title that only repeats the movement's is left out, as the
1889    // MusicXML reader leaves it out, so that both read one score alike.
1890    let title = get("workTitle").filter(|title| Some(title) != get("movementTitle").as_ref());
1891    if let Some(title) = title {
1892        metadata.add_text("title", title);
1893    }
1894    if let Some(title) = get("movementTitle") {
1895        metadata.add_text("movementName", title);
1896    }
1897    for role in ["arranger", "composer", "lyricist", "poet", "translator"] {
1898        if let Some(name) = get(role) {
1899            let unique = if crate::metadata::is_contributor_unique_name(role) {
1900                role
1901            } else {
1902                "otherContributor"
1903            };
1904            metadata.add(unique, MetadataValue::with_role(name.trim(), role));
1905        }
1906    }
1907    if let Some(copyright) = get("copyright") {
1908        metadata.add("copyright", MetadataValue::new(copyright.trim()));
1909    }
1910    if !program.is_empty() {
1911        metadata.add_text("software", program);
1912    }
1913    const NAMED: [&str; 12] = [
1914        "arranger",
1915        "composer",
1916        "lyricist",
1917        "poet",
1918        "translator",
1919        "copyright",
1920        "source",
1921        "workTitle",
1922        "workNumber",
1923        "movementTitle",
1924        "movementNumber",
1925        "originalFormat",
1926    ];
1927    for (name, value) in &tags {
1928        if NAMED.contains(&name.as_str()) {
1929            continue;
1930        }
1931        let unique = crate::metadata::STANDARD_PROPERTIES
1932            .iter()
1933            .find(|(unique, namespaced, _)| unique == name || namespaced == name)
1934            .map_or(name.as_str(), |(unique, _, _)| unique);
1935        metadata.add_text(unique, value.clone());
1936    }
1937    metadata
1938}
1939
1940/// music21's `getDefaultInstrument`, from what MuseScore says of the
1941/// instrument: a program and a name.
1942fn instrument_of(program: Option<u8>, channel: Option<u8>, name: Option<&str>) -> Instrument {
1943    let mut instrument = program
1944        .and_then(|program| Instrument::from_midi_program(program).ok())
1945        .unwrap_or_default();
1946    if program.is_some() {
1947        instrument.set_midi_channel(channel);
1948    }
1949    if let Some(name) = name.filter(|name| !name.is_empty()) {
1950        let mut from_name = Instrument::from_name(name, SearchLanguage::All).unwrap_or_default();
1951        from_name.set_midi_channel(instrument.midi_channel());
1952        if from_name.midi_program() == instrument.midi_program() || instrument.is_a("Piano") {
1953            instrument = from_name;
1954        }
1955    }
1956    instrument
1957}
1958
1959fn parts_of(score: &Xml, hides_single_name: bool) -> Result<Vec<PartRead>> {
1960    let mut parts = Vec::new();
1961    let mut first_staff = 0;
1962    let mut channel: usize = 0;
1963    let listed: Vec<&Xml> = score.find_all("Part").collect();
1964    let hidden = hides_single_name && listed.len() == 1;
1965    for (index, part) in listed.into_iter().enumerate() {
1966        let staves = part.find_all("Staff").count();
1967        if staves == 0 {
1968            return Err(mscx_error("a part with no staff"));
1969        }
1970        for staff in part.find_all("Staff") {
1971            if let Some(kind) = staff.find("StaffType")
1972                && let Some(group) = kind.get("group")
1973                && group != "pitched"
1974            {
1975                return Err(refused(format!("A {group} staff")));
1976            }
1977        }
1978        let instrument = part
1979            .find("Instrument")
1980            .ok_or_else(|| mscx_error("a part with no instrument"))?;
1981        if flag(instrument, "useDrumset") {
1982            return Err(refused("A drum set"));
1983        }
1984        let text = |element: &Xml, tag: &str| -> Result<Option<String>> {
1985            Ok(element
1986                .find(tag)
1987                .map(plain_text)
1988                .transpose()?
1989                .map(|text| text.trim().replace('\n', " "))
1990                .filter(|text| !text.is_empty()))
1991        };
1992        let long_name = text(instrument, "longName")?;
1993        let short_name = text(instrument, "shortName")?;
1994        let track_name = text(instrument, "trackName")?;
1995        let part_track = text(part, "trackName")?;
1996        // A part with no name of its own goes by its track's, which is not
1997        // printed.
1998        let (name, name_hidden) = match long_name {
1999            Some(name) => (Some(name), hidden),
2000            None => (part_track.clone(), part_track.is_some() || hidden),
2001        };
2002        let abbreviation_hidden = name_hidden && short_name.is_some();
2003        let mut brackets: Vec<(i64, i64, usize)> = Vec::new();
2004        let mut bracket_found = false;
2005        for (staff_index, staff) in part.find_all("Staff").enumerate() {
2006            for bracket in staff.find_all("bracket") {
2007                let number = |name: &str| {
2008                    bracket
2009                        .get(name)
2010                        .and_then(|value| value.parse::<i64>().ok())
2011                        .unwrap_or(0)
2012                };
2013                if number("type") < 0 {
2014                    continue;
2015                }
2016                bracket_found = true;
2017                if staff_index == 0 {
2018                    brackets.push((
2019                        number("col"),
2020                        number("type"),
2021                        number("span").max(0) as usize,
2022                    ));
2023                }
2024            }
2025        }
2026        brackets.sort_by_key(|(column, _, _)| *column);
2027        let channels: Vec<&Xml> = instrument.find_all("Channel").collect();
2028        let program = channels
2029            .first()
2030            .and_then(|first| first.find("program"))
2031            .and_then(|program| program.get("value"))
2032            .and_then(|value| value.parse::<u8>().ok());
2033        // The channel the file gives the instrument's first sound, or the
2034        // next one free where it gives none; the tenth is the drums'.
2035        let written = channels
2036            .first()
2037            .and_then(|first| first.find("midiChannel"))
2038            .map(integer)
2039            .transpose()?;
2040        let mut first_channel = written.map(|written| written.rem_euclid(16) as u8);
2041        for _ in 0..channels.len().max(1) {
2042            if channel % 16 == 9 {
2043                channel += 1;
2044            }
2045            first_channel.get_or_insert((channel % 16) as u8);
2046            channel += 1;
2047        }
2048        let mut made = instrument_of(program, first_channel, track_name.as_deref());
2049        made.set_part_id(Some(format!("P{}", index + 1)));
2050        made.set_part_name(name.clone());
2051        made.set_part_abbreviation(short_name.clone());
2052        if let Some(track_name) = &track_name {
2053            made.set_name(Some(track_name.clone()));
2054        }
2055        let sound = instrument.child_text("instrumentId");
2056        if !sound.is_empty() {
2057            made.set_sound(Some(sound.to_string()));
2058        }
2059        let transposition = (
2060            child_integer(instrument, "transposeDiatonic")?.unwrap_or(0),
2061            child_integer(instrument, "transposeChromatic")?.unwrap_or(0),
2062        );
2063        if transposition.1 != 0 {
2064            // The interval from the written note to the sounding one, the
2065            // octaves counted into both halves.
2066            let octaves = transposition.1 / 12;
2067            let diatonic = transposition.0 % 7 + 7 * octaves;
2068            let steps = if diatonic < 0 {
2069                diatonic - 1
2070            } else {
2071                diatonic + 1
2072            };
2073            let interval = Interval::from_generic_and_chromatic(
2074                steps as IntegerType,
2075                transposition.1 as IntegerType,
2076            )
2077            .or_else(|_| Interval::from_semitones(transposition.1 as IntegerType))?;
2078            made.set_transposition(Some(interval));
2079        }
2080        // The clef a staff starts with where its first measure writes
2081        // none: the staff's own, else a treble clef, whatever clef its
2082        // instrument is usually written in. A transposing instrument's is
2083        // the one it reads.
2084        let mut default_clefs = vec![String::from("G"); staves];
2085        for (staff_index, staff) in part.find_all("Staff").enumerate() {
2086            for tag in [
2087                "defaultClef",
2088                "defaultConcertClef",
2089                "defaultTransposingClef",
2090            ] {
2091                if let Some(clef) = staff.find(tag) {
2092                    default_clefs[staff_index] = clef.stripped().to_string();
2093                }
2094            }
2095        }
2096        parts.push(PartRead {
2097            staves,
2098            first_staff,
2099            name,
2100            abbreviation: short_name,
2101            name_hidden,
2102            abbreviation_hidden,
2103            instrument: made,
2104            default_clefs,
2105            brackets: brackets
2106                .into_iter()
2107                .map(|(_, kind, span)| (kind, span))
2108                .collect(),
2109            bracket_found,
2110            transposition,
2111        });
2112        first_staff += staves;
2113    }
2114    if parts.is_empty() {
2115        return Err(mscx_error("a score with no parts"));
2116    }
2117    Ok(parts)
2118}
2119
2120// --------------------------------------------------------------- assembly
2121
2122/// One element of a measure as music21 would hold it once read.
2123#[derive(Clone, Debug)]
2124struct Item {
2125    offset: FloatType,
2126    seq: usize,
2127    staff: usize,
2128    uid: Option<usize>,
2129    element: StreamElement,
2130}
2131
2132impl Item {
2133    fn order(&self) -> i32 {
2134        self.element.class_sort_order()
2135    }
2136
2137    fn is_grace(&self) -> bool {
2138        self.element.duration().is_some_and(Duration::is_grace)
2139    }
2140}
2141
2142fn sorted(mut items: Vec<Item>) -> Vec<Item> {
2143    items.sort_by(|left, right| {
2144        left.offset
2145            .total_cmp(&right.offset)
2146            .then(left.order().cmp(&right.order()))
2147            .then(right.is_grace().cmp(&left.is_grace()))
2148            .then(left.seq.cmp(&right.seq))
2149    });
2150    items
2151}
2152
2153#[derive(Clone, Debug, Default)]
2154struct VoiceIr {
2155    id: String,
2156    items: Vec<Item>,
2157}
2158
2159#[derive(Clone, Debug, Default)]
2160struct MeasureIr {
2161    offset: FloatType,
2162    number: IntegerType,
2163    suffix: Option<String>,
2164    hidden: bool,
2165    left: Option<Barline>,
2166    right: Option<Barline>,
2167    ending: Option<Ending>,
2168    items: Vec<Item>,
2169    voices: Vec<VoiceIr>,
2170}
2171
2172fn build_measure(measure: MeasureIr) -> (Stream, Vec<Option<usize>>) {
2173    let mut entries: Vec<(Item, Vec<Option<usize>>)> = Vec::new();
2174    for (index, voice) in measure.voices.into_iter().enumerate() {
2175        let mut uids = Vec::new();
2176        let mut events = Vec::new();
2177        for item in sorted(voice.items) {
2178            uids.push(item.uid);
2179            events.push(StreamEvent::new(item.offset, item.element));
2180        }
2181        let mut stream = Stream::from_events(events);
2182        stream.set_kind(StreamKind::Voice);
2183        stream.set_id(Some(voice.id));
2184        entries.push((
2185            Item {
2186                offset: 0.0,
2187                seq: index,
2188                staff: 0,
2189                uid: None,
2190                element: stream.into(),
2191            },
2192            uids,
2193        ));
2194    }
2195    let voices = entries.len();
2196    for mut item in measure.items {
2197        item.seq = item.seq.saturating_add(voices);
2198        let uid = item.uid;
2199        entries.push((item, vec![uid]));
2200    }
2201    entries.sort_by(|(left, _), (right, _)| {
2202        left.offset
2203            .total_cmp(&right.offset)
2204            .then(left.order().cmp(&right.order()))
2205            .then(right.is_grace().cmp(&left.is_grace()))
2206            .then(left.seq.cmp(&right.seq))
2207    });
2208    let mut uids = Vec::new();
2209    let mut events = Vec::new();
2210    for (item, leaf_uids) in entries {
2211        uids.extend(leaf_uids);
2212        events.push(StreamEvent::new(item.offset, item.element));
2213    }
2214    let mut stream = Stream::from_events(events);
2215    stream.set_kind(StreamKind::Measure);
2216    stream.set_number(measure.number);
2217    stream.set_number_suffix(measure.suffix);
2218    stream.set_number_hidden(measure.hidden);
2219    stream.set_left_barline(measure.left);
2220    stream.set_right_barline(measure.right);
2221    stream.set_ending(measure.ending);
2222    (stream, uids)
2223}
2224
2225/// The tuplets a note is written inside, outermost first, each marked where
2226/// it starts and stops.
2227fn tuplets_for(
2228    tuplets: &[TupletRead],
2229    innermost: Option<usize>,
2230    note: usize,
2231    brackets: &[bool],
2232) -> Vec<Tuplet> {
2233    let mut chain = Vec::new();
2234    let mut open = innermost;
2235    let mut held = Held::Note(note);
2236    while let Some(index) = open {
2237        let tuplet = &tuplets[index];
2238        let first = tuplet.elements.first() == Some(&held);
2239        let last = tuplet.elements.last() == Some(&held);
2240        let mut made = Tuplet::new(tuplet.actual, tuplet.normal, tuplet.base.0, tuplet.base.1);
2241        made.set_tuplet_type(match (first, last) {
2242            (true, true) => Some(TupletType::StartStop),
2243            (true, false) => Some(TupletType::Start),
2244            (false, true) => Some(TupletType::Stop),
2245            _ => None,
2246        });
2247        let bracket = match tuplet.bracket {
2248            1 => true,
2249            2 => false,
2250            // As the beams decide.
2251            _ => brackets[index],
2252        };
2253        made.set_bracket(if bracket {
2254            TupletBracket::Bracket
2255        } else {
2256            TupletBracket::None
2257        });
2258        match tuplet.number {
2259            1 => {
2260                made.set_normal_show(Some(TupletShow::Number));
2261            }
2262            2 => made.set_actual_show(None),
2263            _ => {}
2264        }
2265        made.set_placement(tuplet.placement);
2266        chain.push(made);
2267        held = Held::Tuplet(index);
2268        open = tuplet.parent;
2269    }
2270    chain.reverse();
2271    chain
2272}
2273
2274fn collect_notes(tuplets: &[TupletRead], index: usize, out: &mut Vec<usize>) {
2275    for held in &tuplets[index].elements {
2276        match held {
2277            Held::Note(note) => out.push(*note),
2278            Held::Tuplet(inner) => collect_notes(tuplets, *inner, out),
2279        }
2280    }
2281}
2282
2283/// The note, chord or rest a read one stands for.
2284fn element_of(
2285    read: &ChordRest,
2286    tuplets: Vec<Tuplet>,
2287    beams: Option<Beams>,
2288    beam_stem: StemDirection,
2289) -> Result<StreamElement> {
2290    // Its own stem direction, else its beam's; a note written with no
2291    // stem has neither.
2292    let stem = match read.stem {
2293        _ if read.no_stem => StemDirection::NoStem,
2294        _ if read.order < 3 => StemDirection::Unspecified,
2295        StemDirection::Unspecified => beam_stem,
2296        own => own,
2297    };
2298    let duration = duration_of(read, tuplets)?;
2299    let lyrics: Vec<Lyric> = read
2300        .lyrics
2301        .iter()
2302        .map(|lyric| {
2303            let mut made = Lyric::unsung();
2304            made.set_text(lyric.text.trim());
2305            made.set_syllabic(lyric.syllabic.unwrap_or(Syllabic::Single));
2306            made.set_number(lyric.number);
2307            made
2308        })
2309        .collect();
2310    // Fermatas, then an arpeggio, then the ornaments.
2311    let is_arpeggio = |expression: &&Expression| matches!(expression, Expression::Arpeggio(_));
2312    let expressions: Vec<Expression> = read
2313        .fermatas
2314        .iter()
2315        .cloned()
2316        .map(Expression::Fermata)
2317        .chain(read.expressions.iter().filter(is_arpeggio).cloned())
2318        .chain(
2319            read.expressions
2320                .iter()
2321                .filter(|expression| !is_arpeggio(expression))
2322                .cloned(),
2323        )
2324        .collect();
2325    if read.is_rest {
2326        let mut rest = Rest::new(duration);
2327        rest.set_hidden(read.hidden);
2328        if read.small {
2329            rest.set_size(Some(NoteSize::Cue));
2330        }
2331        rest.set_step_shift(read.step_shift);
2332        *rest.lyrics_mut() = lyrics;
2333        *rest.expressions_mut() = expressions;
2334        *rest.articulations_mut() = read.articulations.clone();
2335        return Ok(rest.into());
2336    }
2337    let mut notes: Vec<Note> = Vec::new();
2338    for written in &read.notes {
2339        let mut note = Note::from_pitch(written.pitch.clone());
2340        note.set_duration(duration.clone());
2341        // MuseScore hides a note's head and its stem each on its own, so a
2342        // hidden note is one with no head and not one left off the page.
2343        if written.hidden {
2344            note.set_notehead(Notehead::NoneShape);
2345        }
2346        if written.small || read.small {
2347            note.set_size(Some(NoteSize::Cue));
2348        }
2349        let tie = match (written.tie_start, written.tie_stop) {
2350            (true, true) => Some(TieType::Continue),
2351            (true, false) => Some(TieType::Start),
2352            (false, true) => Some(TieType::Stop),
2353            (false, false) => None,
2354        };
2355        note.set_tie(tie.map(|tie_type| {
2356            let mut tie = Tie::new(tie_type);
2357            if tie_type == TieType::Start {
2358                tie.set_placement(written.tie_placement);
2359            }
2360            tie
2361        }));
2362        if let Some(velocity) = written.velocity {
2363            // MuseScore's MusicXML writes a velocity as a percentage of
2364            // ninety to two places, which is as fine as the two can agree.
2365            let percent = (velocity as FloatType * 10000.0 / 90.0).round() / 100.0;
2366            note.set_volume(Some(Volume::from_velocity_scalar(
2367                percent * 90.0 / 12700.0,
2368            )?));
2369        }
2370        if let Some(head) = written.head {
2371            note.set_notehead(head);
2372        }
2373        if written.color.is_some() {
2374            note.set_color(written.color.clone());
2375        }
2376        if written.head_filled.is_some() {
2377            note.set_notehead_fill(written.head_filled);
2378        }
2379        note.set_stem_direction(stem);
2380        notes.push(note);
2381    }
2382    // The marks of the chord, each note's fingerings among them: those of
2383    // the lowest note first, then what is written on the chord itself, then
2384    // the fingerings of the notes above.
2385    let mut articulations: Vec<Articulation> = Vec::new();
2386    for (index, written) in read.notes.iter().enumerate() {
2387        articulations.extend(written.fingerings.iter().cloned());
2388        if index == 0 {
2389            articulations.extend(read.articulations.iter().cloned());
2390        }
2391    }
2392    if notes.len() == 1 {
2393        let mut note = notes.remove(0);
2394        if let Some(beams) = beams {
2395            note.set_beams(beams);
2396        }
2397        *note.lyrics_mut() = lyrics;
2398        *note.articulations_mut() = articulations;
2399        *note.expressions_mut() = expressions;
2400        return Ok(note.into());
2401    }
2402    if let Some(first) = notes.first_mut() {
2403        *first.lyrics_mut() = lyrics;
2404    }
2405    let mut chord = Chord::new(notes)?;
2406    chord.set_duration(duration);
2407    if let Some(beams) = beams {
2408        chord.set_beams(beams);
2409    }
2410    *chord.articulations_mut() = articulations;
2411    *chord.expressions_mut() = expressions;
2412    Ok(chord.into())
2413}
2414
2415fn duration_of(read: &ChordRest, tuplets: Vec<Tuplet>) -> Result<Duration> {
2416    let quarter_length = quarters(read.length);
2417    let Some((kind, dots)) = read.value else {
2418        return Duration::new(quarter_length);
2419    };
2420    if let Some(grace) = read.grace {
2421        let mut written = Duration::default();
2422        written.clear();
2423        written.set_tuplets(Vec::new());
2424        written.add_duration_tuple(kind, dots);
2425        let mut value = written.grace_duration();
2426        let mut marks = Grace::new();
2427        marks.set_slash(grace == GraceKind::Acciaccatura);
2428        value.set_grace(Some(marks));
2429        return Ok(value);
2430    }
2431    if tuplets.is_empty() {
2432        return Duration::new(quarter_length);
2433    }
2434    let mut duration = Duration::default();
2435    duration.clear();
2436    duration.set_tuplets(Vec::new());
2437    duration.add_duration_tuple(kind, dots);
2438    duration.set_tuplets(tuplets);
2439    if (duration.quarter_length() - quarter_length).abs() > 1e-7 {
2440        duration.set_linked(false);
2441        duration.set_quarter_length(quarter_length)?;
2442    }
2443    Ok(duration)
2444}
2445
2446/// A part put together out of its measures, with the uid of each leaf.
2447struct BuiltPart {
2448    stream: Stream,
2449    uids: Vec<Option<usize>>,
2450}
2451
2452/// Reads a MuseScore file into a score.
2453///
2454/// The text is an uncompressed `.mscx` as MuseScore 4 saves it, or as
2455/// MuseScore 3 does where the two formats are the same. A `.mscz` is a zip
2456/// archive holding one; the library opens no file and unpacks nothing, so
2457/// the caller hands over the text of the `.mscx` inside it.
2458///
2459/// Every `<Part>` is a part, and a part on several staves -- a piano -- is
2460/// a part for each staff joined by a brace, as a MusicXML reader makes it.
2461/// Pitches are spelled as the file spells them, and a transposing
2462/// instrument's are written as it reads them.
2463///
2464/// # What is read
2465///
2466/// - Parts, their names and abbreviations, instruments, MIDI programs and
2467///   channels, transpositions, and the brackets and braces joining staves.
2468/// - Measures and their numbers -- pickups, measures left out of the count,
2469///   sections that start again from one -- and up to four voices in each.
2470/// - Notes, chords and rests, measure rests among them: lengths, dots,
2471///   tuplets and tuplets inside tuplets, ties, written accidentals,
2472///   noteheads, colours, velocities, stems the file fixes, and grace notes
2473///   before and after a note.
2474/// - Clefs, key signatures, meters, tempo marks, dynamics, staff and system
2475///   text, lyrics and chord symbols.
2476/// - Articulations, fingerings, breath marks, fermatas on notes and on
2477///   barlines, ornaments and arpeggios.
2478/// - Barlines, repeats, endings, and the signs and words that send a
2479///   player elsewhere: segno, coda, *To Coda*, *Fine*, *D.C.* and *D.S.*
2480/// - Slurs, hairpins and pedal lines.
2481/// - The title, composer and the rest of the file's `metaTag`s.
2482///
2483/// A MuseScore file leaves some of what a page shows to be worked out when
2484/// the page is laid out, and that is worked out here as MuseScore does it:
2485/// beams from the meter and the beam modes of the notes, whether a tuplet
2486/// takes a bracket, the clef and key signature a staff starts with when
2487/// none is written, and the final barline.
2488///
2489/// # What is not read
2490///
2491/// What is only drawn -- frames, page and system breaks, positions, fonts,
2492/// rehearsal marks, and whatever is marked invisible -- is passed over.
2493/// MuseScore 4 keeps a score's style in a file of its own beside the
2494/// `.mscx`, which this function is not given; where the style decides
2495/// something, MuseScore's default is taken.
2496///
2497/// What the crate has no value for, or cannot read yet, is refused with an
2498/// [`Error::MuseScore`] naming it rather than dropped: percussion and
2499/// tablature staves, files in a format older than MuseScore 3's, tremolos,
2500/// trill, octave, glissando and text lines, arpeggios across staves,
2501/// ornaments with accidentals, key signatures of a score's own making,
2502/// measure repeats, fret diagrams, figured bass, instrument changes, shape
2503/// notes, and a chord symbol whose name is none the crate knows.
2504///
2505/// ```
2506/// use music21_rs::musescore::from_mscx;
2507///
2508/// let score = from_mscx(
2509///     r#"<museScore version="4.20"><Score>
2510///     <Part><Staff/><trackName>Flute</trackName>
2511///       <Instrument><longName>Flute</longName><trackName>Flute</trackName>
2512///       <Channel><program value="73"/></Channel></Instrument></Part>
2513///     <Staff id="1"><Measure><voice>
2514///       <TimeSig><sigN>2</sigN><sigD>4</sigD></TimeSig>
2515///       <Chord><durationType>quarter</durationType><Note><pitch>60</pitch><tpc>14</tpc></Note></Chord>
2516///       <Chord><durationType>quarter</durationType><Note><pitch>63</pitch><tpc>11</tpc></Note></Chord>
2517///     </voice></Measure></Staff>
2518///     </Score></museScore>"#,
2519/// )?;
2520/// let names: Vec<String> = score.parts()[0]
2521///     .pitches()
2522///     .iter()
2523///     .map(|pitch| pitch.name_with_octave())
2524///     .collect();
2525/// assert_eq!(names, ["C4", "Eb4"]);
2526/// # Ok::<(), music21_rs::Error>(())
2527/// ```
2528pub fn from_mscx(document: &str) -> Result<Stream> {
2529    let root = Xml::parse(document)?;
2530    if root.tag != "museScore" {
2531        return Err(mscx_error(format!(
2532            "a MuseScore file starts with <museScore>, not <{}>",
2533            root.tag
2534        )));
2535    }
2536    let version = root.get("version").unwrap_or("");
2537    let format: FloatType = version.parse().unwrap_or(0.0);
2538    if format < 3.0 {
2539        return Err(refused(format!("A file in MuseScore's format {version:?}")));
2540    }
2541    let score = root
2542        .find("Score")
2543        .ok_or_else(|| mscx_error("a MuseScore file with no <Score>"))?;
2544
2545    let program_version = root.child_text("programVersion");
2546    let program = if program_version.is_empty() {
2547        String::new()
2548    } else {
2549        let studio = program_version
2550            .split('.')
2551            .take(2)
2552            .map(|piece| piece.parse::<u32>().unwrap_or(0))
2553            .collect::<Vec<_>>();
2554        let renamed = studio.first().copied().unwrap_or(0) > 4
2555            || (studio.first() == Some(&4) && studio.get(1).copied().unwrap_or(0) >= 4);
2556        if renamed {
2557            format!("MuseScore Studio {program_version}")
2558        } else {
2559            format!("MuseScore {program_version}")
2560        }
2561    };
2562    let metadata = metadata_of(score, &program);
2563    // A score of one part does not print the part's name, unless its style
2564    // says otherwise. MuseScore 4 keeps the style in a file of its own,
2565    // which is not read; MuseScore 3 wrote it into the score.
2566    let hides_single_name = score
2567        .find("Style")
2568        .and_then(|style| style.find("hideInstrumentNameIfOneInstrument"))
2569        .is_none_or(|hide| hide.stripped() != "0");
2570    let parts = parts_of(score, hides_single_name)?;
2571    let staves: Vec<&Xml> = score.find_all("Staff").collect();
2572    let staff_count: usize = parts.iter().map(|part| part.staves).sum();
2573    if staves.len() != staff_count {
2574        return Err(mscx_error(format!(
2575            "{} staves are written for parts with {staff_count}",
2576            staves.len()
2577        )));
2578    }
2579
2580    let mut reader = Reader {
2581        old_format: format < 4.1,
2582        markers_by_label: format < 4.6,
2583        next_uid: 0,
2584        spanners: Vec::new(),
2585    };
2586    let mut read_staves: Vec<Vec<StaffMeasure>> = Vec::new();
2587    for part in &parts {
2588        for index in 0..part.staves {
2589            let global = part.first_staff + index;
2590            read_staves.push(reader.staff(staves[global], global, part.transposition)?);
2591        }
2592    }
2593    let measure_count = read_staves.first().map_or(0, Vec::len);
2594    if read_staves.iter().any(|staff| staff.len() != measure_count) {
2595        return Err(mscx_error("staves with different numbers of measures"));
2596    }
2597
2598    let grid = grid_of(&mut read_staves)?;
2599    Assembler {
2600        parts: &parts,
2601        staves: &read_staves,
2602        grid: &grid,
2603        spanners: &reader.spanners,
2604        uids: HashMap::new(),
2605        placed: Vec::new(),
2606    }
2607    .score(metadata)
2608}
2609
2610/// Where each measure starts and how long it is.
2611///
2612/// A clef, a key or a meter written at the very end of a measure is the
2613/// next measure's, and is moved to its start on the way.
2614fn grid_of(staves: &mut [Vec<StaffMeasure>]) -> Result<Grid> {
2615    let count = staves.first().map_or(0, Vec::len);
2616    let mut grid = Grid {
2617        starts: Vec::with_capacity(count),
2618        lengths: Vec::with_capacity(count),
2619        meters: Vec::with_capacity(count),
2620    };
2621    let mut meter = (4, 4);
2622    let mut start = Frac::zero();
2623    for index in 0..count {
2624        // The meter a measure starts with, from whichever staff says one.
2625        for staff in staves.iter() {
2626            let found = staff[index]
2627                .voices
2628                .iter()
2629                .flat_map(|voice| &voice.events)
2630                .find_map(|event| match &event.what {
2631                    What::Meter(written) if event.tick.is_zero() => Some(written),
2632                    _ => None,
2633                });
2634            if let Some(written) = found {
2635                meter = (
2636                    i64::from(written.numerator()),
2637                    i64::from(written.denominator()),
2638                );
2639                break;
2640            }
2641        }
2642        let length = staves
2643            .iter()
2644            .find_map(|staff| staff[index].len)
2645            .unwrap_or_else(|| Frac::new(meter.0, meter.1));
2646        grid.starts.push(start);
2647        grid.lengths.push(length);
2648        grid.meters.push(meter);
2649        start += length;
2650        if index + 1 < count {
2651            for staff in staves.iter_mut() {
2652                let mut moved: Vec<Event> = Vec::new();
2653                for voice in &mut staff[index].voices {
2654                    let (ending, kept): (Vec<Event>, Vec<Event>) =
2655                        std::mem::take(&mut voice.events)
2656                            .into_iter()
2657                            .partition(|event| {
2658                                event.tick == length
2659                                    && matches!(
2660                                        event.what,
2661                                        What::Clef(_) | What::Key(_) | What::Meter(_)
2662                                    )
2663                            });
2664                    voice.events = kept;
2665                    moved.extend(ending);
2666                }
2667                if moved.is_empty() {
2668                    continue;
2669                }
2670                let next = &mut staff[index + 1];
2671                if next.voices.is_empty() {
2672                    next.voices.push(VoiceRead::default());
2673                }
2674                for (place, mut event) in moved.into_iter().enumerate() {
2675                    event.tick = Frac::zero();
2676                    next.voices[0].events.insert(place, event);
2677                }
2678            }
2679        }
2680    }
2681    Ok(grid)
2682}
2683
2684struct Assembler<'a> {
2685    parts: &'a [PartRead],
2686    staves: &'a [Vec<StaffMeasure>],
2687    grid: &'a Grid,
2688    spanners: &'a [SpannerRead],
2689    /// Each note's uid by where it stands: measure, tick and track.
2690    uids: HashMap<(i64, Frac, usize, Option<usize>), usize>,
2691    /// Every note, chord and rest in the order MuseScore writes them out:
2692    /// part by part, measure by measure, staff by staff, voice by voice.
2693    placed: Vec<Placed>,
2694}
2695
2696/// A note, chord or rest by where it stands, from the top of the score.
2697#[derive(Clone, Copy, Debug)]
2698struct Placed {
2699    part: usize,
2700    track: usize,
2701    start: Frac,
2702    end: Frac,
2703    uid: usize,
2704}
2705
2706impl Assembler<'_> {
2707    fn score(mut self, metadata: Metadata) -> Result<Stream> {
2708        let mut built: Vec<BuiltPart> = Vec::new();
2709        let mut groups: Vec<StaffGroup> = Vec::new();
2710        let mut part_positions: Vec<Vec<usize>> = Vec::new();
2711        for (index, part) in self.parts.iter().enumerate() {
2712            let first = built.len();
2713            let staves = self.part(index, part)?;
2714            let count = staves.len();
2715            built.extend(staves);
2716            part_positions.push((first..first + count).collect());
2717            if count > 1 {
2718                let mut group = StaffGroup::new((first..first + count).collect());
2719                group.set_name(part.name.clone());
2720                group.set_symbol(Some("brace"))?;
2721                group.set_bar_together(Some(BarTogether::Yes));
2722                group.set_name_hidden(true);
2723                groups.push(group);
2724            }
2725        }
2726        groups.extend(self.part_groups(&part_positions)?);
2727        let mut uids: Vec<Option<usize>> = Vec::new();
2728        let mut events = Vec::new();
2729        for part in built {
2730            uids.extend(part.uids);
2731            events.push(StreamEvent::new(0.0, part.stream));
2732        }
2733        let mut assembled = Stream::from_events(events);
2734        assembled.set_kind(StreamKind::Score);
2735        assembled.set_metadata(Some(metadata));
2736        for group in groups {
2737            assembled.add_staff_group(group);
2738        }
2739        let position_of = |uid: usize| uids.iter().position(|held| *held == Some(uid));
2740        // A part's spanners in the order they start: measure by measure,
2741        // and in a measure staff by staff and voice by voice.
2742        let part_of = |track: usize| {
2743            self.parts
2744                .iter()
2745                .position(|part| {
2746                    (part.first_staff..part.first_staff + part.staves).contains(&(track / 4))
2747                })
2748                .unwrap_or(0)
2749        };
2750        let mut order: Vec<&SpannerRead> = self.spanners.iter().collect();
2751        order.sort_by_key(|spanner| {
2752            (
2753                part_of(spanner.start.track),
2754                spanner.start.measure,
2755                spanner.start.track,
2756                spanner.start.tick,
2757            )
2758        });
2759        for spanner in order {
2760            let (start, end) = (spanner.start, spanner.end);
2761            let made = match &spanner.kind {
2762                SpannerStart::Slur(placement, line_type) => {
2763                    let first = self
2764                        .uids
2765                        .get(&(start.measure, start.tick, start.track, start.grace))
2766                        .copied();
2767                    let last = self
2768                        .uids
2769                        .get(&(end.measure, end.tick, end.track, end.grace))
2770                        .copied();
2771                    let mut positions = Vec::new();
2772                    for uid in [first, last].into_iter().flatten() {
2773                        if let Some(position) = position_of(uid)
2774                            && !positions.contains(&Some(position))
2775                        {
2776                            positions.push(Some(position));
2777                        }
2778                    }
2779                    if positions.is_empty() {
2780                        continue;
2781                    }
2782                    let mut slur = Spanner::with_unplaced(SpannerKind::Slur, positions);
2783                    slur.set_placement(*placement);
2784                    slur.set_line_type(line_type.map(str::to_string));
2785                    slur
2786                }
2787                SpannerStart::Wedge(_) | SpannerStart::Pedal(_) => {
2788                    let part = part_of(start.track);
2789                    let mut positions: Vec<Option<usize>> = Vec::new();
2790                    if let Some(first) = self.line_start(part, start, end)
2791                        && let Some(position) = position_of(first)
2792                    {
2793                        positions.push(Some(position));
2794                    }
2795                    if let Some(last) = self.line_end(part, start, end)
2796                        && let Some(position) = position_of(last)
2797                        && !positions.contains(&Some(position))
2798                    {
2799                        positions.push(Some(position));
2800                    }
2801                    match &spanner.kind {
2802                        SpannerStart::Wedge(kind) => {
2803                            let template = Spanner::wedge(*kind, Vec::new());
2804                            let mut wedge = Spanner::with_unplaced(*kind, positions);
2805                            wedge.set_placement(template.placement());
2806                            wedge.set_spread(template.spread());
2807                            wedge
2808                        }
2809                        SpannerStart::Pedal(pedal) => {
2810                            let mut mark =
2811                                Spanner::with_unplaced(SpannerKind::PedalMark, positions);
2812                            mark.set_pedal(Some(*pedal));
2813                            mark
2814                        }
2815                        _ => continue,
2816                    }
2817                }
2818                SpannerStart::Volta { .. } => continue,
2819            };
2820            if made.is_empty() {
2821                continue;
2822            }
2823            assembled.add_spanner(made);
2824        }
2825        Ok(assembled)
2826    }
2827
2828    /// The note a line under the staff starts on. A line belongs to a staff
2829    /// and runs from one moment to another, not from note to note: it
2830    /// starts on the note of its staff standing where it starts, or on the
2831    /// first note of its voice to start under it, or else on the note
2832    /// sounding as it starts.
2833    fn line_start(&self, part: usize, start: Position, end: Position) -> Option<usize> {
2834        let from = *self.grid.starts.get(usize::try_from(start.measure).ok()?)? + start.tick;
2835        let to = *self.grid.starts.get(usize::try_from(end.measure).ok()?)? + end.tick;
2836        let staff = start.track / 4;
2837        let here = |placed: &&Placed| placed.part == part && placed.track / 4 == staff;
2838        let exact = self
2839            .placed
2840            .iter()
2841            .filter(here)
2842            .filter(|placed| placed.start == from)
2843            .min_by_key(|placed| placed.track);
2844        if let Some(exact) = exact {
2845            return Some(exact.uid);
2846        }
2847        let mut tracks: Vec<usize> = vec![start.track];
2848        tracks.extend((staff * 4..staff * 4 + 4).filter(|track| *track != start.track));
2849        for track in tracks {
2850            let voice = || {
2851                self.placed
2852                    .iter()
2853                    .filter(here)
2854                    .filter(move |placed| placed.track == track)
2855            };
2856            let under = voice()
2857                .filter(|placed| placed.start >= from && placed.start < to)
2858                .min_by_key(|placed| placed.start);
2859            let sounding = || voice().find(|placed| placed.start <= from && from < placed.end);
2860            if let Some(found) = under.or_else(sounding) {
2861                return Some(found.uid);
2862            }
2863        }
2864        None
2865    }
2866
2867    /// The note a line under the staff ends on: the note of its staff
2868    /// ending where it ends, or else the last note of its voice to start
2869    /// under it.
2870    fn line_end(&self, part: usize, start: Position, end: Position) -> Option<usize> {
2871        let from = *self.grid.starts.get(usize::try_from(start.measure).ok()?)? + start.tick;
2872        let to = *self.grid.starts.get(usize::try_from(end.measure).ok()?)? + end.tick;
2873        let staff = start.track / 4;
2874        let here = |placed: &&Placed| placed.part == part && placed.track / 4 == staff;
2875        let exact = self
2876            .placed
2877            .iter()
2878            .filter(here)
2879            .filter(|placed| placed.end == to)
2880            .min_by_key(|placed| placed.track);
2881        if let Some(exact) = exact {
2882            return Some(exact.uid);
2883        }
2884        let mut tracks: Vec<usize> = vec![start.track];
2885        tracks.extend((staff * 4..staff * 4 + 4).filter(|track| *track != start.track));
2886        for track in tracks {
2887            let voice = || {
2888                self.placed
2889                    .iter()
2890                    .filter(here)
2891                    .filter(move |placed| placed.track == track)
2892            };
2893            let last = voice()
2894                .filter(|placed| placed.start < to && placed.end > from)
2895                .max_by_key(|placed| placed.start);
2896            if let Some(found) = last {
2897                return Some(found.uid);
2898            }
2899        }
2900        None
2901    }
2902
2903    /// The brackets joining parts, as MuseScore's part list says them: a
2904    /// bracket on a part's first staff joins the parts its span reaches, a
2905    /// brace over exactly the staves of one part being that part's own.
2906    fn part_groups(&self, positions: &[Vec<usize>]) -> Result<Vec<StaffGroup>> {
2907        let mut groups: Vec<(i64, Vec<usize>)> = Vec::new();
2908        // Each open group's index and the staff it ends before.
2909        let mut open: Vec<Option<(usize, usize)>> = vec![None; 8];
2910        let mut staff_count = 0usize;
2911        let last = self.parts.len().saturating_sub(1);
2912        for (index, part) in self.parts.iter().enumerate() {
2913            let mut starting: Vec<(i64, usize)> = Vec::new();
2914            for (kind, span) in &part.brackets {
2915                if *span == part.staves && *kind == 1 {
2916                    continue;
2917                }
2918                if index < last {
2919                    starting.push((*kind, staff_count + span));
2920                }
2921            }
2922            if !part.bracket_found && part.staves > 1 {
2923                starting.push((-1, index + part.staves));
2924            }
2925            for (kind, end) in starting {
2926                if let Some(slot) = open.iter().position(Option::is_none) {
2927                    open[slot] = Some((groups.len(), end));
2928                    groups.push((kind, Vec::new()));
2929                }
2930            }
2931            for (group, _) in open.iter().flatten() {
2932                groups[*group].1.extend(positions[index].iter().copied());
2933            }
2934            staff_count += part.staves;
2935            for slot in open.iter_mut() {
2936                if let Some((_, end)) = slot
2937                    && staff_count >= *end
2938                {
2939                    *slot = None;
2940                }
2941            }
2942        }
2943        let mut out = Vec::new();
2944        for (kind, parts) in groups {
2945            let mut group = StaffGroup::new(parts);
2946            group.set_symbol(Some(match kind {
2947                0 => "bracket",
2948                1 => "brace",
2949                2 => "square",
2950                3 => "line",
2951                _ => "none",
2952            }))?;
2953            group.set_bar_together(Some(BarTogether::Yes));
2954            out.push(group);
2955        }
2956        Ok(out)
2957    }
2958
2959    /// A part, or one part for each of its staves.
2960    fn part(&mut self, index: usize, part: &PartRead) -> Result<Vec<BuiltPart>> {
2961        let measures = self.measures(index, part)?;
2962        if part.staves == 1 {
2963            let (stream, uids) = self.build(part, StreamKind::Part, None, measures);
2964            return Ok(vec![BuiltPart { stream, uids }]);
2965        }
2966        let mut out = Vec::new();
2967        let mut taken: Vec<usize> = Vec::new();
2968        for key in 1..=part.staves {
2969            let mut split = Vec::new();
2970            for measure in &measures {
2971                let mut copy = MeasureIr {
2972                    offset: measure.offset,
2973                    number: measure.number,
2974                    suffix: measure.suffix.clone(),
2975                    hidden: false,
2976                    left: measure.left.clone(),
2977                    right: measure.right.clone(),
2978                    ending: measure.ending.clone(),
2979                    items: Vec::new(),
2980                    voices: Vec::new(),
2981                };
2982                let mut seq = 0usize;
2983                let mut take = |items: &[Item], into: &mut Vec<Item>, seq: &mut usize| {
2984                    for item in sorted(items.to_vec()) {
2985                        if item.staff != 0 && item.staff != key {
2986                            continue;
2987                        }
2988                        let mut item = item;
2989                        let seq_key = item.uid.unwrap_or(usize::MAX);
2990                        if taken.contains(&seq_key) {
2991                            item.uid = None;
2992                        } else {
2993                            taken.push(seq_key);
2994                        }
2995                        item.seq = *seq;
2996                        *seq += 1;
2997                        into.push(item);
2998                    }
2999                };
3000                take(&measure.items, &mut copy.items, &mut seq);
3001                for voice in &measure.voices {
3002                    let mut items = Vec::new();
3003                    take(&voice.items, &mut items, &mut seq);
3004                    copy.voices.push(VoiceIr {
3005                        id: voice.id.clone(),
3006                        items,
3007                    });
3008                }
3009                copy.voices.retain(|voice| !voice.items.is_empty());
3010                if copy.voices.len() == 1 {
3011                    let voice = copy.voices.remove(0);
3012                    for mut item in sorted(voice.items) {
3013                        item.seq = seq;
3014                        seq += 1;
3015                        copy.items.push(item);
3016                    }
3017                }
3018                split.push(copy);
3019            }
3020            let id = format!("P{}-Staff{key}", index + 1);
3021            let (stream, uids) = self.build(part, StreamKind::PartStaff, Some(id), split);
3022            out.push(BuiltPart { stream, uids });
3023        }
3024        Ok(out)
3025    }
3026
3027    fn build(
3028        &self,
3029        part: &PartRead,
3030        kind: StreamKind,
3031        id: Option<String>,
3032        measures: Vec<MeasureIr>,
3033    ) -> (Stream, Vec<Option<usize>>) {
3034        let mut uids = vec![None];
3035        let mut events = vec![StreamEvent::new(0.0, part.instrument.clone())];
3036        for measure in measures {
3037            let offset = measure.offset;
3038            let (stream, leaf_uids) = build_measure(measure);
3039            uids.extend(leaf_uids);
3040            events.push(StreamEvent::new(offset, stream));
3041        }
3042        let mut stream = Stream::from_events(events);
3043        stream.set_kind(kind);
3044        stream.set_id(id.or_else(|| part.instrument.best_name().map(str::to_string)));
3045        stream.set_name(part.name.clone());
3046        stream.set_abbreviation(part.abbreviation.clone());
3047        if kind != StreamKind::PartStaff {
3048            stream.set_name_hidden(part.name_hidden);
3049            stream.set_abbreviation_hidden(part.abbreviation_hidden);
3050        }
3051        (stream, uids)
3052    }
3053
3054    /// Every measure of a part, all its staves together, as music21 holds
3055    /// a measure it has read before separating the staves.
3056    fn measures(&mut self, part_index: usize, part: &PartRead) -> Result<Vec<MeasureIr>> {
3057        let mut out: Vec<MeasureIr> = Vec::new();
3058        let mut number: IntegerType = 1;
3059        let mut irregular_count: IntegerType = 1;
3060        let mut last_number: IntegerType = 0;
3061        let mut last_suffix: Option<String> = None;
3062        let mut offset = 0.0;
3063        let mut last_meter: Option<TimeSignature> = None;
3064        let mut open_voltas: Vec<(Vec<u32>, i64)> = Vec::new();
3065        let count = self.grid.lengths.len();
3066        for index in 0..count {
3067            // What is said of a measure as a whole is said on the score's
3068            // first staff.
3069            let first_staff = &self.staves[0][index];
3070            // The measure's number, as MuseScore's MusicXML writes it and
3071            // music21 reads that.
3072            if first_staff.starts_section {
3073                number = 1;
3074                irregular_count = 1;
3075            }
3076            number += first_staff.number_offset as IntegerType;
3077            let (mut measure_number, mut suffix, hidden) =
3078                if first_staff.irregular && irregular_count + number == 2 {
3079                    (0, None, true)
3080                } else if first_staff.irregular {
3081                    let written = irregular_count;
3082                    irregular_count += 1;
3083                    (written, Some("X".to_string()), true)
3084                } else {
3085                    number += 1;
3086                    (number - 1, None, false)
3087                };
3088            if suffix.as_deref() == Some("X") && measure_number != last_number + 1 {
3089                let mut written = format!("X{measure_number}");
3090                if let Some(before) = &last_suffix {
3091                    written = format!("{before}{written}");
3092                }
3093                measure_number = last_number;
3094                suffix = Some(written);
3095            }
3096            if measure_number != last_number {
3097                last_number = measure_number;
3098                last_suffix = suffix.clone();
3099            }
3100
3101            let mut ir = MeasureIr {
3102                number: measure_number,
3103                suffix,
3104                hidden,
3105                ..MeasureIr::default()
3106            };
3107            let mut seq = 0usize;
3108            let mut push = |items: &mut Vec<Item>,
3109                            offset: FloatType,
3110                            staff: usize,
3111                            uid: Option<usize>,
3112                            element: StreamElement| {
3113                items.push(Item {
3114                    offset,
3115                    seq,
3116                    staff,
3117                    uid,
3118                    element,
3119                });
3120                seq += 1;
3121            };
3122
3123            // What the measure's staves hold, staff by staff, voice by voice.
3124            let mut voice_items: Vec<(String, Vec<Item>)> = Vec::new();
3125            let mut plain: Vec<Item> = Vec::new();
3126            let mut right: Option<Barline> = None;
3127            let mut right_fermata = false;
3128            // Signs and words saying where to go next are the first part's;
3129            // a sign stands ahead of the notes it stands with.
3130            if part_index == 0 {
3131                let target = usize::from(part.staves > 1);
3132                for mark in &first_staff.marks_at_start {
3133                    push(&mut plain, 0.0, target, None, mark.clone());
3134                }
3135            }
3136            for staff in 0..part.staves {
3137                let global = part.first_staff + staff;
3138                let staff_number = if part.staves > 1 { staff + 1 } else { 0 };
3139                let key_staff = staff + 1;
3140                let read = &self.staves[global][index];
3141                // A staff with no clef at its very start takes its
3142                // instrument's.
3143                if index == 0 {
3144                    let has_clef = read
3145                        .voices
3146                        .iter()
3147                        .flat_map(|voice| &voice.events)
3148                        .any(|event| matches!(event.what, What::Clef(_)) && event.tick.is_zero());
3149                    if !has_clef {
3150                        let clef = clef_named(&part.default_clefs[staff])?;
3151                        push(&mut plain, 0.0, key_staff, None, clef.into());
3152                    }
3153                    let has_key = read
3154                        .voices
3155                        .iter()
3156                        .flat_map(|voice| &voice.events)
3157                        .any(|event| matches!(event.what, What::Key(_)) && event.tick.is_zero());
3158                    if !has_key && staff == 0 {
3159                        push(&mut plain, 0.0, 0, None, KeySignature::new(0).into());
3160                    }
3161                }
3162                for (voice_index, voice) in read.voices.iter().enumerate() {
3163                    let track = global * 4 + voice_index;
3164                    let voice_id = if part.staves > 1 {
3165                        (staff * 4 + voice_index + 1).to_string()
3166                    } else {
3167                        (voice_index + 1).to_string()
3168                    };
3169                    let groups = self.beams_for(voice, index, voice_index, global)?;
3170                    let mut note_index = 0usize;
3171                    for event in &voice.events {
3172                        let at = quarters(event.tick);
3173                        match &event.what {
3174                            What::ChordRest(read_cr) => {
3175                                let beams = groups.beams.get(&note_index).cloned();
3176                                let tuplets = tuplets_for(
3177                                    &voice.tuplets,
3178                                    read_cr.tuplet,
3179                                    note_index,
3180                                    &groups.brackets,
3181                                );
3182                                note_index += 1;
3183                                // A chord may be written on the staff beside its
3184                                // own; a rest is not.
3185                                let staff_move = if read_cr.is_rest {
3186                                    0
3187                                } else {
3188                                    read_cr.staff_move
3189                                };
3190                                let cr_staff = if part.staves > 1 {
3191                                    (staff as i64 + 1 + staff_move).clamp(1, part.staves as i64)
3192                                        as usize
3193                                } else {
3194                                    0
3195                                };
3196                                let items =
3197                                    match voice_items.iter_mut().find(|(id, _)| *id == voice_id) {
3198                                        Some((_, items)) => items,
3199                                        None => {
3200                                            voice_items.push((voice_id.clone(), Vec::new()));
3201                                            &mut voice_items.last_mut().expect("just pushed").1
3202                                        }
3203                                    };
3204                                for (grace_index, grace) in read_cr.graces_before.iter().enumerate()
3205                                {
3206                                    let grace_beams = grace_beams(&read_cr.graces_before)
3207                                        .get(grace_index)
3208                                        .cloned()
3209                                        .flatten();
3210                                    let element = element_of(
3211                                        grace,
3212                                        Vec::new(),
3213                                        grace_beams,
3214                                        grace.beam_stem,
3215                                    )?;
3216                                    self.uids.insert(
3217                                        (index as i64, event.tick, track, Some(grace.grace_index)),
3218                                        grace.uid,
3219                                    );
3220                                    push(items, at, cr_staff, Some(grace.uid), element);
3221                                }
3222                                let beam_stem = groups
3223                                    .stems
3224                                    .get(&(note_index - 1))
3225                                    .copied()
3226                                    .unwrap_or(StemDirection::Unspecified);
3227                                let element = element_of(read_cr, tuplets, beams, beam_stem)?;
3228                                self.uids
3229                                    .insert((index as i64, event.tick, track, None), read_cr.uid);
3230                                let begins = self.grid.starts[index] + event.tick;
3231                                self.placed.push(Placed {
3232                                    part: part_index,
3233                                    track,
3234                                    start: begins,
3235                                    end: begins + read_cr.length,
3236                                    uid: read_cr.uid,
3237                                });
3238                                push(items, at, cr_staff, Some(read_cr.uid), element);
3239                                let end = quarters(event.tick + read_cr.length);
3240                                for (grace_index, grace) in read_cr.graces_after.iter().enumerate()
3241                                {
3242                                    let grace_beams = grace_beams(&read_cr.graces_after)
3243                                        .get(grace_index)
3244                                        .cloned()
3245                                        .flatten();
3246                                    let element = element_of(
3247                                        grace,
3248                                        Vec::new(),
3249                                        grace_beams,
3250                                        grace.beam_stem,
3251                                    )?;
3252                                    self.uids.insert(
3253                                        (index as i64, event.tick, track, Some(grace.grace_index)),
3254                                        grace.uid,
3255                                    );
3256                                    push(items, end, cr_staff, Some(grace.uid), element);
3257                                }
3258                            }
3259                            What::Clef(clef) => {
3260                                // A clef at the end of a measure is the next
3261                                // measure's.
3262                                if event.tick == self.grid.lengths[index] {
3263                                    continue;
3264                                }
3265                                push(&mut plain, at, key_staff, None, clef.clone().into());
3266                            }
3267                            What::Key(key) => {
3268                                if event.tick == self.grid.lengths[index] {
3269                                    continue;
3270                                }
3271                                if staff == 0 {
3272                                    push(&mut plain, at, 0, None, key.clone());
3273                                }
3274                            }
3275                            What::Meter(meter) => {
3276                                if event.tick == self.grid.lengths[index] {
3277                                    continue;
3278                                }
3279                                if staff == 0 {
3280                                    push(&mut plain, at, 0, None, meter.clone().into());
3281                                }
3282                            }
3283                            What::Element(element) => {
3284                                let target = if part.staves > 1 { staff + 1 } else { 0 };
3285                                let _ = staff_number;
3286                                push(&mut plain, at, target, None, element.clone());
3287                            }
3288                            What::Barline(barline, fermata) => {
3289                                if event.tick == self.grid.lengths[index] && staff == 0 {
3290                                    right = Some(barline.clone());
3291                                    right_fermata = *fermata;
3292                                }
3293                            }
3294                        }
3295                    }
3296                }
3297            }
3298            if part_index == 0 {
3299                let target = usize::from(part.staves > 1);
3300                let end = quarters(self.grid.lengths[index]);
3301                for mark in &first_staff.marks_at_end {
3302                    push(&mut plain, end, target, None, mark.clone());
3303                }
3304            }
3305            if part.staves == 1 {
3306                for item in &mut plain {
3307                    item.staff = 0;
3308                }
3309            }
3310
3311            // Repeats and endings.
3312            if first_staff.start_repeat {
3313                ir.left = Some(Barline::repeat(RepeatDirection::Start, None));
3314            }
3315            if let Some(times) = first_staff.end_repeat {
3316                let times = (times > 2).then_some(times);
3317                ir.right = Some(Barline::repeat(RepeatDirection::End, times));
3318            } else {
3319                // An ordinary barline written out is what a measure ends
3320                // with anyway, and stands in the way of any other.
3321                ir.right = match right {
3322                    Some(barline)
3323                        if barline.bar_type() == BarlineType::Regular && !right_fermata =>
3324                    {
3325                        None
3326                    }
3327                    Some(barline) => Some(barline),
3328                    None => self.drawn_barline(index),
3329                };
3330            }
3331            for spanner in self.spanners {
3332                if let SpannerStart::Volta { numbers } = &spanner.kind
3333                    && spanner.start.measure == index as i64
3334                    && spanner.start.track / 4 >= part.first_staff
3335                    && spanner.start.track / 4 < part.first_staff + part.staves
3336                {
3337                    let end = self.measure_at(spanner.end);
3338                    open_voltas.push((numbers.clone(), end));
3339                }
3340            }
3341            if let Some(position) = open_voltas.iter().position(|(_, end)| index as i64 <= *end) {
3342                let (numbers, end) = open_voltas[position].clone();
3343                let starts = self.volta_start(&numbers, index, part);
3344                let stops = index as i64 == end;
3345                ir.ending = Some(Ending::new(numbers.clone(), starts, stops));
3346                // A bracket starts and ends on a barline, an ordinary one
3347                // where the measure has no other.
3348                if starts && ir.left.is_none() {
3349                    ir.left = Some(Barline::default());
3350                }
3351                if stops {
3352                    if ir.right.is_none() {
3353                        ir.right = Some(Barline::default());
3354                    }
3355                    open_voltas.remove(position);
3356                }
3357            }
3358
3359            let use_voices = voice_items.len() > 1;
3360            if use_voices {
3361                voice_items.sort_by(|left, right| left.0.cmp(&right.0));
3362                ir.voices = voice_items
3363                    .into_iter()
3364                    .map(|(id, items)| VoiceIr { id, items })
3365                    .collect();
3366                ir.items = plain;
3367            } else {
3368                ir.items = plain;
3369                for (_, items) in voice_items {
3370                    ir.items.extend(items);
3371                }
3372            }
3373
3374            // Where the measure stands, as music21 works it out.
3375            let own_meter = ir.items.iter().find_map(|item| match &item.element {
3376                StreamElement::TimeSignature(meter) => Some(meter.clone()),
3377                _ => None,
3378            });
3379            if let Some(meter) = own_meter {
3380                last_meter = Some(meter);
3381            } else if last_meter.is_none() {
3382                last_meter = Some(TimeSignature::new(4, 4)?);
3383            }
3384            ir.offset = offset;
3385            offset = op_frac(offset + quarters(self.grid.lengths[index]));
3386            let _ = part_index;
3387            out.push(ir);
3388        }
3389        Ok(out)
3390    }
3391
3392    /// The barline a measure ends with where it writes none of its own: a
3393    /// final one at the end of the score, which MuseScore draws without
3394    /// being told. The double barline it draws before a courtesy key
3395    /// signature depends on where a system ends, which is the page's to
3396    /// say, and is not one of these.
3397    fn drawn_barline(&self, index: usize) -> Option<Barline> {
3398        (index + 1 == self.staves[0].len()).then(|| Barline::new(BarlineType::Final))
3399    }
3400
3401    /// Whether a volta starting at this measure is the first measure of it.
3402    fn volta_start(&self, _numbers: &[u32], index: usize, part: &PartRead) -> bool {
3403        self.spanners.iter().any(|spanner| {
3404            matches!(spanner.kind, SpannerStart::Volta { .. })
3405                && spanner.start.measure == index as i64
3406                && spanner.start.track / 4 >= part.first_staff
3407                && spanner.start.track / 4 < part.first_staff + part.staves
3408        })
3409    }
3410
3411    /// The last measure a spanner ending here covers.
3412    fn measure_at(&self, end: Position) -> i64 {
3413        let Some(start) = self.grid.starts.get(end.measure.max(0) as usize) else {
3414            return self.grid.starts.len() as i64 - 1;
3415        };
3416        let at = *start + end.tick;
3417        let mut last = 0;
3418        for (index, begins) in self.grid.starts.iter().enumerate() {
3419            if *begins < at {
3420                last = index as i64;
3421            }
3422        }
3423        last
3424    }
3425
3426    /// The beams of every note of a voice.
3427    fn beams_for(
3428        &self,
3429        voice: &VoiceRead,
3430        index: usize,
3431        voice_index: usize,
3432        _staff: usize,
3433    ) -> Result<Beamed> {
3434        let (numerator, denominator) = self.grid.meters[index];
3435        let groups_table = beams::default_groups(numerator, denominator);
3436        let bar = Frac::new(numerator, denominator);
3437        let anacrusis = if index == 0 && self.grid.lengths[0] < bar {
3438            ticks(bar - self.grid.lengths[0])
3439        } else {
3440            0
3441        };
3442        let context = beams::Context {
3443            groups: &groups_table,
3444            denominator,
3445            anacrusis,
3446            voice: voice_index,
3447        };
3448        let mut members = Vec::new();
3449        let mut written_stems = Vec::new();
3450        for event in &voice.events {
3451            if let What::ChordRest(read) = &event.what {
3452                members.push(member_of(read));
3453                written_stems.push((read.beam_stem, read.staff_move != 0));
3454            }
3455        }
3456        let groups = beams::beam_groups(&context, &members);
3457        let mut beams = HashMap::new();
3458        let mut stems = HashMap::new();
3459        for group in &groups {
3460            let held: Vec<&Member> = group.iter().map(|index| &members[*index]).collect();
3461            for (at, made) in group.iter().zip(beams::beams_of_group(&held)) {
3462                if !members[*at].is_rest {
3463                    beams.insert(*at, made);
3464                }
3465            }
3466            // A beam written out with a direction turns every stem under
3467            // it, unless it runs between two staves, where the stems of
3468            // each staff go their own way.
3469            let direction = group
3470                .iter()
3471                .map(|at| written_stems[*at].0)
3472                .find(|stem| *stem != StemDirection::Unspecified);
3473            let crosses = group.iter().any(|at| written_stems[*at].1);
3474            if let Some(direction) = direction
3475                && !crosses
3476            {
3477                for at in group {
3478                    stems.insert(*at, direction);
3479                }
3480            }
3481        }
3482        // Whether each tuplet that leaves its bracket to MuseScore takes
3483        // one.
3484        let under: Vec<Vec<usize>> = (0..voice.tuplets.len())
3485            .map(|index| {
3486                let mut notes = Vec::new();
3487                collect_notes(&voice.tuplets, index, &mut notes);
3488                notes
3489            })
3490            .collect();
3491        let tuplet_ticks =
3492            |index: usize| -> i64 { under[index].iter().map(|note| members[*note].ticks).sum() };
3493        let brackets = voice
3494            .tuplets
3495            .iter()
3496            .enumerate()
3497            .map(|(index, tuplet)| {
3498                let own: Vec<usize> = tuplet
3499                    .elements
3500                    .iter()
3501                    .filter_map(|held| match held {
3502                        Held::Note(note) => Some(*note),
3503                        Held::Tuplet(_) => None,
3504                    })
3505                    .collect();
3506                beams::tuplet_has_bracket(
3507                    &context,
3508                    &members,
3509                    &groups,
3510                    &beams::TupletShape {
3511                        notes: &under[index],
3512                        own: &own,
3513                        nests: own.len() != tuplet.elements.len(),
3514                    },
3515                    &tuplet_ticks,
3516                )
3517            })
3518            .collect();
3519        Ok(Beamed {
3520            beams,
3521            stems,
3522            brackets,
3523        })
3524    }
3525}
3526
3527struct Beamed {
3528    beams: HashMap<usize, Beams>,
3529    /// Whether each tuplet of the voice is drawn with a bracket, where it
3530    /// leaves that to MuseScore.
3531    brackets: Vec<bool>,
3532    /// The stem direction each beamed note takes from its beam.
3533    stems: HashMap<usize, StemDirection>,
3534}
3535
3536fn member_of(read: &ChordRest) -> Member {
3537    let dots = read.value.map_or(0, |(_, dots)| dots);
3538    Member {
3539        tick: ticks(read.tick),
3540        ticks: ticks(read.length),
3541        value: (if read.measure_rest { 14 } else { read.order }, dots),
3542        is_rest: read.is_rest,
3543        mode: read.mode,
3544        tuplet: read.tuplet,
3545    }
3546}
3547
3548/// The beams of a run of grace notes.
3549fn grace_beams(graces: &[ChordRest]) -> Vec<Option<Beams>> {
3550    let members: Vec<Member> = graces.iter().map(member_of).collect();
3551    let mut out = vec![None; graces.len()];
3552    for group in beams::grace_groups(&members) {
3553        let held: Vec<&Member> = group.iter().map(|index| &members[*index]).collect();
3554        for (at, made) in group.iter().zip(beams::beams_of_group(&held)) {
3555            out[*at] = Some(made);
3556        }
3557    }
3558    out
3559}
3560
3561#[cfg(test)]
3562mod tests {
3563    use super::*;
3564
3565    fn document(voice: &str) -> String {
3566        format!(
3567            r#"<museScore version="4.70"><Score>
3568            <Part><Staff/><trackName>Flute</trackName>
3569            <Instrument><longName>Flute</longName><trackName>Flute</trackName>
3570            <Channel><program value="73"/></Channel></Instrument></Part>
3571            <Staff id="1"><Measure><voice>
3572            <TimeSig><sigN>4</sigN><sigD>4</sigD></TimeSig>{voice}</voice></Measure></Staff>
3573            </Score></museScore>"#
3574        )
3575    }
3576
3577    fn chord(value: &str, pitch: i64, tpc: i64) -> String {
3578        format!(
3579            "<Chord><durationType>{value}</durationType><Note><pitch>{pitch}</pitch>\
3580             <tpc>{tpc}</tpc></Note></Chord>"
3581        )
3582    }
3583
3584    #[test]
3585    fn a_tonal_pitch_class_spells_its_note() {
3586        assert_eq!(spelling(14).unwrap(), ('C', 0));
3587        assert_eq!(spelling(21).unwrap(), ('C', 1));
3588        assert_eq!(spelling(-1).unwrap(), ('F', -2));
3589        // The letter and the octave; the accidental is the note's to add.
3590        assert_eq!(pitch_of(60, 26).unwrap().name_with_octave(), "B3");
3591        assert_eq!(pitch_of(59, 7).unwrap().name_with_octave(), "C4");
3592    }
3593
3594    #[test]
3595    fn notes_follow_one_another_and_eighths_are_beamed() {
3596        let body = [
3597            chord("eighth", 60, 14),
3598            chord("eighth", 62, 16),
3599            chord("quarter", 64, 18),
3600            chord("half", 65, 13),
3601        ]
3602        .concat();
3603        let score = from_mscx(&document(&body)).unwrap();
3604        let notes = score.parts()[0].notes();
3605        let offsets: Vec<FloatType> = notes.iter().map(|(offset, _)| *offset).collect();
3606        assert_eq!(offsets, [0.0, 0.5, 1.0, 2.0]);
3607        let beams: Vec<usize> = notes
3608            .iter()
3609            .map(|(_, element)| match element {
3610                StreamElement::Note(note) => note.beams().len(),
3611                _ => 0,
3612            })
3613            .collect();
3614        assert_eq!(beams, [1, 1, 0, 0]);
3615    }
3616
3617    #[test]
3618    fn a_triplet_shortens_its_notes() {
3619        let body = format!(
3620            "<Tuplet><normalNotes>2</normalNotes><actualNotes>3</actualNotes>\
3621             <baseNote>eighth</baseNote></Tuplet>{}{}{}<endTuplet/>\
3622             <Chord><durationType>quarter</durationType><dots>1</dots><Note><pitch>60</pitch><tpc>14</tpc></Note></Chord>\
3623             <Rest><durationType>quarter</durationType></Rest>",
3624            chord("eighth", 60, 14),
3625            chord("eighth", 62, 16),
3626            chord("eighth", 64, 18),
3627        );
3628        let score = from_mscx(&document(&body)).unwrap();
3629        let lengths: Vec<FloatType> = score.parts()[0].measures()[0]
3630            .events()
3631            .iter()
3632            .map(|event| event.element().quarter_length())
3633            .filter(|length| *length > 0.0)
3634            .collect();
3635        assert_eq!(lengths.len(), 5);
3636        assert!((lengths[0] - 1.0 / 3.0).abs() < 1e-9);
3637        assert_eq!(lengths[3], 1.5);
3638    }
3639
3640    /// The notes of the first measure of the first part.
3641    fn notes_of(score: &Stream) -> Vec<Note> {
3642        score.parts()[0].measures()[0]
3643            .events()
3644            .iter()
3645            .filter_map(|event| match event.element() {
3646                StreamElement::Note(note) => Some(note.clone()),
3647                _ => None,
3648            })
3649            .collect()
3650    }
3651
3652    #[test]
3653    fn a_grace_note_is_slashed_only_where_it_is_an_acciaccatura() {
3654        let grace = |kind: &str| {
3655            format!(
3656                "<Chord><durationType>eighth</durationType><{kind}/>\
3657                 <Note><pitch>62</pitch><tpc>16</tpc></Note></Chord>"
3658            )
3659        };
3660        let body = [
3661            grace("acciaccatura"),
3662            chord("half", 60, 14),
3663            grace("appoggiatura"),
3664            chord("half", 60, 14),
3665        ]
3666        .concat();
3667        let notes = notes_of(&from_mscx(&document(&body)).unwrap());
3668        let slashed: Vec<Option<bool>> = notes
3669            .iter()
3670            .map(|note| {
3671                note.duration()
3672                    .and_then(Duration::grace)
3673                    .map(|grace| grace.slash())
3674            })
3675            .collect();
3676        assert_eq!(slashed, [Some(true), None, Some(false), None]);
3677    }
3678
3679    #[test]
3680    fn a_stem_points_where_the_file_fixes_it_and_nowhere_otherwise() {
3681        let body = format!(
3682            "<Chord><durationType>quarter</durationType><StemDirection>up</StemDirection>\
3683             <Note><pitch>72</pitch><tpc>14</tpc></Note></Chord>{}\
3684             <Chord><durationType>half</durationType><noStem>1</noStem>\
3685             <Note><pitch>72</pitch><tpc>14</tpc></Note></Chord>",
3686            chord("quarter", 72, 14),
3687        );
3688        let stems: Vec<StemDirection> = notes_of(&from_mscx(&document(&body)).unwrap())
3689            .iter()
3690            .map(Note::stem_direction)
3691            .collect();
3692        assert_eq!(
3693            stems,
3694            [
3695                StemDirection::Up,
3696                StemDirection::Unspecified,
3697                StemDirection::NoStem
3698            ]
3699        );
3700    }
3701
3702    #[test]
3703    fn a_notehead_a_colour_and_a_fingering_are_read_off_the_note() {
3704        let body = "<Chord><durationType>whole</durationType><Note><pitch>60</pitch>\
3705                    <tpc>14</tpc><head>cross</head>\
3706                    <color r=\"255\" g=\"38\" b=\"0\" a=\"255\"/>\
3707                    <Fingering><text>3</text></Fingering></Note></Chord>";
3708        let notes = notes_of(&from_mscx(&document(body)).unwrap());
3709        assert_eq!(notes[0].notehead(), Notehead::from_name("x").unwrap());
3710        assert_eq!(notes[0].color(), Some("#FF2600"));
3711        assert_eq!(notes[0].articulations().len(), 1);
3712        assert!(notes[0].articulations()[0].is_a("Fingering"));
3713    }
3714
3715    #[test]
3716    fn a_tuplet_takes_a_bracket_unless_a_beam_sets_it_apart() {
3717        let triplet = |value: &str| {
3718            format!(
3719                "<Tuplet><normalNotes>2</normalNotes><actualNotes>3</actualNotes>                 <baseNote>{value}</baseNote></Tuplet>{}{}{}<endTuplet/>",
3720                chord(value, 60, 14),
3721                chord(value, 62, 16),
3722                chord(value, 64, 18),
3723            )
3724        };
3725        let body = [
3726            triplet("eighth"),
3727            triplet("quarter"),
3728            chord("quarter", 60, 14),
3729        ]
3730        .concat();
3731        let brackets: Vec<TupletBracket> = notes_of(&from_mscx(&document(&body)).unwrap())
3732            .iter()
3733            .filter_map(|note| {
3734                note.duration()
3735                    .and_then(|length| length.tuplets().first().cloned())
3736            })
3737            .map(|tuplet| tuplet.bracket())
3738            .collect();
3739        // Three beamed eighths, then three quarters no beam can join.
3740        assert_eq!(brackets[..3], [TupletBracket::None; 3]);
3741        assert_eq!(brackets[3..], [TupletBracket::Bracket; 3]);
3742    }
3743
3744    /// A score of one whole note with something written in its measure.
3745    fn marked(version: &str, mark: &str) -> String {
3746        format!(
3747            r#"<museScore version="{version}"><Score>
3748            <Part><Staff/><trackName>Flute</trackName>
3749            <Instrument><longName>Flute</longName><trackName>Flute</trackName>
3750            <Channel><program value="73"/></Channel></Instrument></Part>
3751            <Staff id="1"><Measure>{mark}<voice>
3752            <TimeSig><sigN>4</sigN><sigD>4</sigD></TimeSig>{}</voice></Measure></Staff>
3753            </Score></museScore>"#,
3754            chord("whole", 60, 14)
3755        )
3756    }
3757
3758    /// The signs and jumps of the first measure, each with its offset.
3759    fn repeat_marks(score: &Stream) -> Vec<(FloatType, RepeatExpressionKind)> {
3760        score.parts()[0].measures()[0]
3761            .events()
3762            .iter()
3763            .filter_map(|event| match event.element() {
3764                StreamElement::RepeatExpression(mark) => Some((event.offset(), mark.kind())),
3765                _ => None,
3766            })
3767            .collect()
3768    }
3769
3770    #[test]
3771    fn a_marker_is_of_the_kind_the_file_says_in_the_way_its_format_says_it() {
3772        let segno = "<Marker><text><sym>segno</sym></text><label>segno</label></Marker>";
3773        let typed = "<Marker><text><sym>segno</sym></text><label>segno</label>\
3774                     <markerType>segno</markerType></Marker>";
3775        // Before format 4.6 the label says what a marker is.
3776        let old = from_mscx(&marked("4.40", segno)).unwrap();
3777        assert_eq!(repeat_marks(&old), [(0.0, RepeatExpressionKind::Segno)]);
3778        // From 4.6 on its kind is said apart, and one that says none is the
3779        // end of the piece, as MuseScore reads it.
3780        let new = from_mscx(&marked("4.70", typed)).unwrap();
3781        assert_eq!(repeat_marks(&new), [(0.0, RepeatExpressionKind::Segno)]);
3782        let untyped = from_mscx(&marked("4.70", segno)).unwrap();
3783        assert!(
3784            !repeat_marks(&untyped)
3785                .iter()
3786                .any(|(_, kind)| *kind == RepeatExpressionKind::Segno)
3787        );
3788        // A jump stands at the end of its measure.
3789        let jump = "<Jump><text>D.C.</text><jumpTo>start</jumpTo><playUntil>end</playUntil>\
3790                    <continueAt></continueAt></Jump>";
3791        let jumped = from_mscx(&marked("4.70", jump)).unwrap();
3792        assert_eq!(repeat_marks(&jumped), [(4.0, RepeatExpressionKind::DaCapo)]);
3793    }
3794
3795    #[test]
3796    fn what_the_model_has_no_value_for_is_refused_by_name() {
3797        let tremolo = "<Chord><durationType>whole</durationType><Tremolo><subtype>r8</subtype>\
3798                       </Tremolo><Note><pitch>60</pitch><tpc>14</tpc></Note></Chord>";
3799        let error = from_mscx(&document(tremolo)).unwrap_err().to_string();
3800        assert!(
3801            error.contains("Tremolo") && error.contains("cannot be read yet"),
3802            "{error}"
3803        );
3804        let trill = "<Spanner type=\"Trill\"><Trill/><next><location><measures>1</measures>\
3805                     </location></next></Spanner>";
3806        let error = from_mscx(&document(&[trill, &chord("whole", 60, 14)].concat()))
3807            .unwrap_err()
3808            .to_string();
3809        assert!(error.contains("Trill"), "{error}");
3810    }
3811
3812    #[test]
3813    fn what_is_not_a_musescore_file_is_refused() {
3814        assert!(from_mscx("<score-partwise/>").is_err());
3815        assert!(from_mscx("not xml").is_err());
3816        assert!(from_mscx(r#"<museScore version="2.06"><Score/></museScore>"#).is_err());
3817    }
3818}