Skip to main content

music21/abc/
read.rs

1//! Reading ABC: music21's `abcFormat`, its tokens and handlers, and
2//! `abcFormat.translate`, which turns them into a score.
3//!
4//! The text is cut into tokens one character at a time, each token is told
5//! what is in force where it stands -- the default length, the key, a tuplet,
6//! a tie -- and the tokens of each voice are then read off measure by
7//! measure. The order and the oddities are music21's throughout, since the
8//! score it makes is what this one is held to.
9
10use crate::articulations::{Articulation, ArticulationKind};
11use crate::bar::{Barline, BarlineType, Ending, RepeatDirection};
12use crate::chord::Chord;
13use crate::chordsymbol::ChordSymbol;
14use crate::clef::Clef;
15use crate::defaults::{FloatType, IntegerType};
16use crate::duration::{Duration, Tuplet};
17use crate::error::{Error, FormatErrorKind, Position, Result};
18use crate::interval::Interval;
19use crate::key::KeySignature;
20use crate::makenotation::split_element;
21use crate::metadata::Metadata;
22use crate::meter::TimeSignature;
23use crate::notation::{Tie, TieStyle, TieType};
24use crate::note::Note;
25use crate::pitch::Pitch;
26use crate::rest::Rest;
27use crate::spanner::{Spanner, SpannerKind};
28use crate::stream::{Stream, StreamElement, StreamEvent, StreamKind};
29use crate::tempo::MetronomeMark;
30
31fn abc_error(message: impl Into<String>) -> Error {
32    Error::abc(message.into())
33}
34
35/// The ABC version a file is read as where it names none: music21's
36/// `defaults.abcVersionDefault`.
37const DEFAULT_VERSION: (u32, u32, u32) = (1, 3, 0);
38
39/// Every bar token, in the order music21 tries them.
40const BARS: [(&str, &str); 14] = [
41    (":|1", "light-heavy-repeat-end-first"),
42    (":|2", "light-heavy-repeat-end-second"),
43    ("|]", "light-heavy"),
44    ("||", "light-light"),
45    ("[|", "heavy-light"),
46    ("[1", "regular-first"),
47    ("[2", "regular-second"),
48    ("|1", "regular-first"),
49    ("|2", "regular-second"),
50    (":|", "light-heavy-repeat-end"),
51    ("|:", "heavy-light-repeat-start"),
52    ("::", "heavy-heavy-repeat-bidirectional"),
53    ("|", "regular"),
54    (":", "dotted"),
55];
56
57/// music21's `opFrac`, near enough for lengths: the nearest fraction with a
58/// small denominator where the float is within a hair of one.
59fn op_frac(value: FloatType) -> FloatType {
60    if (value * 32768.0).fract() == 0.0 {
61        return value;
62    }
63    for denominator in 1..=65535u32 {
64        let scaled = value * FloatType::from(denominator);
65        if (scaled - scaled.round()).abs() < 1e-9 * FloatType::from(denominator).max(1.0) {
66            return scaled.round() / FloatType::from(denominator);
67        }
68    }
69    value
70}
71
72// ------------------------------------------------------------------ tokens
73
74/// music21's `ABCBar`.
75#[derive(Clone, Debug, Default, PartialEq)]
76struct Bar {
77    src: String,
78    /// `repeat` or `barline`, nothing where the text is no bar at all.
79    repeat: bool,
80    style: String,
81    /// `end`, `start`, `first` or `second`.
82    form: String,
83}
84
85impl Bar {
86    fn new(src: &str) -> Self {
87        let mut bar = Self {
88            src: src.to_string(),
89            ..Self::default()
90        };
91        let Some((_, described)) = BARS.iter().find(|(text, _)| *text == src.trim()) else {
92            return bar;
93        };
94        let parts: Vec<&str> = described.split('-').collect();
95        bar.repeat = parts.contains(&"repeat");
96        if parts.len() == 1 {
97            bar.style = parts[0].to_string();
98        } else if parts.contains(&"first") {
99            bar.style = "regular".to_string();
100            bar.form = "first".to_string();
101        } else if parts.contains(&"second") {
102            bar.style = "regular".to_string();
103            bar.form = "second".to_string();
104        } else {
105            bar.style = format!("{}-{}", parts[0], parts[1]);
106        }
107        if parts.len() > 2 {
108            bar.form = parts[3].to_string();
109        }
110        bar
111    }
112
113    fn is_regular(&self) -> bool {
114        !self.repeat && self.style == "regular"
115    }
116
117    /// Which ending the bar opens, where it opens one.
118    fn repeat_bracket(&self) -> Option<u32> {
119        match self.form.as_str() {
120            "first" => Some(1),
121            "second" => Some(2),
122            _ => None,
123        }
124    }
125
126    /// music21's `getBarObject`.
127    fn barline(&self) -> Option<Barline> {
128        if self.repeat {
129            return match self.form.as_str() {
130                "start" => Some(Barline::repeat(RepeatDirection::Start, None)),
131                "end" => Some(Barline::repeat(RepeatDirection::End, None)),
132                _ => None,
133            };
134        }
135        if self.style == "regular" || self.style.is_empty() || self.repeat_bracket().is_some() {
136            return None;
137        }
138        BarlineType::from_name(&self.style).ok().map(Barline::new)
139    }
140}
141
142/// music21's `ABCNote`, and `ABCChord` where it holds notes of its own.
143#[derive(Clone, Debug, Default)]
144struct AbcNote {
145    src: String,
146    /// The line of the text it starts on.
147    line: usize,
148    is_chord: bool,
149    carried_accidental: String,
150    chord_symbols: Vec<String>,
151    in_grace: bool,
152    default_quarter_length: Option<FloatType>,
153    /// The mark and whether this note stands to its left.
154    broken_rhythm: Option<(String, bool)>,
155    key: Option<KeySignature>,
156    tuplet: Option<Tuplet>,
157    /// The spanners in force, by where they stand among the handler's.
158    spanners: Vec<usize>,
159    tie: Option<TieType>,
160    articulations: Vec<&'static str>,
161    accidental_display: Option<bool>,
162    is_rest: bool,
163    pitch_name: Option<String>,
164    quarter_length: FloatType,
165    sub_tokens: Vec<AbcNote>,
166}
167
168#[derive(Clone, Debug)]
169enum Token {
170    Metadata {
171        tag: String,
172        data: String,
173        line: usize,
174    },
175    Bar(Bar),
176    Tuplet {
177        src: String,
178        line: usize,
179    },
180    Tie,
181    /// A slur or a hairpin opening: the spanner it starts.
182    SpannerStart(SpannerKind, Option<usize>),
183    /// A closing `)`, or a hairpin's `!crescendo)!` or `!diminuendo)!`.
184    ParenStop {
185        hairpin: bool,
186    },
187    Staccato,
188    Upbow,
189    Downbow,
190    Accent,
191    Straccent,
192    Tenuto,
193    GraceStart,
194    GraceStop,
195    BrokenRhythm(String),
196    Note(Box<AbcNote>),
197}
198
199impl Token {
200    fn is_note(&self) -> bool {
201        matches!(self, Self::Note(_))
202    }
203
204    fn metadata(&self) -> Option<(&str, &str)> {
205        match self {
206            Self::Metadata { tag, data, .. } => Some((tag, data)),
207            _ => None,
208        }
209    }
210
211    /// The line of the text the token starts on, where it is one that can
212    /// be refused.
213    fn line(&self) -> Option<usize> {
214        match self {
215            Self::Metadata { line, .. } | Self::Tuplet { line, .. } => Some(*line),
216            Self::Note(note) => Some(note.line),
217            _ => None,
218        }
219    }
220}
221
222/// `error`, placed at `line` where the token knows one.
223fn at_line(error: Error, line: Option<usize>) -> Error {
224    match line {
225        Some(line) => error.placed(|| Position::line(line)),
226        None => error,
227    }
228}
229
230/// music21's `ABCMetadata.preParse`: the tag before the colon and what
231/// follows it, a comment taken off.
232fn metadata_token(src: &str, line: usize) -> Token {
233    let chars: Vec<char> = src.chars().collect();
234    let is_tag =
235        chars.len() >= 2 && (chars[0].is_ascii_uppercase() || chars[0] == 'w') && chars[1] == ':';
236    if !is_tag {
237        return Token::Metadata {
238            tag: String::new(),
239            data: String::new(),
240            line,
241        };
242    }
243    let stripped = src.split('%').next().unwrap_or("");
244    let mut pieces = stripped.chars();
245    let tag: String = pieces.by_ref().take(1).collect();
246    let data: String = pieces.skip(1).collect();
247    Token::Metadata {
248        tag,
249        data: data.trim().to_string(),
250        line,
251    }
252}
253
254/// music21's `getTimeSignatureParameters`.
255fn meter_parameters(data: &str) -> Result<Option<(u32, u32)>> {
256    if data.to_lowercase() == "none" {
257        return Ok(None);
258    }
259    match data {
260        "C" => return Ok(Some((4, 4))),
261        "C|" => return Ok(Some((2, 2))),
262        _ => {}
263    }
264    let (numerator, denominator) = data
265        .split_once('/')
266        .ok_or_else(|| abc_error(format!("cannot read the meter {data:?}")))?;
267    let digits = |text: &str| -> Result<u32> {
268        text.chars()
269            .filter(char::is_ascii_digit)
270            .collect::<String>()
271            .parse()
272            .map_err(|_| abc_error(format!("cannot read the meter {data:?}")))
273    };
274    Ok(Some((digits(numerator)?, digits(denominator)?)))
275}
276
277fn meter_of(data: &str) -> Result<Option<TimeSignature>> {
278    match meter_parameters(data)? {
279        Some((numerator, denominator)) => Ok(Some(TimeSignature::new(numerator, denominator)?)),
280        None => Ok(None),
281    }
282}
283
284/// music21's `getKeySignatureParameters`: the signed count of sharps and the
285/// mode, where the key names one.
286fn key_parameters(data: &str) -> Result<(IntegerType, Option<&'static str>)> {
287    const NAMES: [&str; 20] = [
288        "c", "g", "d", "a", "e", "b", "f#", "g#", "a#", "f", "bb", "eb", "d#", "ab", "e#", "db",
289        "c#", "gb", "cb", "hp",
290    ];
291    let mut names: Vec<&str> = NAMES.to_vec();
292    // Longest first, and the sort is stable.
293    names.sort_by_key(|name| std::cmp::Reverse(name.len()));
294    let chars: Vec<char> = data.chars().collect();
295    let mut standard = "C".to_string();
296    let mut remain = String::new();
297    for target in names {
298        let length = target.chars().count();
299        let head: String = chars.iter().take(length).collect();
300        if head.to_lowercase() == target {
301            standard = head;
302            remain = chars.iter().skip(length).collect();
303            break;
304        }
305    }
306    let letters: Vec<char> = standard.chars().collect();
307    if letters.len() > 1 && letters[1] == 'b' {
308        standard = format!("{}-", letters[0]);
309    }
310    let remain = remain.trim().to_lowercase();
311    let mut mode: Option<&'static str> = if remain.is_empty() {
312        Some("major")
313    } else {
314        [
315            ("dor", "dorian"),
316            ("phr", "phrygian"),
317            ("lyd", "lydian"),
318            ("mix", "mixolydian"),
319            ("maj", "major"),
320            ("ion", "ionian"),
321            ("aeo", "aeolian"),
322            ("m", "minor"),
323        ]
324        .into_iter()
325        .find(|(prefix, _)| remain.starts_with(prefix))
326        .map(|(_, mode)| mode)
327    };
328    // The Highland pipes: no signature written, or two sharps and a natural.
329    if standard == "HP" {
330        standard = "C".to_string();
331        mode = None;
332    } else if standard == "Hp" {
333        standard = "D".to_string();
334        mode = None;
335    }
336    let tonic = Pitch::from_name(&standard)?;
337    let sharps = crate::key::pitch_to_sharps(&tonic, mode)?;
338    Ok((sharps, mode))
339}
340
341/// music21's `getKeySignatureObject`: a key where there is a mode, a
342/// signature otherwise.
343fn key_of(data: &str) -> Result<StreamElement> {
344    let (sharps, mode) = key_parameters(data)?;
345    let signature = KeySignature::new(sharps);
346    Ok(match mode {
347        Some(mode) => match signature.try_as_key(Some(mode), None) {
348            Ok(key) => key.into(),
349            Err(_) => signature.into(),
350        },
351        None => signature.into(),
352    })
353}
354
355/// music21's `getClefObject`: the clef a key line names, and how far the
356/// notes under it are moved.
357fn clef_of(data: &str) -> Option<(Clef, IntegerType)> {
358    let lower = data.to_lowercase();
359    if lower.contains("-8va") {
360        Clef::from_string("treble8vb", 0)
361            .ok()
362            .map(|clef| (clef, -12))
363    } else if lower.contains("bass") {
364        Some((Clef::bass(), -24))
365    } else {
366        None
367    }
368}
369
370/// music21's `getMetronomeMarkObject`.
371fn tempo_of(data: &str) -> Result<MetronomeMark> {
372    let mut text: Option<String> = None;
373    let non_text = if data.contains('"') {
374        let mut quoted = String::new();
375        let mut outside = String::new();
376        let mut open = false;
377        for character in data.chars() {
378            if character == '"' {
379                open = !open;
380            } else if open {
381                quoted.push(character);
382            } else {
383                outside.push(character);
384            }
385        }
386        text = Some(quoted.trim().to_string()).filter(|text| !text.is_empty());
387        outside.trim().to_string()
388    } else {
389        data.trim().to_string()
390    };
391    let read = |number: &str| -> Result<FloatType> {
392        number
393            .trim()
394            .parse::<FloatType>()
395            .map_err(|_| abc_error(format!("cannot read the tempo {data:?}")))
396    };
397    let mut number: Option<FloatType> = None;
398    let mut referent: Option<FloatType> = None;
399    if !non_text.is_empty() {
400        if let Some((lengths, count)) = non_text.split_once('=') {
401            number = Some(read(count)?);
402            let mut quarters = 0.0;
403            for length in lengths.split(' ') {
404                let (numerator, denominator) = length.split_once('/').unwrap_or(("1", "1"));
405                quarters += read(numerator)? / read(denominator)? * 4.0;
406            }
407            referent = Some(quarters);
408        } else {
409            number = Some(read(&non_text)?);
410        }
411    }
412    let mut mark = match (number, text) {
413        (Some(number), Some(text)) => MetronomeMark::with_number_and_text(number, text),
414        (Some(number), None) => MetronomeMark::new(number),
415        (None, Some(text)) => MetronomeMark::from_text(text),
416        (None, None) => MetronomeMark::default(),
417    };
418    if let Some(referent) = referent {
419        mark.set_referent(Duration::new(referent)?);
420    }
421    Ok(mark)
422}
423
424/// music21's `getDefaultQuarterLength`, for an `L:` or an `M:` line.
425fn default_quarter_length(tag: &str, data: &str) -> Result<FloatType> {
426    if tag == "L" && data.contains('/') {
427        let (numerator, denominator) = data.split_once('/').unwrap_or(("1", "8"));
428        let numerator: FloatType = numerator
429            .trim()
430            .parse()
431            .map_err(|_| abc_error(format!("cannot read the default length {data:?}")))?;
432        let denominator: FloatType = if denominator == "G" {
433            4.0
434        } else {
435            denominator
436                .trim()
437                .parse()
438                .map_err(|_| abc_error(format!("cannot read the default length {data:?}")))?
439        };
440        return Ok(numerator * 4.0 / denominator);
441    }
442    if tag == "M" {
443        return Ok(match meter_parameters(data)? {
444            None => 0.5,
445            // Under three quarters of a whole note the unit is a sixteenth.
446            Some((numerator, denominator))
447                if FloatType::from(numerator) / FloatType::from(denominator) < 0.75 =>
448            {
449                0.25
450            }
451            Some(_) => 0.5,
452        });
453    }
454    Err(abc_error(format!(
455        "no quarter length associated with this metadata: {data}"
456    )))
457}
458
459impl AbcNote {
460    fn new(src: &str, line: usize, carried_accidental: &str, is_chord: bool) -> Self {
461        Self {
462            src: src.to_string(),
463            line,
464            is_chord,
465            carried_accidental: carried_accidental.to_string(),
466            ..Self::default()
467        }
468    }
469
470    /// music21's `_splitChordSymbols`: the quoted strings, and what is left
471    /// after the last of them.
472    fn split_chord_symbols(src: &str) -> (Vec<String>, String) {
473        if !src.contains('"') {
474            return (Vec::new(), src.to_string());
475        }
476        let chars: Vec<char> = src.chars().collect();
477        let mut symbols = Vec::new();
478        let mut index = 0;
479        let mut after = 0;
480        while index < chars.len() {
481            if chars[index] == '"'
482                && let Some(length) = chars[index + 1..].iter().position(|c| *c == '"')
483            {
484                let close = index + 1 + length;
485                symbols.push(chars[index..=close].iter().collect::<String>());
486                index = close + 1;
487                after = index;
488                continue;
489            }
490            index += 1;
491        }
492        if symbols.is_empty() {
493            return (Vec::new(), src.to_string());
494        }
495        (symbols, chars[after..].iter().collect())
496    }
497
498    /// music21's `getPitchName`: the pitch as music21 names one, or nothing
499    /// for a rest, and whether its accidental is shown.
500    fn pitch_name(
501        &self,
502        src: &str,
503        forced_key: Option<&KeySignature>,
504    ) -> Result<(Option<String>, Option<bool>)> {
505        let chars: Vec<char> = src.chars().collect();
506        let mut text: String = if chars.len() > 1 && matches!(chars[0], 'u' | 'T') {
507            chars[1..].iter().collect()
508        } else {
509            src.to_string()
510        };
511        text = text.replace('T', "");
512        let name = text
513            .chars()
514            .find(|c| matches!(c, 'a'..='g' | 'A'..='G' | 'z'))
515            .ok_or_else(|| abc_error(format!("cannot find any pitch information in: {text:?}")))?;
516        if name == 'z' {
517            return Ok((None, None));
518        }
519        let key = forced_key.or(self.key.as_ref());
520        let count = |wanted: char| text.chars().filter(|c| *c == wanted).count();
521        let mut octave: i32 = if name.is_lowercase() { 5 } else { 4 };
522        octave -= count(',') as i32;
523        octave += count('\'') as i32;
524        let marks = |source: &str| -> String {
525            let count = |wanted: char| source.chars().filter(|c| *c == wanted).count();
526            format!(
527                "{}{}{}",
528                "-".repeat(count('_')),
529                "#".repeat(count('^')),
530                "n".repeat(count('='))
531            )
532        };
533        let written = marks(&text);
534        let carried = marks(&self.carried_accidental);
535        if !carried.is_empty() && !written.is_empty() {
536            return Err(abc_error("Carried accidentals not rendered moot."));
537        }
538        let mut name = name.to_uppercase().to_string();
539        let display = if !carried.is_empty() {
540            None
541        } else if !written.is_empty() {
542            Some(true)
543        } else {
544            match key {
545                None => None,
546                Some(key) => {
547                    // The signature's own spelling of the note, not shown.
548                    if let Ok(altered) = key.altered_pitches()
549                        && let Some(pitch) = altered
550                            .iter()
551                            .find(|pitch| pitch.step().as_char().to_string() == name)
552                    {
553                        name = pitch.name();
554                    }
555                    Some(false)
556                }
557            }
558        };
559        let accidental = if carried.is_empty() { written } else { carried };
560        Ok((Some(format!("{name}{accidental}{octave}")), display))
561    }
562
563    /// music21's `getQuarterLength`.
564    fn read_quarter_length(
565        &self,
566        src: &str,
567        forced_default: Option<FloatType>,
568    ) -> Result<FloatType> {
569        let default = forced_default
570            .or(self.default_quarter_length)
571            .ok_or_else(|| {
572                abc_error("cannot calculate quarter length without a default quarter length")
573            })?;
574        let number: String = src
575            .chars()
576            .filter(|c| c.is_ascii_digit() || *c == '/')
577            .collect();
578        let whole = |text: &str| -> Result<FloatType> {
579            text.trim()
580                .parse::<FloatType>()
581                .map_err(|_| abc_error(format!("cannot read the length in {src:?}")))
582        };
583        let mut length = match number.as_str() {
584            "" => default,
585            "/" => default * 0.5,
586            "//" => default * 0.25,
587            "///" => default * 0.125,
588            text if text.starts_with('/') => {
589                op_frac(default / whole(text.split('/').nth(1).unwrap_or(""))?)
590            }
591            text if text.ends_with('/') => {
592                default * whole(text.split('/').next().unwrap_or(""))? / 2.0
593            }
594            text if text.matches('/').count() == 2 => 1.0,
595            text if text.contains('/') => {
596                let (numerator, denominator) = text.split_once('/').unwrap_or(("1", "1"));
597                op_frac(default * whole(numerator)? / whole(denominator)?)
598            }
599            text => default * whole(text)?,
600        };
601        if let Some((symbol, left)) = &self.broken_rhythm {
602            let (first, second) = match symbol.as_str() {
603                ">" => (1.5, 0.5),
604                "<" => (0.5, 1.5),
605                ">>" => (1.75, 0.25),
606                "<<" => (0.25, 1.75),
607                ">>>" => (1.875, 0.125),
608                "<<<" => (0.125, 1.875),
609                _ => (1.0, 1.0),
610            };
611            length *= if *left { first } else { second };
612        }
613        Ok(length)
614    }
615
616    /// music21's `ABCNote.parse` and `ABCChord.parse`.
617    fn parse(
618        &mut self,
619        forced_default: Option<FloatType>,
620        forced_key: Option<&KeySignature>,
621    ) -> Result<()> {
622        let (symbols, rest) = Self::split_chord_symbols(&self.src);
623        self.chord_symbols = symbols;
624        if self.is_chord {
625            let chars: Vec<char> = rest.chars().collect();
626            let close = chars.iter().position(|c| *c == ']').ok_or_else(|| {
627                abc_error(format!(
628                    "Bad chord indicator: {}: no closing bracket found.",
629                    self.src
630                ))
631            })?;
632            let outer: String = chars[close + 1..].iter().collect();
633            let inner: String = chars[1..close].iter().collect();
634            let outer_length = self.read_quarter_length(&outer, Some(1.0))?;
635            let key = forced_key.cloned().or_else(|| self.key.clone());
636            let mut handler = Handler::new(DEFAULT_VERSION);
637            // What goes wrong inside is placed where the chord stands.
638            handler.read_tokens(&inner).map_err(|(_, error)| error)?;
639            let mut inner_length = 0.0;
640            for token in handler.tokens {
641                let Token::Note(mut note) = token else {
642                    continue;
643                };
644                note.parse(self.default_quarter_length, key.as_ref())?;
645                if note.is_rest {
646                    continue;
647                }
648                if inner_length == 0.0 {
649                    inner_length = note.quarter_length;
650                }
651                self.sub_tokens.push(*note);
652            }
653            self.quarter_length = outer_length * inner_length;
654            return Ok(());
655        }
656        // A note music21 can find no pitch in is read as a C.
657        let (name, display) = match self.pitch_name(&rest, forced_key) {
658            Ok(read) => read,
659            Err(Error::Abc(read)) if read.message.starts_with("cannot find any pitch") => {
660                (Some("C".to_string()), Some(false))
661            }
662            Err(error) => return Err(error),
663        };
664        self.is_rest = name.is_none();
665        self.pitch_name = name;
666        self.accidental_display = display;
667        self.quarter_length = self.read_quarter_length(&rest, forced_default)?;
668        Ok(())
669    }
670}
671
672// ----------------------------------------------------------------- handler
673
674/// A spanner as the handler makes one: what kind, and the notes it joins.
675#[derive(Clone, Debug)]
676struct Spanning {
677    kind: SpannerKind,
678    uids: Vec<usize>,
679    /// The notes it took that no stream holds, by their uid: a grace
680    /// note's own, which music21 copies as the grace it places.
681    strays: Vec<(usize, StreamElement)>,
682    /// Where its part had got to when it opened, which is where music21
683    /// appends it to the part.
684    offset: FloatType,
685}
686
687/// music21's `ABCHandler`.
688#[derive(Clone, Debug)]
689struct Handler {
690    version: (u32, u32, u32),
691    directives: Vec<(String, String)>,
692    tokens: Vec<Token>,
693}
694
695impl Handler {
696    fn new(version: (u32, u32, u32)) -> Self {
697        Self {
698            version,
699            directives: Vec::new(),
700            tokens: Vec::new(),
701        }
702    }
703
704    /// music21's `_accidentalPropagation`.
705    fn accidental_propagation(&self) -> &str {
706        if self.version < (2, 0, 0) {
707            return "not";
708        }
709        self.directives
710            .iter()
711            .rev()
712            .find(|(key, _)| key == "propagate-accidentals")
713            .map_or("pitch", |(_, value)| value.as_str())
714    }
715
716    /// music21's `parseHeaderForVersionInformation`: `%abc-2.1` in the first
717    /// hundred characters.
718    fn read_version(&mut self, text: &str) {
719        let head: String = text.chars().take(100).collect();
720        let Some(at) = head.find("%abc-") else {
721            return;
722        };
723        let rest = &head[at + 5..];
724        let mut numbers = rest
725            .split(|c: char| !c.is_ascii_digit())
726            .take(3)
727            .map(|piece| piece.parse::<u32>().ok());
728        // `major.minor` at the least.
729        let (Some(Some(major)), Some(Some(minor))) = (numbers.next(), numbers.next()) else {
730            return;
731        };
732        if !rest[major.to_string().len()..].starts_with('.') {
733            return;
734        }
735        let patch = numbers.next().flatten().unwrap_or(0);
736        self.version = (major, minor, patch);
737    }
738
739    /// music21's `barlineTokenFilter`: a bar written as two in one.
740    fn bar_tokens(text: &str) -> Vec<Bar> {
741        let pair = match text {
742            "::" => Some((":|", "|:")),
743            "|1" => Some(("|", "[1")),
744            "|2" => Some(("|", "[2")),
745            ":|1" => Some((":|", "[1")),
746            ":|2" => Some((":|", "[2")),
747            _ => None,
748        };
749        match pair {
750            Some((first, second)) => vec![Bar::new(first), Bar::new(second)],
751            None => vec![Bar::new(text)],
752        }
753    }
754
755    /// music21's `tokenize`, what goes wrong placed at its line and column.
756    fn tokenize(&mut self, source: &str) -> Result<()> {
757        self.read_tokens(source).map_err(|(at, error)| {
758            let byte = source
759                .char_indices()
760                .nth(at)
761                .map_or(source.len(), |(byte, _)| byte);
762            error.placed(|| Position::in_text(source, byte))
763        })
764    }
765
766    /// The tokens of `source`, or what went wrong and the character it
767    /// went wrong at.
768    fn read_tokens(&mut self, source: &str) -> std::result::Result<(), (usize, Error)> {
769        let src: Vec<char> = source.chars().collect();
770        let len = src.len();
771        // Where each line starts, to tell a token its line.
772        let line_starts: Vec<usize> = std::iter::once(0)
773            .chain((0..len).filter(|at| src[*at] == '\n').map(|at| at + 1))
774            .collect();
775        let line_of = |at: usize| line_starts.partition_point(|start| *start <= at);
776        let at = |index: usize| src.get(index).copied();
777        let slice =
778            |from: usize, to: usize| -> String { src[from.min(len)..to.min(len)].iter().collect() };
779        let next_line_break =
780            |from: usize| -> usize { (from + 1..len).find(|j| src[*j] == '\n').unwrap_or(len) };
781        const DECORATIONS: &str = ".~^=_HLMOPSTuv";
782        const ACCIDENTALS: &str = "^=_";
783
784        let mut active_chord_symbol = String::new();
785        let mut accidentalized: Vec<(String, String)> = Vec::new();
786        let mut accidental = String::new();
787        let mut abc_pitch = String::new();
788        let mut pos = 0usize;
789        while pos < len {
790            let c = src[pos];
791            let next = at(pos + 1);
792            let next_next = at(pos + 2);
793            // What is taken past this character.
794            let mut skip = 0usize;
795
796            if c == '%' {
797                let end = next_line_break(pos);
798                let line = slice(pos, end);
799                if let Some(directive) = line.strip_prefix("%%") {
800                    let key: String = directive
801                        .chars()
802                        .take_while(|c| c.is_ascii_lowercase() || *c == '-')
803                        .collect();
804                    let after = &directive[key.len()..];
805                    if !key.is_empty()
806                        && after.starts_with(char::is_whitespace)
807                        && let Some(value) = after.split_whitespace().next()
808                    {
809                        self.directives.push((key, value.to_string()));
810                    }
811                }
812                pos = end;
813                continue;
814            }
815
816            let starts_metadata = next == Some(':')
817                && next_next.is_some()
818                && next_next != Some('|')
819                && (c == 'w' || (c.is_alphabetic() && c.is_uppercase()));
820            if starts_metadata {
821                let end = next_line_break(pos);
822                self.tokens
823                    .push(metadata_token(slice(pos, end).trim(), line_of(pos)));
824                pos = end;
825                continue;
826            }
827
828            if !c.is_whitespace() && !c.is_alphanumeric() && c != '~' && c != '(' {
829                let mut matched = None;
830                for (text, _) in BARS {
831                    let wanted: Vec<char> = text.chars().collect();
832                    let fits = match wanted.len() {
833                        3 => next.is_some() && next_next.is_some() && slice(pos, pos + 3) == text,
834                        2 => next.is_some() && slice(pos, pos + 2) == text,
835                        _ => c == wanted[0],
836                    };
837                    if fits {
838                        matched = Some(wanted.len());
839                        break;
840                    }
841                }
842                if let Some(length) = matched {
843                    accidentalized.clear();
844                    accidental.clear();
845                    for bar in Self::bar_tokens(&slice(pos, pos + length)) {
846                        self.tokens.push(Token::Bar(bar));
847                    }
848                    pos += length;
849                    continue;
850                }
851            }
852
853            if c == '(' && next.is_some_and(|c| c.is_ascii_digit()) {
854                let mut j = pos + 2;
855                if j >= len {
856                    return Err((
857                        pos,
858                        abc_error(format!("bad index value {j}, max is {}", len - 1)),
859                    ));
860                }
861                if at(j) == Some(':') {
862                    j += 1;
863                    if at(j).is_some_and(|c| c.is_ascii_digit()) {
864                        j += 1;
865                    }
866                    if at(j) == Some(':') {
867                        j += 1;
868                        if at(j).is_some_and(|c| c.is_ascii_digit()) {
869                            j += 1;
870                        }
871                    }
872                }
873                self.tokens.push(Token::Tuplet {
874                    src: slice(pos, j),
875                    line: line_of(pos),
876                });
877                pos = j;
878                continue;
879            }
880
881            if c == '<' || c == '>' {
882                let mut j = pos + 1;
883                while j + 1 < len && matches!(src[j], '<' | '>') {
884                    j += 1;
885                }
886                self.tokens
887                    .push(Token::BrokenRhythm(slice(pos, j).trim().to_string()));
888                pos = j;
889                continue;
890            }
891
892            if c == '!' {
893                let mut j = pos + 1;
894                while j < pos + 20 && j < len {
895                    if src[j] == '!' {
896                        match slice(pos, j + 1).as_str() {
897                            "!crescendo(!" => self
898                                .tokens
899                                .push(Token::SpannerStart(SpannerKind::Crescendo, None)),
900                            "!diminuendo(!" => self
901                                .tokens
902                                .push(Token::SpannerStart(SpannerKind::Diminuendo, None)),
903                            "!crescendo)!" | "!diminuendo)!" => {
904                                self.tokens.push(Token::ParenStop { hairpin: true });
905                            }
906                            _ => {}
907                        }
908                        skip = j - pos;
909                        break;
910                    }
911                    j += 1;
912                }
913                pos += skip + 1;
914                continue;
915            }
916
917            if c == '(' && next.is_some() {
918                self.tokens
919                    .push(Token::SpannerStart(SpannerKind::Slur, None));
920                pos += 1;
921                continue;
922            }
923            let simple = match c {
924                ')' => Some(Token::ParenStop { hairpin: false }),
925                '-' => Some(Token::Tie),
926                _ => None,
927            };
928            if let Some(token) = simple {
929                self.tokens.push(token);
930                pos += 1;
931                continue;
932            }
933
934            if c == '"' {
935                let mut j = pos + 1;
936                while j + 1 < len && src[j] != '"' {
937                    j += 1;
938                }
939                j += 1;
940                active_chord_symbol.push_str(&slice(pos, j));
941                pos = j.max(pos + 1);
942                continue;
943            }
944
945            if c == '[' {
946                let mut j = pos + 1;
947                while j + 1 < len && src[j] != ']' {
948                    j += 1;
949                }
950                j += 1;
951                while j < len && (src[j].is_ascii_digit() || src[j] == '/') {
952                    j += 1;
953                }
954                let collected = format!("{}{}", active_chord_symbol, slice(pos, j));
955                active_chord_symbol.clear();
956                self.tokens.push(Token::Note(Box::new(AbcNote::new(
957                    &collected,
958                    line_of(pos),
959                    "",
960                    true,
961                ))));
962                pos = j.max(pos + 1);
963                continue;
964            }
965
966            let mark = match c {
967                '.' => Some(Token::Staccato),
968                'u' => Some(Token::Upbow),
969                '{' => Some(Token::GraceStart),
970                '}' => Some(Token::GraceStop),
971                'v' => Some(Token::Downbow),
972                'K' => Some(Token::Accent),
973                'k' => Some(Token::Straccent),
974                'M' => Some(Token::Tenuto),
975                _ => None,
976            };
977            if let Some(token) = mark {
978                self.tokens.push(token);
979                pos += 1;
980                continue;
981            }
982
983            if c.is_alphabetic() || "~^=_".contains(c) {
984                let mut found = c.is_alphabetic() && !DECORATIONS.contains(c);
985                if found {
986                    abc_pitch = c.to_string();
987                }
988                if ACCIDENTALS.contains(c) {
989                    accidental = c.to_string();
990                }
991                let mut j = pos + 1;
992                while j < len {
993                    let here = src[j];
994                    if !found && DECORATIONS.contains(here) {
995                        j += 1;
996                        // music21 looks at the character after the one it
997                        // has just passed.
998                        match at(j) {
999                            Some(after) if ACCIDENTALS.contains(after) => accidental.push(after),
1000                            Some(_) => {}
1001                            None => {
1002                                return Err((pos, abc_error("a decoration ends the text")));
1003                            }
1004                        }
1005                    } else if !found && here.is_alphabetic() && !"~wuvhHLTSN".contains(here) {
1006                        found = true;
1007                        abc_pitch = here.to_string();
1008                        j += 1;
1009                    } else if here.is_ascii_digit() || ",/'".contains(here) {
1010                        if here == ',' || here == '\'' {
1011                            abc_pitch.push(here);
1012                        }
1013                        j += 1;
1014                    } else {
1015                        break;
1016                    }
1017                }
1018                let collected = format!("{}{}", active_chord_symbol, slice(pos, j));
1019                active_chord_symbol.clear();
1020
1021                const PASSED: [&str; 38] = [
1022                    "w", "u", "v", "v.", "h", "H", "vk", "uk", "U", "~", ".", "=", "V", "v.", "S",
1023                    "s", "i", "I", "ui", "u.", "Q", "Hy", "Hx", "r", "m", "M", "n", "N", "o", "O",
1024                    "P", "l", "L", "R", "y", "T", "t", "x",
1025                ];
1026                let chars: Vec<char> = collected.chars().collect();
1027                let last = chars.last().copied().unwrap_or(' ');
1028                let passed = PASSED.contains(&collected.as_str())
1029                    || collected == "Z"
1030                    || (collected.starts_with('"')
1031                        && ("uvkKQ.yTwhx".contains(last) || collected.ends_with("v.")))
1032                    || collected.starts_with('x')
1033                    || collected.starts_with('H')
1034                    || collected.starts_with('Z')
1035                    || (chars.len() > 1 && chars[0] == '=' && chars[1].is_ascii_digit());
1036                if !passed {
1037                    let mut carried = String::new();
1038                    if !abc_pitch.is_empty() {
1039                        let class: String = abc_pitch
1040                            .chars()
1041                            .take(1)
1042                            .flat_map(char::to_uppercase)
1043                            .collect();
1044                        let key = match self.accidental_propagation() {
1045                            "octave" => Some(abc_pitch.clone()),
1046                            "pitch" => Some(class),
1047                            _ => None,
1048                        };
1049                        if !accidental.is_empty() {
1050                            if let Some(key) = key {
1051                                accidentalized.retain(|(known, _)| *known != key);
1052                                accidentalized.push((key, accidental.clone()));
1053                            }
1054                            accidental.clear();
1055                        } else if let Some(key) = key
1056                            && let Some((_, held)) =
1057                                accidentalized.iter().find(|(known, _)| *known == key)
1058                        {
1059                            carried = held.clone();
1060                        }
1061                    }
1062                    self.tokens.push(Token::Note(Box::new(AbcNote::new(
1063                        &collected,
1064                        line_of(pos),
1065                        &carried,
1066                        false,
1067                    ))));
1068                }
1069                pos = j.max(pos + 1);
1070                continue;
1071            }
1072
1073            pos += 1;
1074        }
1075        Ok(())
1076    }
1077
1078    /// music21's `tokenProcess`: each token told what is in force where it
1079    /// stands, and then read. Hands back the spanners the tokens started.
1080    fn process(&mut self) -> Result<Vec<Spanning>> {
1081        let mut spanners: Vec<Spanning> = Vec::new();
1082        let mut active_spanners: Vec<usize> = Vec::new();
1083        let mut active_parens: Vec<&'static str> = Vec::new();
1084        let mut default_length: Option<FloatType> = None;
1085        let mut key: Option<KeySignature> = None;
1086        let mut meter: Option<TimeSignature> = None;
1087        // The tuplet in force and how many notes it still takes.
1088        let mut tuplet: Option<(Tuplet, i32)> = None;
1089        let mut tie_waiting = false;
1090        let mut marks: Vec<&'static str> = Vec::new();
1091        let mut in_grace = false;
1092        let mut last_note: Option<usize> = None;
1093
1094        for index in 0..self.tokens.len() {
1095            let previous_is_note = index > 0 && self.tokens[index - 1].is_note();
1096            let next_is_note = self.tokens.get(index + 1).is_some_and(Token::is_note);
1097            let line = self.tokens[index].line();
1098            let here = |error: Error| at_line(error, line);
1099            match self.tokens[index].clone() {
1100                Token::Metadata { tag, data, .. } => {
1101                    if tag == "M" {
1102                        meter = meter_of(&data).map_err(here)?;
1103                    }
1104                    if tag == "L" || (tag == "M" && default_length.is_none()) {
1105                        default_length = Some(default_quarter_length(&tag, &data).map_err(here)?);
1106                    } else if tag == "K" {
1107                        let (sharps, _) = key_parameters(&data).map_err(here)?;
1108                        key = Some(KeySignature::new(sharps));
1109                    }
1110                    if tag == "X" {
1111                        active_parens.clear();
1112                        active_spanners.clear();
1113                    }
1114                }
1115                Token::BrokenRhythm(symbol) => {
1116                    if previous_is_note && next_is_note {
1117                        if let Token::Note(note) = &mut self.tokens[index - 1] {
1118                            note.broken_rhythm = Some((symbol.clone(), true));
1119                        }
1120                        if let Token::Note(note) = &mut self.tokens[index + 1] {
1121                            note.broken_rhythm = Some((symbol, false));
1122                        }
1123                    }
1124                }
1125                Token::Tuplet { src, .. } => {
1126                    let (made, count) = tuplet_of(&src, meter.as_ref()).map_err(here)?;
1127                    tuplet = Some((made, count));
1128                }
1129                Token::SpannerStart(kind, _) => {
1130                    spanners.push(Spanning {
1131                        kind,
1132                        uids: Vec::new(),
1133                        strays: Vec::new(),
1134                        offset: 0.0,
1135                    });
1136                    let made = spanners.len() - 1;
1137                    self.tokens[index] = Token::SpannerStart(kind, Some(made));
1138                    active_spanners.push(made);
1139                    active_parens.push(match kind {
1140                        SpannerKind::Crescendo => "Crescendo",
1141                        SpannerKind::Diminuendo => "Diminuendo",
1142                        _ => "Slur",
1143                    });
1144                }
1145                Token::ParenStop { hairpin } => {
1146                    // Slurs and hairpins may overlap, so each stop ends the
1147                    // latest of its own kind.
1148                    let closes: &[&str] = if hairpin {
1149                        &["Crescendo", "Diminuendo"]
1150                    } else {
1151                        &["Slur"]
1152                    };
1153                    if let Some(at) = active_parens.iter().rposition(|open| closes.contains(open)) {
1154                        active_parens.remove(at);
1155                        active_spanners.remove(at);
1156                    }
1157                }
1158                Token::Tie => {
1159                    if let Some(last) = last_note
1160                        && let Token::Note(note) = &mut self.tokens[last]
1161                    {
1162                        note.tie = Some(if note.tie == Some(TieType::Stop) {
1163                            TieType::Continue
1164                        } else {
1165                            TieType::Start
1166                        });
1167                    }
1168                    tie_waiting = true;
1169                }
1170                Token::Staccato => marks.push("staccato"),
1171                Token::Upbow => marks.push("upbow"),
1172                Token::Downbow => marks.push("downbow"),
1173                Token::Accent => marks.push("accent"),
1174                Token::Straccent => marks.push("strongaccent"),
1175                Token::Tenuto => marks.push("tenuto"),
1176                Token::GraceStart => in_grace = true,
1177                Token::GraceStop => in_grace = false,
1178                Token::Bar(_) => {}
1179                Token::Note(_) => {
1180                    let Some(default_length) = default_length else {
1181                        return Err(here(abc_error(
1182                            "no active default note length provided for note processing.",
1183                        )));
1184                    };
1185                    let Token::Note(note) = &mut self.tokens[index] else {
1186                        continue;
1187                    };
1188                    note.default_quarter_length = Some(default_length);
1189                    note.key = key.clone();
1190                    note.spanners = active_spanners.clone();
1191                    if std::mem::take(&mut tie_waiting) {
1192                        note.tie = Some(TieType::Stop);
1193                    }
1194                    // Each kind of mark once, in music21's order.
1195                    for mark in [
1196                        "staccato",
1197                        "upbow",
1198                        "downbow",
1199                        "accent",
1200                        "strongaccent",
1201                        "tenuto",
1202                    ] {
1203                        if marks.contains(&mark) {
1204                            note.articulations.push(mark);
1205                        }
1206                    }
1207                    marks.clear();
1208                    if in_grace {
1209                        note.in_grace = true;
1210                    }
1211                    match &mut tuplet {
1212                        None => {}
1213                        Some((_, 0)) => tuplet = None,
1214                        Some((made, count)) => {
1215                            *count -= 1;
1216                            note.tuplet = Some(*made);
1217                        }
1218                    }
1219                    last_note = Some(index);
1220                }
1221            }
1222        }
1223        for token in &mut self.tokens {
1224            if let Token::Note(note) = token {
1225                let line = Some(note.line);
1226                note.parse(None, None)
1227                    .map_err(|error| at_line(error, line))?;
1228            }
1229        }
1230        Ok(spanners)
1231    }
1232
1233    /// music21's `definesReferenceNumbers`: more than one `X:`.
1234    fn defines_reference_numbers(&self) -> bool {
1235        self.tokens
1236            .iter()
1237            .filter(|token| token.metadata().is_some_and(|(tag, _)| tag == "X"))
1238            .count()
1239            > 1
1240    }
1241
1242    /// music21's `splitByReferenceNumber`, in order of the numbers.
1243    fn split_by_reference_number(&self) -> Vec<(IntegerType, Handler)> {
1244        let mut before: Vec<Token> = Vec::new();
1245        let mut tunes: Vec<(IntegerType, Vec<Token>)> = Vec::new();
1246        for token in &self.tokens {
1247            if let Some(("X", data)) = token.metadata() {
1248                let number = data.trim().parse::<IntegerType>().unwrap_or(0);
1249                tunes.retain(|(known, _)| *known != number);
1250                tunes.push((number, Vec::new()));
1251            }
1252            match tunes.last_mut() {
1253                Some((_, tokens)) => tokens.push(token.clone()),
1254                None => before.push(token.clone()),
1255            }
1256        }
1257        tunes.sort_by_key(|(number, _)| *number);
1258        tunes
1259            .into_iter()
1260            .map(|(number, tokens)| {
1261                let mut handler = Handler::new(self.version);
1262                handler.tokens = before.iter().cloned().chain(tokens).collect();
1263                (number, handler)
1264            })
1265            .collect()
1266    }
1267
1268    /// music21's `definesMeasures`: two plain barlines or more.
1269    fn defines_measures(&self) -> bool {
1270        self.tokens
1271            .iter()
1272            .filter(|token| matches!(token, Token::Bar(bar) if bar.is_regular()))
1273            .count()
1274            >= 2
1275    }
1276
1277    fn has_notes(tokens: &[Token]) -> bool {
1278        tokens.iter().any(Token::is_note)
1279    }
1280
1281    /// music21's `splitByVoice`: the header, and the tokens of each voice
1282    /// whose `V:` line starts with a digit.
1283    fn split_by_voice(&self) -> Vec<Vec<Token>> {
1284        let positions: Vec<usize> = self
1285            .tokens
1286            .iter()
1287            .enumerate()
1288            .filter(|(_, token)| {
1289                token.metadata().is_some_and(|(tag, data)| {
1290                    tag == "V" && data.chars().next().is_some_and(|c| c.is_ascii_digit())
1291                })
1292            })
1293            .map(|(index, _)| index)
1294            .collect();
1295        if positions.len() <= 1 {
1296            return vec![self.tokens.clone()];
1297        }
1298        let mut pieces = vec![self.tokens[..positions[0]].to_vec()];
1299        for pair in positions.windows(2) {
1300            pieces.push(self.tokens[pair[0]..pair[1]].to_vec());
1301        }
1302        pieces.push(self.tokens[positions[positions.len() - 1]..].to_vec());
1303        pieces
1304    }
1305}
1306
1307/// music21's `ABCTuplet.updateRatio` and `updateNoteCount`: the tuplet and
1308/// how many notes it takes.
1309fn tuplet_of(src: &str, meter: Option<&TimeSignature>) -> Result<(Tuplet, i32)> {
1310    let normal_switch = match meter {
1311        Some(meter) if meter.beat_division_count() == 3 => 3,
1312        _ => 2,
1313    };
1314    let pieces: Vec<&str> = src.trim().split(':').collect();
1315    let (actual, normal) = match pieces[0] {
1316        "(1" => (1, 1),
1317        "(2" => (2, 3),
1318        "(3" => (3, 2),
1319        "(4" => (4, 3),
1320        "(5" => (5, normal_switch),
1321        "(6" => (6, 2),
1322        "(7" => (7, normal_switch),
1323        "(8" => (8, 3),
1324        "(9" => (9, normal_switch),
1325        other => {
1326            return Err(abc_error(format!(
1327                "cannot handle tuplet of form: {other:?}"
1328            )));
1329        }
1330    };
1331    let read = |piece: Option<&&str>| piece.and_then(|piece| piece.parse::<u32>().ok());
1332    let normal = read(pieces.get(1)).unwrap_or(normal);
1333    let count = read(pieces.get(2)).unwrap_or(actual);
1334    Ok((Tuplet::ratio(actual, normal), count as i32))
1335}
1336
1337/// A bar's worth of tokens with the barlines either side: music21's
1338/// `ABCHandlerBar`.
1339#[derive(Clone, Debug, Default)]
1340struct BarHandler {
1341    tokens: Vec<Token>,
1342    left: Option<Bar>,
1343    right: Option<Bar>,
1344}
1345
1346impl BarHandler {
1347    /// music21's `ABCHandlerBar.__add__`.
1348    fn joined(&self, other: &BarHandler) -> BarHandler {
1349        BarHandler {
1350            tokens: self
1351                .tokens
1352                .iter()
1353                .cloned()
1354                .chain(other.tokens.iter().cloned())
1355                .collect(),
1356            left: other.left.clone().or_else(|| self.left.clone()),
1357            right: other.right.clone().or_else(|| self.right.clone()),
1358        }
1359    }
1360}
1361
1362/// music21's `splitByMeasure`.
1363fn split_by_measure(tokens: &[Token]) -> Vec<BarHandler> {
1364    // Where a bar stands, or a line of metadata a note follows.
1365    let mut positions: Vec<usize> = Vec::new();
1366    for (index, token) in tokens.iter().enumerate() {
1367        let note_follows = tokens.get(index + 1).is_some_and(Token::is_note);
1368        if matches!(token, Token::Bar(_)) || (token.metadata().is_some() && note_follows) {
1369            positions.push(index);
1370        }
1371    }
1372    if positions.is_empty() || tokens.is_empty() {
1373        return Vec::new();
1374    }
1375    let last_valid = tokens.len() - 1;
1376    let mut pairs: Vec<(usize, usize)> = vec![(0, positions[0])];
1377    let mut start = positions[0];
1378    for end in positions.iter().skip(1).copied() {
1379        // A span of one is passed over.
1380        if end == start + 1 {
1381            start = end;
1382            continue;
1383        }
1384        pairs.push((start, end));
1385        start = end;
1386    }
1387    if start != last_valid {
1388        pairs.push((start, last_valid));
1389    }
1390
1391    let mut handlers = Vec::new();
1392    for (x, y) in pairs {
1393        let mut handler = BarHandler::default();
1394        let mut from = x;
1395        let mut to = y;
1396        match &tokens[x] {
1397            Token::Bar(bar) => {
1398                // A repeat's end belongs to the measure before.
1399                if !(bar.repeat && bar.form == "end") {
1400                    handler.left = Some(bar.clone());
1401                }
1402                from = x + 1;
1403            }
1404            Token::Metadata { .. } if x != 0 => from = x + 1,
1405            _ => {}
1406        }
1407        match &tokens[y] {
1408            Token::Bar(bar) => {
1409                if !(bar.repeat && bar.form == "start") {
1410                    handler.right = Some(bar.clone());
1411                }
1412                to = y.wrapping_sub(1);
1413            }
1414            Token::Metadata { .. } => {}
1415            token => {
1416                if !(token.is_note() && y == tokens.len() - 1) {
1417                    to = y.wrapping_sub(1);
1418                }
1419            }
1420        }
1421        if to == usize::MAX || from > to {
1422            continue;
1423        }
1424        handler.tokens = tokens[from..=to].to_vec();
1425        if handler.tokens.is_empty() {
1426            continue;
1427        }
1428        handlers.push(handler);
1429    }
1430    handlers
1431}
1432
1433/// music21's `mergeLeadingMetaData`: a handler of nothing but metadata is
1434/// joined to the one after it, and a tune of one measure is one handler.
1435fn merge_leading_metadata(handlers: Vec<BarHandler>) -> Vec<BarHandler> {
1436    let sounding = handlers
1437        .iter()
1438        .filter(|handler| Handler::has_notes(&handler.tokens))
1439        .count();
1440    if sounding <= 1 {
1441        let mut whole = BarHandler::default();
1442        for handler in &handlers {
1443            whole = whole.joined(handler);
1444        }
1445        return vec![whole];
1446    }
1447    let mut merged = Vec::new();
1448    let mut index = 0;
1449    while index < handlers.len() {
1450        let silent = !Handler::has_notes(&handlers[index].tokens);
1451        if silent && index != handlers.len() - 1 {
1452            merged.push(handlers[index].joined(&handlers[index + 1]));
1453            index += 2;
1454        } else {
1455            merged.push(handlers[index].clone());
1456            index += 1;
1457        }
1458    }
1459    merged
1460}
1461
1462// --------------------------------------------------------------- translate
1463
1464/// One element with where it stands and the order it was put in.
1465#[derive(Clone, Debug)]
1466struct Item {
1467    offset: FloatType,
1468    seq: usize,
1469    uid: Option<usize>,
1470    element: StreamElement,
1471}
1472
1473/// A measure or a part while it is being filled: what it holds, and where
1474/// the next thing appended goes.
1475#[derive(Clone, Debug, Default)]
1476struct Line {
1477    items: Vec<Item>,
1478    end: FloatType,
1479    seq: usize,
1480}
1481
1482impl Line {
1483    /// music21's `coreAppend`.
1484    fn append(&mut self, element: impl Into<StreamElement>, uid: Option<usize>) {
1485        let element = element.into();
1486        let length = element.quarter_length();
1487        self.items.push(Item {
1488            offset: self.end,
1489            seq: self.seq,
1490            uid,
1491            element,
1492        });
1493        self.seq += 1;
1494        self.end = op_frac(self.end + length);
1495    }
1496
1497    /// A signature or a clef put at the start in place of the one there,
1498    /// as music21's `measure.timeSignature = ...` does.
1499    fn set_at_start(&mut self, element: StreamElement) {
1500        let same = |held: &StreamElement| {
1501            matches!(
1502                (held, &element),
1503                (
1504                    StreamElement::TimeSignature(_),
1505                    StreamElement::TimeSignature(_)
1506                ) | (StreamElement::Clef(_), StreamElement::Clef(_))
1507                    | (
1508                        StreamElement::KeySignature(_) | StreamElement::Key(_),
1509                        StreamElement::KeySignature(_) | StreamElement::Key(_)
1510                    )
1511            )
1512        };
1513        self.items.retain(|item| !same(&item.element));
1514        self.items.push(Item {
1515            offset: 0.0,
1516            seq: self.seq,
1517            uid: None,
1518            element,
1519        });
1520        self.seq += 1;
1521    }
1522
1523    fn meter(&self) -> Option<&TimeSignature> {
1524        self.items.iter().find_map(|item| match &item.element {
1525            StreamElement::TimeSignature(meter) => Some(meter),
1526            _ => None,
1527        })
1528    }
1529
1530    /// The elements in the order music21 sorts a stream into.
1531    fn sorted(&self) -> Vec<&Item> {
1532        let mut sorted: Vec<&Item> = self.items.iter().collect();
1533        sorted.sort_by(|left, right| {
1534            let grace = |item: &Item| item.element.duration().is_some_and(Duration::is_grace);
1535            left.offset
1536                .total_cmp(&right.offset)
1537                .then(class_sort_order(&left.element).cmp(&class_sort_order(&right.element)))
1538                .then(grace(right).cmp(&grace(left)))
1539                .then(left.seq.cmp(&right.seq))
1540        });
1541        sorted
1542    }
1543}
1544
1545/// music21's `classSortOrder`.
1546pub(super) fn class_sort_order(element: &StreamElement) -> i32 {
1547    match element {
1548        StreamElement::TextExpression(_) => -30,
1549        StreamElement::Instrument(_) => -25,
1550        StreamElement::Stream(_) => -20,
1551        StreamElement::Clef(_) => 0,
1552        StreamElement::MetronomeMark(_) | StreamElement::TempoText(_) => 1,
1553        StreamElement::KeySignature(_) | StreamElement::Key(_) => 2,
1554        StreamElement::TimeSignature(_) => 4,
1555        StreamElement::Dynamic(_) => 10,
1556        StreamElement::ChordSymbol(_) => 19,
1557        _ => 20,
1558    }
1559}
1560
1561#[derive(Clone, Debug, Default)]
1562struct MeasureIr {
1563    line: Line,
1564    number: IntegerType,
1565    left: Option<Barline>,
1566    right: Option<Barline>,
1567    padding_left: FloatType,
1568}
1569
1570/// An ending while its measures are being met.
1571#[derive(Clone, Debug)]
1572struct Bracket {
1573    number: u32,
1574    measures: Vec<usize>,
1575    complete: bool,
1576}
1577
1578/// What reading one voice keeps between its measures.
1579struct PartReader {
1580    spanners: Vec<Spanning>,
1581    next_uid: usize,
1582    /// The notes a line of words is sung to, by measure and place.
1583    lyric_targets: Vec<(Option<usize>, usize)>,
1584    post_transposition: IntegerType,
1585}
1586
1587impl PartReader {
1588    fn uid(&mut self) -> usize {
1589        self.next_uid += 1;
1590        self.next_uid
1591    }
1592}
1593
1594/// music21's `addABCLyrics`: the words of a `w:` line, shared out among the
1595/// notes since the line before.
1596fn add_lyrics(data: &str, targets: &mut [&mut StreamElement]) -> Result<()> {
1597    let mut at = 0usize;
1598    for word in data.split_whitespace() {
1599        if word == "*" || word == "-" {
1600            at += 1;
1601            continue;
1602        }
1603        let syllables: Vec<&str> = word.split('-').collect();
1604        for (index, syllable) in syllables.iter().enumerate() {
1605            if syllable.is_empty() {
1606                at += 1;
1607                continue;
1608            }
1609            let Some(target) = targets.get_mut(at) else {
1610                return Ok(());
1611            };
1612            let text = format!(
1613                "{}{syllable}{}",
1614                if index > 0 { "-" } else { "" },
1615                if index + 1 < syllables.len() { "-" } else { "" }
1616            );
1617            match target {
1618                StreamElement::Note(note) => note.add_lyric(&text, None, false)?,
1619                StreamElement::Chord(chord) => chord.add_lyric(&text, None, false)?,
1620                _ => {}
1621            }
1622            at += 1;
1623        }
1624    }
1625    Ok(())
1626}
1627
1628/// An element and the number spanners know it by.
1629type Placed = (StreamElement, Option<usize>);
1630
1631/// music21's `parseABCNote`: the note, chord or rest a token stands for,
1632/// after the chord symbol written over it.
1633fn note_elements(
1634    token: &AbcNote,
1635    reader: &mut PartReader,
1636) -> Result<(Option<ChordSymbol>, Option<Placed>)> {
1637    let mut symbol = None;
1638    if let Some(first) = token.chord_symbols.first() {
1639        let mut name: String = first.replace('"', "").trim().to_string();
1640        name = name.replace(['(', ')'], "");
1641        // A flat written `b` after a note letter is music21's `-`.
1642        let chars: Vec<char> = name.chars().collect();
1643        let mut cleaned = String::new();
1644        for (index, character) in chars.iter().enumerate() {
1645            let after_letter = index > 0 && matches!(chars[index - 1], 'A'..='G' | 'a'..='g');
1646            cleaned.push(if *character == 'b' && after_letter {
1647                '-'
1648            } else {
1649                *character
1650            });
1651        }
1652        if matches!(cleaned.as_str(), "NC" | "N.C." | "No Chord" | "None") {
1653            symbol = Some(ChordSymbol::no_chord(Some(cleaned)));
1654        } else if cleaned.starts_with('>') {
1655            return Ok((None, None));
1656        } else if let Ok(read) = ChordSymbol::parse_music21(cleaned) {
1657            symbol = Some(read);
1658        }
1659    }
1660
1661    let with_tuplet = |duration: &mut Duration, tuplet: Option<Tuplet>| {
1662        if let Some(mut tuplet) = tuplet {
1663            if tuplet.duration_normal().is_none()
1664                && let Some((kind, dots)) = duration.type_and_dots()
1665            {
1666                tuplet.set_duration_type(kind, dots);
1667            }
1668            duration.append_tuplet(tuplet);
1669        }
1670    };
1671
1672    if token.is_chord {
1673        if token.sub_tokens.is_empty() {
1674            return Ok((symbol, None));
1675        }
1676        let mut members = Vec::new();
1677        for sub in &token.sub_tokens {
1678            let Some(name) = &sub.pitch_name else {
1679                continue;
1680            };
1681            let mut pitch = Pitch::from_name(name)?;
1682            if let Some(accidental) = pitch.written_accidental_mut() {
1683                accidental.set_display_status(sub.accidental_display);
1684            }
1685            members.push(Note::from_pitch(pitch));
1686        }
1687        let mut duration = Duration::new(token.quarter_length)?;
1688        with_tuplet(&mut duration, token.tuplet);
1689        let chord = Chord::new(members)?.with_duration(duration);
1690        let uid = reader.uid();
1691        return Ok((symbol, Some((chord.into(), Some(uid)))));
1692    }
1693
1694    let mut duration = Duration::new(token.quarter_length)?;
1695    with_tuplet(&mut duration, token.tuplet);
1696    if token.is_rest {
1697        let uid = reader.uid();
1698        for spanner in &token.spanners {
1699            reader.spanners[*spanner].uids.push(uid);
1700        }
1701        if token.in_grace {
1702            let mut stray = Rest::new(duration.clone());
1703            stray.set_tie(tie_of(token.tie));
1704            for spanner in &token.spanners {
1705                reader.spanners[*spanner]
1706                    .strays
1707                    .push((uid, stray.clone().into()));
1708            }
1709        }
1710        let duration = if token.in_grace {
1711            grace_of(&duration)
1712        } else {
1713            duration
1714        };
1715        // A grace rest is a copy made after the spanners took the first.
1716        let placed = if token.in_grace { reader.uid() } else { uid };
1717        let mut rest = Rest::new(duration);
1718        rest.set_tie(tie_of(token.tie));
1719        *rest.articulations_mut() = articulations_of(&token.articulations);
1720        return Ok((symbol, Some((rest.into(), Some(placed)))));
1721    }
1722    let name = token
1723        .pitch_name
1724        .as_deref()
1725        .ok_or_else(|| abc_error("a note with no pitch"))?;
1726    let mut pitch = Pitch::from_name(name)?;
1727    if let Some(accidental) = pitch.written_accidental_mut() {
1728        accidental.set_display_status(token.accidental_display);
1729    }
1730    let mut note = Note::from_pitch(pitch);
1731    note.set_tie(tie_of(token.tie));
1732    let uid = reader.uid();
1733    for spanner in &token.spanners {
1734        if !reader.spanners[*spanner].uids.contains(&uid) {
1735            reader.spanners[*spanner].uids.push(uid);
1736        }
1737    }
1738    // A grace note is a copy made after the spanners took the note itself,
1739    // which no stream then holds.
1740    let placed = if token.in_grace {
1741        let mut stray = note.clone();
1742        stray.set_duration(duration.clone());
1743        for spanner in &token.spanners {
1744            reader.spanners[*spanner]
1745                .strays
1746                .push((uid, stray.clone().into()));
1747        }
1748        duration = grace_of(&duration);
1749        reader.uid()
1750    } else {
1751        uid
1752    };
1753    note.set_duration(duration);
1754    *note.articulations_mut() = articulations_of(&token.articulations);
1755    Ok((symbol, Some((note.into(), Some(placed)))))
1756}
1757
1758/// The tie a token asks for, on a note or a rest alike.
1759fn tie_of(tie: Option<TieType>) -> Option<Tie> {
1760    match tie? {
1761        tie_type @ (TieType::Start | TieType::Continue) => {
1762            let mut tie = Tie::new(tie_type);
1763            tie.set_style(TieStyle::Normal);
1764            Some(tie)
1765        }
1766        tie_type => Some(Tie::new(tie_type)),
1767    }
1768}
1769
1770/// The marks a token carries, last written first: music21 pops them off
1771/// the end of its list.
1772fn articulations_of(marks: &[&'static str]) -> Vec<Articulation> {
1773    marks
1774        .iter()
1775        .rev()
1776        .filter_map(|mark| {
1777            let class = match *mark {
1778                "staccato" => "Staccato",
1779                "upbow" => "UpBow",
1780                "downbow" => "DownBow",
1781                "accent" => "Accent",
1782                "strongaccent" => "StrongAccent",
1783                "tenuto" => "Tenuto",
1784                _ => return None,
1785            };
1786            ArticulationKind::from_class_name(class).map(Articulation::of_kind)
1787        })
1788        .collect()
1789}
1790
1791/// A length as a grace note's: the written value, lasting nothing and in no
1792/// tuplet, whatever bracket the note was written inside.
1793fn grace_of(duration: &Duration) -> Duration {
1794    duration.grace_duration()
1795}
1796
1797/// music21's `abcToStreamPart`: one voice as a part, with the spanners it
1798/// holds, each naming its notes by the numbers the part's leaves carry.
1799fn part_of(
1800    tokens: &[Token],
1801    spanners: &[Spanning],
1802) -> Result<(Stream, Vec<Option<usize>>, Vec<Spanning>)> {
1803    let handler = Handler {
1804        version: DEFAULT_VERSION,
1805        directives: Vec::new(),
1806        tokens: tokens.to_vec(),
1807    };
1808    let merged: Vec<BarHandler> = if handler.defines_measures() {
1809        merge_leading_metadata(split_by_measure(tokens))
1810    } else {
1811        vec![BarHandler {
1812            tokens: tokens.to_vec(),
1813            ..BarHandler::default()
1814        }]
1815    };
1816    let use_measures = merged.len() > 1;
1817
1818    let mut reader = PartReader {
1819        spanners: spanners.to_vec(),
1820        next_uid: 0,
1821        lyric_targets: Vec::new(),
1822        post_transposition: 0,
1823    };
1824    // Which of the handler's spanners this voice starts, in order, each
1825    // with where the part had got to: the measure it opened in, or the
1826    // length of the part's own line.
1827    let mut started: Vec<(usize, Option<usize>, FloatType)> = Vec::new();
1828    let mut part = Line::default();
1829    let mut measures: Vec<MeasureIr> = Vec::new();
1830    let mut brackets: Vec<Bracket> = Vec::new();
1831    let mut bar_count = 0;
1832    let mut measure_number = 1;
1833
1834    for handler in &merged {
1835        let in_measure = use_measures && Handler::has_notes(&handler.tokens);
1836        let mut measure = MeasureIr::default();
1837        if in_measure {
1838            let index = measures.len();
1839            if let Some(left) = &handler.left {
1840                measure.left = left.barline();
1841                if let Some(number) = left.repeat_bracket() {
1842                    match brackets.iter_mut().find(|bracket| !bracket.complete) {
1843                        None => brackets.push(Bracket {
1844                            number,
1845                            measures: vec![index],
1846                            complete: number == 2,
1847                        }),
1848                        Some(open) => {
1849                            if !open.measures.contains(&index) {
1850                                open.measures.push(index);
1851                            }
1852                            open.complete = true;
1853                        }
1854                    }
1855                }
1856            }
1857            if let Some(right) = &handler.right {
1858                // A repeat closing a measure ends the passage.
1859                measure.right = right.barline().map(|barline| {
1860                    if barline.repeat_direction() == Some(RepeatDirection::Start) {
1861                        Barline::repeat(RepeatDirection::End, None)
1862                    } else {
1863                        barline
1864                    }
1865                });
1866                if right.repeat
1867                    && let Some(open) = brackets.iter_mut().find(|bracket| !bracket.complete)
1868                {
1869                    if !open.measures.contains(&index) {
1870                        open.measures.push(index);
1871                    }
1872                    open.complete = true;
1873                }
1874            }
1875            bar_count += 1;
1876        }
1877
1878        // music21's `parseTokens`.
1879        reader.post_transposition = 0;
1880        let place = in_measure.then_some(measures.len());
1881        {
1882            let line = if in_measure {
1883                &mut measure.line
1884            } else {
1885                &mut part
1886            };
1887            for token in &handler.tokens {
1888                // What goes wrong says its line, and its measure counted
1889                // from one as the tune writes them, a pickup the first.
1890                let refused = |error: Error| {
1891                    let error = at_line(error, token.line());
1892                    if in_measure {
1893                        return error.placed(|| Position::measure(bar_count.to_string()));
1894                    }
1895                    error
1896                };
1897                match token {
1898                    Token::Metadata { tag, data, .. } => {
1899                        if tag == "w" {
1900                            let wanted = std::mem::take(&mut reader.lyric_targets);
1901                            let mut targets: Vec<&mut StreamElement> = Vec::new();
1902                            // Notes of this line only; those of measures
1903                            // already closed are reached below.
1904                            let mut here: Vec<usize> = wanted
1905                                .iter()
1906                                .filter(|(held, _)| *held == place)
1907                                .map(|(_, index)| *index)
1908                                .collect();
1909                            here.sort_unstable();
1910                            let outside = wanted.iter().any(|(held, _)| *held != place);
1911                            if !outside {
1912                                let mut rest: &mut [Item] = &mut line.items;
1913                                let mut passed = 0;
1914                                for index in here {
1915                                    let (_, tail) = rest.split_at_mut(index - passed);
1916                                    let (item, tail) = tail.split_first_mut().ok_or_else(|| {
1917                                        refused(abc_error("a lyric's note is missing"))
1918                                    })?;
1919                                    targets.push(&mut item.element);
1920                                    rest = tail;
1921                                    passed = index + 1;
1922                                }
1923                                add_lyrics(data, &mut targets).map_err(refused)?;
1924                            } else {
1925                                add_lyrics_across(data, &wanted, &mut measures, line, place)
1926                                    .map_err(refused)?;
1927                            }
1928                        }
1929                        match tag.as_str() {
1930                            "M" => {
1931                                if let Some(meter) = meter_of(data).map_err(refused)? {
1932                                    if use_measures {
1933                                        line.set_at_start(meter.into());
1934                                    } else {
1935                                        line.append(meter, None);
1936                                    }
1937                                }
1938                            }
1939                            "K" => {
1940                                let key = key_of(data).map_err(refused)?;
1941                                if use_measures {
1942                                    line.set_at_start(key);
1943                                } else {
1944                                    line.append(key, None);
1945                                }
1946                                if let Some((clef, transposition)) = clef_of(data) {
1947                                    if use_measures {
1948                                        line.set_at_start(clef.into());
1949                                    } else {
1950                                        line.append(clef, None);
1951                                    }
1952                                    reader.post_transposition = transposition;
1953                                }
1954                            }
1955                            "Q" => line.append(tempo_of(data).map_err(refused)?, None),
1956                            _ => {}
1957                        }
1958                    }
1959                    Token::Note(note) => {
1960                        let (symbol, made) = note_elements(note, &mut reader).map_err(refused)?;
1961                        if let Some(symbol) = symbol {
1962                            line.append(symbol, None);
1963                        }
1964                        if let Some((element, uid)) = made {
1965                            let sung = !matches!(element, StreamElement::Rest(_)) && !note.in_grace;
1966                            line.append(element, uid);
1967                            if sung {
1968                                reader.lyric_targets.push((place, line.items.len() - 1));
1969                            }
1970                        }
1971                    }
1972                    Token::SpannerStart(_, Some(index)) => {
1973                        started.push((*index, place, line.end));
1974                    }
1975                    _ => {}
1976                }
1977            }
1978        }
1979
1980        if in_measure {
1981            if bar_count == 1
1982                && let Some(meter) = measure.line.meter()
1983            {
1984                // A short first measure is a pickup, numbered nought.
1985                let bar = meter.bar_quarter_length();
1986                let highest = measure_stream(&measure.line).end_offset();
1987                if highest < bar {
1988                    measure.padding_left = bar - highest;
1989                }
1990                measure.number = 0;
1991            } else {
1992                measure.number = measure_number;
1993                measure_number += 1;
1994            }
1995            // Lyric targets name a measure by its place among them.
1996            measures.push(measure);
1997        }
1998    }
1999
2000    // Where each measure stood as music21 appended it, before `reBar`
2001    // cut any in two: where a spanner opening in it was appended.
2002    let mut appended_at: Vec<FloatType> = Vec::new();
2003    let mut reached = 0.0;
2004    for measure in &measures {
2005        appended_at.push(reached);
2006        reached = op_frac(reached + measure.line.end);
2007    }
2008
2009    re_bar(&mut measures, &mut brackets);
2010
2011    // Endings, from the brackets over the measures.
2012    let mut endings: Vec<Option<Ending>> = vec![None; measures.len()];
2013    // An ending never closed is left out, as music21 leaves it.
2014    for bracket in brackets.iter().filter(|bracket| bracket.complete) {
2015        for (place, index) in bracket.measures.iter().enumerate() {
2016            if let Some(slot) = endings.get_mut(*index)
2017                && slot.is_none()
2018            {
2019                *slot = Some(Ending::new(
2020                    vec![bracket.number],
2021                    place == 0,
2022                    place + 1 == bracket.measures.len(),
2023                ));
2024            }
2025        }
2026    }
2027
2028    // A part with no clef takes the one that fits its notes best.
2029    let has_clef = measures
2030        .iter()
2031        .flat_map(|measure| &measure.line.items)
2032        .chain(&part.items)
2033        .any(|item| matches!(item.element, StreamElement::Clef(_)));
2034    if !has_clef {
2035        let mut pitches: Vec<Pitch> = Vec::new();
2036        for item in measures
2037            .iter()
2038            .flat_map(|measure| measure.line.sorted())
2039            .chain(part.sorted())
2040        {
2041            match &item.element {
2042                StreamElement::Note(note) => pitches.push(note.pitch().clone()),
2043                StreamElement::Chord(chord) => pitches.extend(chord.pitches()),
2044                StreamElement::ChordSymbol(symbol) => {
2045                    pitches.extend(symbol.pitches().unwrap_or_default());
2046                }
2047                _ => {}
2048            }
2049        }
2050        let clef = Clef::best_for(&pitches, false);
2051        match measures.first_mut() {
2052            Some(first) if use_measures => first.line.set_at_start(clef.into()),
2053            _ => {
2054                part.items.push(Item {
2055                    offset: 0.0,
2056                    seq: part.seq,
2057                    uid: None,
2058                    element: clef.into(),
2059                });
2060                part.seq += 1;
2061            }
2062        }
2063    }
2064
2065    if reader.post_transposition != 0 {
2066        // music21 transposes by a count of semitones, which spells each
2067        // note afresh from where it lands and decides nothing about how its
2068        // accidental is shown.
2069        let interval = Interval::from_semitones(reader.post_transposition)?;
2070        for item in measures
2071            .iter_mut()
2072            .flat_map(|measure| &mut measure.line.items)
2073            .chain(&mut part.items)
2074        {
2075            // A chord symbol moves with the notes, as music21 moves any
2076            // element that can be transposed.
2077            let moves = item.element.is_note_or_chord()
2078                || matches!(item.element, StreamElement::ChordSymbol(_));
2079            if moves {
2080                item.element = item.element.transpose(&interval)?;
2081            }
2082        }
2083    }
2084
2085    // Put together: the measures one after another, or the part's own line.
2086    let mut uids: Vec<Option<usize>> = Vec::new();
2087    let mut events = Vec::new();
2088    let mut offset = 0.0;
2089    let has_meter = part.meter().is_some()
2090        || measures
2091            .iter()
2092            .any(|measure| measure.line.meter().is_some());
2093    for (index, measure) in measures.into_iter().enumerate() {
2094        let mut inner = Vec::new();
2095        for item in measure.line.sorted() {
2096            uids.push(item.uid);
2097            inner.push(StreamEvent::new(item.offset, item.element.clone()));
2098        }
2099        let mut stream = Stream::from_events(inner);
2100        stream.set_kind(StreamKind::Measure);
2101        stream.set_number(measure.number);
2102        stream.set_left_barline(measure.left);
2103        stream.set_right_barline(measure.right);
2104        stream.set_ending(endings[index].clone());
2105        stream.set_padding_left(measure.padding_left);
2106        let length = measure.line.end;
2107        events.push(StreamEvent::new(offset, stream));
2108        offset = op_frac(offset + length);
2109    }
2110    for item in part.sorted() {
2111        uids.push(item.uid);
2112        events.push(StreamEvent::new(item.offset, item.element.clone()));
2113    }
2114    let mut stream = Stream::from_events(events);
2115    stream.set_kind(StreamKind::Part);
2116
2117    if use_measures && has_meter {
2118        // music21 warns and carries on where a measure cannot be beamed.
2119        let _ = crate::makenotation::make_beams(&mut stream);
2120    }
2121
2122    // A measure's spanner stands where the measure did when music21
2123    // appended the spanner to the part.
2124    let held: Vec<Spanning> = started
2125        .into_iter()
2126        .map(|(index, measure, end)| {
2127            let mut held = reader.spanners[index].clone();
2128            held.offset = match measure {
2129                Some(measure) => appended_at.get(measure).copied().unwrap_or(reached),
2130                None => end,
2131            };
2132            held
2133        })
2134        .collect();
2135    Ok((stream, uids, held))
2136}
2137
2138/// Words sung to notes of measures already closed as well as this one.
2139fn add_lyrics_across(
2140    data: &str,
2141    wanted: &[(Option<usize>, usize)],
2142    measures: &mut [MeasureIr],
2143    line: &mut Line,
2144    place: Option<usize>,
2145) -> Result<()> {
2146    // One mutable borrow per note: each is reached in turn by where it is.
2147    let mut elements: Vec<StreamElement> = Vec::new();
2148    for (held, index) in wanted {
2149        let item = if *held == place {
2150            line.items.get(*index)
2151        } else {
2152            held.and_then(|measure| measures.get(measure))
2153                .and_then(|measure| measure.line.items.get(*index))
2154        };
2155        elements.push(
2156            item.map(|item| item.element.clone())
2157                .ok_or_else(|| abc_error("a lyric's note is missing"))?,
2158        );
2159    }
2160    {
2161        let mut targets: Vec<&mut StreamElement> = elements.iter_mut().collect();
2162        add_lyrics(data, &mut targets)?;
2163    }
2164    for ((held, index), element) in wanted.iter().zip(elements) {
2165        let slot = if *held == place {
2166            line.items.get_mut(*index)
2167        } else {
2168            held.and_then(|measure| measures.get_mut(measure))
2169                .and_then(|measure| measure.line.items.get_mut(*index))
2170        };
2171        if let Some(slot) = slot {
2172            slot.element = element;
2173        }
2174    }
2175    Ok(())
2176}
2177
2178/// A line as the measure it will be, for the questions asked of a stream.
2179fn measure_stream(line: &Line) -> Stream {
2180    let mut stream = Stream::from_events(
2181        line.sorted()
2182            .into_iter()
2183            .map(|item| StreamEvent::new(item.offset, item.element.clone())),
2184    );
2185    stream.set_kind(StreamKind::Measure);
2186    stream
2187}
2188
2189/// music21's `reBar`: a measure holding more than its bar is cut in two, the
2190/// second taking the meter that fits it where it is not a whole bar, and
2191/// every later measure is numbered one further on.
2192///
2193/// An overflow no meter fits is kept as a measure stating none. music21
2194/// gives up where it stands on a measure with no meter in force, or one it
2195/// cannot cut, keeping what it had done.
2196fn re_bar(measures: &mut Vec<MeasureIr>, brackets: &mut [Bracket]) {
2197    let mut meter: Option<TimeSignature> = None;
2198    let mut shift = 0;
2199    // Where each measure read stands once the cut ones are in.
2200    let mut places: Vec<usize> = (0..measures.len()).collect();
2201    let mut index = 0;
2202    let mut original = 0;
2203    let count = measures.len();
2204    'measures: while original < count {
2205        if let Some(own) = measures[index].line.meter() {
2206            meter = Some(own.clone());
2207        }
2208        let Some(current) = meter.clone() else {
2209            break;
2210        };
2211        places[original] = index;
2212        let bar = op_frac(current.bar_quarter_length());
2213        let end = measures[index].line.end;
2214        measures[index].number += shift;
2215        if end > bar + 1e-9 {
2216            let mut second = Line::default();
2217            let mut kept: Vec<Item> = Vec::new();
2218            let mut moved: Vec<Item> = Vec::new();
2219            let items = std::mem::take(&mut measures[index].line.items);
2220            let mut broken = false;
2221            for item in items {
2222                let length = item.element.quarter_length();
2223                if (item.offset - bar).abs() <= 1e-9 && length == 0.0 {
2224                    // Something with no length standing on the barline ends
2225                    // where the new measure starts, and stays behind.
2226                    kept.push(item);
2227                } else if item.offset >= bar - 1e-9 {
2228                    moved.push(item);
2229                } else if item.offset + length > bar + 1e-9 {
2230                    match split_element(&item.element, op_frac(bar - item.offset)) {
2231                        Ok((first, remain)) => {
2232                            second.items.push(Item {
2233                                offset: 0.0,
2234                                seq: second.seq,
2235                                uid: None,
2236                                element: remain,
2237                            });
2238                            second.seq += 1;
2239                            kept.push(Item {
2240                                element: first,
2241                                ..item
2242                            });
2243                        }
2244                        Err(_) => {
2245                            broken = true;
2246                            kept.push(item);
2247                        }
2248                    }
2249                } else {
2250                    kept.push(item);
2251                }
2252            }
2253            measures[index].line.items = kept;
2254            measures[index].line.end = bar;
2255            if broken {
2256                break 'measures;
2257            }
2258            for item in moved {
2259                second.items.push(Item {
2260                    offset: op_frac(item.offset - bar),
2261                    seq: second.seq,
2262                    ..item
2263                });
2264                second.seq += 1;
2265            }
2266            second.end = op_frac(end - bar);
2267            if (bar - second.end).abs() > 1e-9
2268                && let Ok(best) = crate::meter::best_time_signature(&measure_stream(&second))
2269            {
2270                second.set_at_start(best.into());
2271                if original + 1 < count && measures[index + 1].line.meter().is_none() {
2272                    // music21 puts the very meter object back, so it stands
2273                    // in two measures at once.
2274                    let mut again = current.clone();
2275                    again.set_restated(true);
2276                    measures[index + 1].line.set_at_start(again.into());
2277                }
2278            }
2279            let number = measures[index].number + 1;
2280            shift += 1;
2281            // The barline closing the measure closes the new one.
2282            let right = measures[index].right.take();
2283            measures.insert(
2284                index + 1,
2285                MeasureIr {
2286                    line: second,
2287                    number,
2288                    left: None,
2289                    right,
2290                    padding_left: 0.0,
2291                },
2292            );
2293            index += 1;
2294        }
2295        index += 1;
2296        original += 1;
2297    }
2298    for (passed, place) in places.iter_mut().skip(original).enumerate() {
2299        *place = index + passed;
2300    }
2301    for bracket in brackets {
2302        for measure in &mut bracket.measures {
2303            *measure = places[*measure];
2304        }
2305    }
2306}
2307
2308/// music21's `abcToStreamScore`.
2309fn score_of(handler: &Handler, spanners: &[Spanning]) -> Result<Stream> {
2310    let mut metadata = Metadata::new();
2311    let mut titles = 0;
2312    for token in &handler.tokens {
2313        let Some((tag, data)) = token.metadata() else {
2314            continue;
2315        };
2316        let line = token.line();
2317        match tag {
2318            "T" => {
2319                metadata.add_text(
2320                    if titles == 0 {
2321                        "title"
2322                    } else {
2323                        "alternativeTitle"
2324                    },
2325                    data,
2326                );
2327                titles += 1;
2328            }
2329            "C" => metadata.add_contributor("composer", data),
2330            "O" => metadata.add_text("localeOfComposition", data),
2331            "X" => {
2332                let number = data.trim().parse::<IntegerType>().map_err(|_| {
2333                    let refused = abc_error(format!("the reference number {data:?} is no number"));
2334                    at_line(refused, line)
2335                })?;
2336                metadata.add_text("number", number.to_string());
2337            }
2338            _ => {}
2339        }
2340    }
2341
2342    let voices = handler.split_by_voice();
2343    let parts: Vec<Vec<Token>> = if voices.len() == 1 {
2344        voices
2345    } else {
2346        // The header goes in front of each voice.
2347        voices[1..]
2348            .iter()
2349            .map(|voice| {
2350                voices[0]
2351                    .iter()
2352                    .cloned()
2353                    .chain(voice.iter().cloned())
2354                    .collect()
2355            })
2356            .collect()
2357    };
2358
2359    let mut events = Vec::new();
2360    let mut uids: Vec<Option<(usize, usize)>> = Vec::new();
2361    let mut held: Vec<(usize, Spanning)> = Vec::new();
2362    for (index, tokens) in parts.iter().enumerate() {
2363        let (part, part_uids, part_spanners) = part_of(tokens, spanners)?;
2364        uids.extend(part_uids.into_iter().map(|uid| uid.map(|uid| (index, uid))));
2365        held.extend(part_spanners.into_iter().map(|spanner| (index, spanner)));
2366        events.push(StreamEvent::new(0.0, part));
2367    }
2368    let mut score = Stream::from_events(events);
2369    score.set_kind(StreamKind::Score);
2370    score.set_metadata(Some(metadata));
2371    for (part, spanner) in held {
2372        let positions: Vec<Option<usize>> = spanner
2373            .uids
2374            .iter()
2375            .map(|uid| uids.iter().position(|held| *held == Some((part, *uid))))
2376            .collect();
2377        let mut made = match spanner.kind {
2378            SpannerKind::Crescendo | SpannerKind::Diminuendo => {
2379                let template = Spanner::wedge(spanner.kind, Vec::new());
2380                let mut wedge = Spanner::with_unplaced(spanner.kind, positions);
2381                wedge.set_placement(template.placement());
2382                wedge.set_spread(template.spread());
2383                wedge
2384            }
2385            kind => Spanner::with_unplaced(kind, positions),
2386        };
2387        made.set_offset(spanner.offset);
2388        for (place, uid) in spanner.uids.iter().enumerate() {
2389            if made.spanned().get(place).is_some_and(Option::is_some) {
2390                continue;
2391            }
2392            if let Some((_, stray)) = spanner.strays.iter().find(|(held, _)| held == uid) {
2393                made.set_unplaced_element(place, stray.clone());
2394            }
2395        }
2396        score.add_spanner(made);
2397    }
2398    Ok(score)
2399}
2400
2401/// music21's `extractReferenceNumber`: the lines of one tune, and how many
2402/// lines of the text stand before them.
2403fn extract_reference_number(text: &str, number: IntegerType) -> Result<(usize, String)> {
2404    let mut collected = Vec::new();
2405    let mut gathering = false;
2406    let mut before = 0;
2407    for line in text.split('\n') {
2408        let starts = line.trim().starts_with("X:");
2409        if starts && !gathering {
2410            let named = line.replace(' ', "");
2411            let named = named.trim_end().trim_start_matches("X:");
2412            if named.parse::<IntegerType>() == Ok(number) {
2413                gathering = true;
2414            }
2415        } else if starts && gathering {
2416            break;
2417        }
2418        if gathering {
2419            collected.push(line);
2420        } else if collected.is_empty() {
2421            before += 1;
2422        }
2423    }
2424    if collected.is_empty() {
2425        return Err(abc_error(format!(
2426            "cannot find requested reference number in source file: {number}"
2427        ))
2428        .of_kind(FormatErrorKind::NotFound));
2429    }
2430    Ok((before, collected.join("\n")))
2431}
2432
2433fn handler_of(text: &str) -> Result<(Handler, Vec<Spanning>)> {
2434    let mut handler = Handler::new(DEFAULT_VERSION);
2435    handler.read_version(text);
2436    handler.tokenize(text)?;
2437    let spanners = handler.process()?;
2438    Ok((handler, spanners))
2439}
2440
2441/// Reads ABC text into a score: music21's `converter.parse` for the format.
2442///
2443/// A file holding one tune comes back as a score, with a part for each of
2444/// its voices. A file holding several tunes, each under its own `X:`
2445/// reference number, comes back as an opus of scores in the order of their
2446/// numbers.
2447///
2448/// ```
2449/// use music21::abc::from_abc;
2450///
2451/// let score = from_abc("X:1\nT:Scale\nM:4/4\nL:1/4\nK:G\nG A B c | d e f g |\n")?;
2452/// let part = score.parts()[0];
2453/// assert_eq!(part.measures().len(), 2);
2454/// // The key's F sharp is read into the note.
2455/// assert_eq!(part.measures()[1].pitches()[2].name_with_octave(), "F#5");
2456/// # Ok::<(), music21::Error>(())
2457/// ```
2458pub fn from_abc(text: &str) -> Result<Stream> {
2459    let (handler, spanners) = handler_of(text)?;
2460    if handler.defines_reference_numbers() {
2461        let mut events = Vec::new();
2462        let mut offset = 0.0;
2463        for (_, tune) in handler.split_by_reference_number() {
2464            let score = score_of(&tune, &spanners)?;
2465            let length = score.end_offset();
2466            events.push(StreamEvent::new(offset, score));
2467            offset += length;
2468        }
2469        let mut opus = Stream::from_events(events);
2470        opus.set_kind(StreamKind::Opus);
2471        return Ok(opus);
2472    }
2473    score_of(&handler, &spanners)
2474}
2475
2476/// Reads one tune out of ABC text holding several, by its `X:` reference
2477/// number: music21's `converter.parse(..., number=n)`.
2478pub fn from_abc_number(text: &str, number: IntegerType) -> Result<Stream> {
2479    let (before, tune) = extract_reference_number(text, number)?;
2480    let read = handler_of(&tune).and_then(|(handler, spanners)| score_of(&handler, &spanners));
2481    read.map_err(|error| error.lines_down(before))
2482}
2483
2484#[cfg(test)]
2485mod tests {
2486    use super::*;
2487
2488    fn tokens_of(text: &str) -> Vec<Token> {
2489        let mut handler = Handler::new(DEFAULT_VERSION);
2490        handler.tokenize(text).unwrap();
2491        handler.tokens
2492    }
2493
2494    #[test]
2495    fn a_bar_says_what_it_is() {
2496        // music21's `ABCBar.parse` docstring.
2497        let bar = Bar::new("|");
2498        assert!(bar.is_regular() && !bar.repeat);
2499        let end = Bar::new(":|");
2500        assert!(end.repeat && end.form == "end" && end.style == "light-heavy");
2501        let first = Bar::new("[1");
2502        assert_eq!(first.repeat_bracket(), Some(1));
2503        assert_eq!(
2504            Bar::new("||").barline().unwrap().bar_type(),
2505            BarlineType::Double
2506        );
2507    }
2508
2509    /// A slur over a grace note holds the note music21 made before it
2510    /// copied it as a grace, which no stream holds: the spanner keeps it.
2511    #[test]
2512    fn a_slur_keeps_the_grace_note_no_stream_holds() {
2513        let score = from_abc("X:1\nM:4/4\nL:1/8\nK:C\n(g2{a}g) c4 |\n").unwrap();
2514        let slur = &score.spanners()[0];
2515        assert_eq!(slur.len(), 3);
2516        assert_eq!(slur.spanned()[1], None);
2517        let stray: Vec<(usize, String)> = slur
2518            .unplaced_elements()
2519            .iter()
2520            .map(|(place, element)| (*place, element.pitches()[0].name_with_octave()))
2521            .collect();
2522        assert_eq!(stray, [(1, "A5".to_string())]);
2523    }
2524
2525    #[test]
2526    fn text_is_cut_into_tokens_as_music21_cuts_it() {
2527        let tokens = tokens_of("M:6/8\nL:1/8\nK:G\nB3 A3 | (3GAB c2 :|\n");
2528        let kinds: Vec<&str> = tokens
2529            .iter()
2530            .map(|token| match token {
2531                Token::Metadata { .. } => "meta",
2532                Token::Bar(_) => "bar",
2533                Token::Tuplet { .. } => "tuplet",
2534                Token::Note(_) => "note",
2535                _ => "other",
2536            })
2537            .collect();
2538        assert_eq!(
2539            kinds,
2540            [
2541                "meta", "meta", "meta", "note", "note", "bar", "tuplet", "note", "note", "note",
2542                "note", "bar"
2543            ]
2544        );
2545    }
2546
2547    /// Each note's source and the kinds of the spanners in force on it.
2548    fn spanners_of(body: &str) -> Vec<(String, Vec<SpannerKind>)> {
2549        let mut handler = Handler::new(DEFAULT_VERSION);
2550        handler
2551            .tokenize(&format!("X:1\nM:4/4\nL:1/8\nK:C\n{body}\n"))
2552            .unwrap();
2553        let spanners = handler.process().unwrap();
2554        handler
2555            .tokens
2556            .iter()
2557            .filter_map(|token| match token {
2558                Token::Note(note) => Some((
2559                    note.src.trim().to_string(),
2560                    note.spanners
2561                        .iter()
2562                        .map(|index| spanners[*index].kind)
2563                        .collect(),
2564                )),
2565                _ => None,
2566            })
2567            .collect()
2568    }
2569
2570    #[test]
2571    fn a_closing_mark_ends_the_latest_spanner_of_its_kind() {
2572        // music21's `testSlurAroundTuplet` (cuthbertLab #1798).
2573        use SpannerKind::{Crescendo, Diminuendo, Slur};
2574        let expect = |pairs: &[(&str, &[SpannerKind])]| -> Vec<(String, Vec<SpannerKind>)> {
2575            pairs
2576                .iter()
2577                .map(|(src, kinds)| (src.to_string(), kinds.to_vec()))
2578                .collect()
2579        };
2580        // A tuplet has no closing parenthesis, so ')' ends the slur.
2581        assert_eq!(
2582            spanners_of("(a(3bcd e) f|"),
2583            expect(&[
2584                ("a", &[Slur]),
2585                ("b", &[Slur]),
2586                ("c", &[Slur]),
2587                ("d", &[Slur]),
2588                ("e", &[Slur]),
2589                ("f", &[]),
2590            ])
2591        );
2592        assert_eq!(
2593            spanners_of("!crescendo(! (3abc d !crescendo)! e|"),
2594            expect(&[
2595                ("a", &[Crescendo]),
2596                ("b", &[Crescendo]),
2597                ("c", &[Crescendo]),
2598                ("d", &[Crescendo]),
2599                ("e", &[]),
2600            ])
2601        );
2602        // A slur and a crescendo can overlap without nesting.
2603        assert_eq!(
2604            spanners_of("(a !crescendo(! b) c !crescendo)! d|"),
2605            expect(&[
2606                ("a", &[Slur]),
2607                ("b", &[Slur, Crescendo]),
2608                ("c", &[Crescendo]),
2609                ("d", &[]),
2610            ])
2611        );
2612        assert_eq!(
2613            spanners_of("!diminuendo(! a (b !diminuendo)! c) d|"),
2614            expect(&[
2615                ("a", &[Diminuendo]),
2616                ("b", &[Diminuendo, Slur]),
2617                ("c", &[Slur]),
2618                ("d", &[]),
2619            ])
2620        );
2621    }
2622
2623    #[test]
2624    fn a_key_line_gives_its_sharps_and_mode() {
2625        // music21's `getKeySignatureParameters` docstring.
2626        assert_eq!(key_parameters("Eb").unwrap(), (-3, Some("major")));
2627        assert_eq!(
2628            key_parameters("A mixolydian").unwrap(),
2629            (2, Some("mixolydian"))
2630        );
2631        assert_eq!(key_parameters("F#m").unwrap(), (3, Some("minor")));
2632        assert_eq!(key_parameters("HP").unwrap(), (0, None));
2633        assert_eq!(key_parameters("Hp").unwrap(), (2, None));
2634    }
2635
2636    #[test]
2637    fn a_length_is_read_against_the_default() {
2638        // music21's `getQuarterLength` docstring.
2639        let mut note = AbcNote::new("", 1, "", false);
2640        note.default_quarter_length = Some(0.5);
2641        assert_eq!(note.read_quarter_length("f", None).unwrap(), 0.5);
2642        assert_eq!(note.read_quarter_length("f2", None).unwrap(), 1.0);
2643        assert_eq!(note.read_quarter_length("f/", None).unwrap(), 0.25);
2644        assert_eq!(note.read_quarter_length("f3/2", None).unwrap(), 0.75);
2645        note.broken_rhythm = Some((">".to_string(), true));
2646        assert_eq!(note.read_quarter_length("A", None).unwrap(), 0.75);
2647    }
2648
2649    #[test]
2650    fn a_pitch_takes_its_accidental_from_the_key() {
2651        let mut note = AbcNote::new("f", 1, "", false);
2652        note.key = Some(KeySignature::new(1));
2653        assert_eq!(
2654            note.pitch_name("f", None).unwrap(),
2655            (Some("F#5".to_string()), Some(false))
2656        );
2657        assert_eq!(
2658            note.pitch_name("=f", None).unwrap(),
2659            (Some("Fn5".to_string()), Some(true))
2660        );
2661        assert_eq!(note.pitch_name("z", None).unwrap(), (None, None));
2662        assert_eq!(
2663            note.pitch_name("C,,", None).unwrap(),
2664            (Some("C2".to_string()), Some(false))
2665        );
2666    }
2667
2668    #[test]
2669    fn a_refusal_says_its_line_and_measure() {
2670        let error = from_abc("X:1\nK:C\nc d ~.").unwrap_err();
2671        assert_eq!(error.to_string(), "ABC error: a decoration ends the text");
2672        assert_eq!(error.format_error().unwrap().kind, FormatErrorKind::Invalid);
2673        assert_eq!(error.position(), Some(&Position::line(3).with_column(5)));
2674
2675        let error = from_abc("X:1\nL:1/4\nK:C\n(0c d e\n").unwrap_err();
2676        assert_eq!(error.position(), Some(&Position::line(4)));
2677
2678        let tune = "X:2\nM:4/4\nL:1/4\nK:C\nc d e f |\ng a Q:1/4=x\nb c |\nc d e f |\n";
2679        let error = from_abc(tune).unwrap_err();
2680        assert_eq!(
2681            error.to_string(),
2682            "ABC error: cannot read the tempo \"1/4=x\""
2683        );
2684        let mut wanted = Position::line(6);
2685        wanted.measure = Some("2".to_string());
2686        assert_eq!(error.position(), Some(&wanted));
2687
2688        let opus = format!("X:1\nK:C\nc d e f |\n{tune}");
2689        let error = from_abc_number(&opus, 2).unwrap_err();
2690        wanted.line = Some(9);
2691        assert_eq!(error.position(), Some(&wanted));
2692    }
2693
2694    #[test]
2695    fn a_tune_is_a_score_of_measures() {
2696        let score =
2697            from_abc("X:1\nT:Tune\nC:Anon\nM:3/4\nL:1/4\nK:D\nD E F | G A B | c d2 |]\n").unwrap();
2698        assert_eq!(score.kind(), StreamKind::Score);
2699        let metadata = score.metadata().unwrap();
2700        assert_eq!(metadata.first_text("title"), Some("Tune"));
2701        let part = score.parts()[0];
2702        let measures = part.measures();
2703        assert_eq!(measures.len(), 3);
2704        let names: Vec<String> = measures[0]
2705            .pitches()
2706            .iter()
2707            .map(|pitch| pitch.name_with_octave())
2708            .collect();
2709        assert_eq!(names, ["D4", "E4", "F#4"]);
2710        assert_eq!(
2711            measures[2].right_barline().unwrap().bar_type(),
2712            BarlineType::Final
2713        );
2714    }
2715
2716    #[test]
2717    fn several_tunes_are_an_opus_and_one_can_be_asked_for() {
2718        let text = "X:1\nT:One\nM:2/4\nL:1/4\nK:C\nC D | E F |]\n\nX:2\nT:Two\nM:2/4\nL:1/4\nK:C\nG A | B c |]\n";
2719        let opus = from_abc(text).unwrap();
2720        assert_eq!(opus.kind(), StreamKind::Opus);
2721        assert_eq!(opus.events().len(), 2);
2722        let second = from_abc_number(text, 2).unwrap();
2723        assert_eq!(second.metadata().unwrap().first_text("title"), Some("Two"));
2724        assert!(from_abc_number(text, 3).is_err());
2725    }
2726
2727    #[test]
2728    fn a_measure_holding_more_than_its_bar_is_cut_in_two() {
2729        // Six quarters between barlines in 4/4: a whole bar, then a 2/4 bar
2730        // holding the tied remainder of the long note, and the meter put
2731        // back on the measure after.
2732        let score = from_abc(
2733            "X:1
2734M:4/4
2735L:1/4
2736K:C
2737CDEF|GAB4|CDEF|
2738",
2739        )
2740        .unwrap();
2741        let part = score.events()[0].element().as_stream().unwrap();
2742        let measures = part.measures();
2743        let numbers: Vec<_> = measures.iter().map(|measure| measure.number()).collect();
2744        assert_eq!(numbers, [0, 1, 2, 3]);
2745        let meter = |measure: &Stream| {
2746            measure
2747                .events()
2748                .iter()
2749                .find_map(|event| match event.element() {
2750                    StreamElement::TimeSignature(meter) => Some(meter.ratio_string()),
2751                    _ => None,
2752                })
2753        };
2754        assert_eq!(meter(measures[1]), None);
2755        assert_eq!(meter(measures[2]).as_deref(), Some("2/4"));
2756        assert_eq!(meter(measures[3]).as_deref(), Some("4/4"));
2757        let ties: Vec<_> = measures[1..3]
2758            .iter()
2759            .flat_map(|measure| measure.events())
2760            .filter_map(|event| match event.element() {
2761                StreamElement::Note(note) if note.pitch().name() == "B" => Some((
2762                    event.element().quarter_length(),
2763                    note.tie().map(Tie::tie_type),
2764                )),
2765                _ => None,
2766            })
2767            .collect();
2768        assert_eq!(
2769            ties,
2770            [(2.0, Some(TieType::Start)), (2.0, Some(TieType::Stop))]
2771        );
2772    }
2773}