1use 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
35const DEFAULT_VERSION: (u32, u32, u32) = (1, 3, 0);
38
39const 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
57fn 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#[derive(Clone, Debug, Default, PartialEq)]
76struct Bar {
77 src: String,
78 repeat: bool,
80 style: String,
81 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 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 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#[derive(Clone, Debug, Default)]
144struct AbcNote {
145 src: String,
146 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 broken_rhythm: Option<(String, bool)>,
155 key: Option<KeySignature>,
156 tuplet: Option<Tuplet>,
157 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 SpannerStart(SpannerKind, Option<usize>),
183 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 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
222fn 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
230fn 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
254fn 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
284fn 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 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 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
341fn 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
355fn 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
370fn 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
424fn 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 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 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 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 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 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 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 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 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#[derive(Clone, Debug)]
676struct Spanning {
677 kind: SpannerKind,
678 uids: Vec<usize>,
679 strays: Vec<(usize, StreamElement)>,
682 offset: FloatType,
685}
686
687#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
1307fn 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#[derive(Clone, Debug, Default)]
1340struct BarHandler {
1341 tokens: Vec<Token>,
1342 left: Option<Bar>,
1343 right: Option<Bar>,
1344}
1345
1346impl BarHandler {
1347 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
1362fn split_by_measure(tokens: &[Token]) -> Vec<BarHandler> {
1364 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 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 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
1433fn 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#[derive(Clone, Debug)]
1466struct Item {
1467 offset: FloatType,
1468 seq: usize,
1469 uid: Option<usize>,
1470 element: StreamElement,
1471}
1472
1473#[derive(Clone, Debug, Default)]
1476struct Line {
1477 items: Vec<Item>,
1478 end: FloatType,
1479 seq: usize,
1480}
1481
1482impl Line {
1483 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 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 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
1545pub(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#[derive(Clone, Debug)]
1572struct Bracket {
1573 number: u32,
1574 measures: Vec<usize>,
1575 complete: bool,
1576}
1577
1578struct PartReader {
1580 spanners: Vec<Spanning>,
1581 next_uid: usize,
1582 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
1594fn 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
1628type Placed = (StreamElement, Option<usize>);
1630
1631fn 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 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 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 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
1758fn 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
1770fn 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
1791fn grace_of(duration: &Duration) -> Duration {
1794 duration.grace_duration()
1795}
1796
1797fn 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 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 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 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 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 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 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 measures.push(measure);
1997 }
1998 }
1999
2000 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 let mut endings: Vec<Option<Ending>> = vec![None; measures.len()];
2013 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 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 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 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 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 let _ = crate::makenotation::make_beams(&mut stream);
2120 }
2121
2122 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
2138fn 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 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
2178fn 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
2189fn re_bar(measures: &mut Vec<MeasureIr>, brackets: &mut [Bracket]) {
2197 let mut meter: Option<TimeSignature> = None;
2198 let mut shift = 0;
2199 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 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 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 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
2308fn 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 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
2401fn 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
2441pub 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
2476pub 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 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 #[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 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 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 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 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 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 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 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}