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, 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 is_chord: bool,
147 carried_accidental: String,
148 chord_symbols: Vec<String>,
149 in_grace: bool,
150 default_quarter_length: Option<FloatType>,
151 broken_rhythm: Option<(String, bool)>,
153 key: Option<KeySignature>,
154 tuplet: Option<Tuplet>,
155 spanners: Vec<usize>,
157 tie: Option<TieType>,
158 articulations: Vec<&'static str>,
159 accidental_display: Option<bool>,
160 is_rest: bool,
161 pitch_name: Option<String>,
162 quarter_length: FloatType,
163 sub_tokens: Vec<AbcNote>,
164}
165
166#[derive(Clone, Debug)]
167enum Token {
168 Metadata {
169 tag: String,
170 data: String,
171 },
172 Bar(Bar),
173 Tuplet {
174 src: String,
175 },
176 Tie,
177 SpannerStart(SpannerKind, Option<usize>),
179 ParenStop,
180 Staccato,
181 Upbow,
182 Downbow,
183 Accent,
184 Straccent,
185 Tenuto,
186 GraceStart,
187 GraceStop,
188 BrokenRhythm(String),
189 Note(Box<AbcNote>),
190}
191
192impl Token {
193 fn is_note(&self) -> bool {
194 matches!(self, Self::Note(_))
195 }
196
197 fn metadata(&self) -> Option<(&str, &str)> {
198 match self {
199 Self::Metadata { tag, data } => Some((tag, data)),
200 _ => None,
201 }
202 }
203}
204
205fn metadata_token(src: &str) -> Token {
208 let chars: Vec<char> = src.chars().collect();
209 let is_tag =
210 chars.len() >= 2 && (chars[0].is_ascii_uppercase() || chars[0] == 'w') && chars[1] == ':';
211 if !is_tag {
212 return Token::Metadata {
213 tag: String::new(),
214 data: String::new(),
215 };
216 }
217 let stripped = src.split('%').next().unwrap_or("");
218 let mut pieces = stripped.chars();
219 let tag: String = pieces.by_ref().take(1).collect();
220 let data: String = pieces.skip(1).collect();
221 Token::Metadata {
222 tag,
223 data: data.trim().to_string(),
224 }
225}
226
227fn meter_parameters(data: &str) -> Result<Option<(u32, u32)>> {
229 if data.to_lowercase() == "none" {
230 return Ok(None);
231 }
232 match data {
233 "C" => return Ok(Some((4, 4))),
234 "C|" => return Ok(Some((2, 2))),
235 _ => {}
236 }
237 let (numerator, denominator) = data
238 .split_once('/')
239 .ok_or_else(|| abc_error(format!("cannot read the meter {data:?}")))?;
240 let digits = |text: &str| -> Result<u32> {
241 text.chars()
242 .filter(char::is_ascii_digit)
243 .collect::<String>()
244 .parse()
245 .map_err(|_| abc_error(format!("cannot read the meter {data:?}")))
246 };
247 Ok(Some((digits(numerator)?, digits(denominator)?)))
248}
249
250fn meter_of(data: &str) -> Result<Option<TimeSignature>> {
251 match meter_parameters(data)? {
252 Some((numerator, denominator)) => Ok(Some(TimeSignature::new(numerator, denominator)?)),
253 None => Ok(None),
254 }
255}
256
257fn key_parameters(data: &str) -> Result<(IntegerType, Option<&'static str>)> {
260 const NAMES: [&str; 20] = [
261 "c", "g", "d", "a", "e", "b", "f#", "g#", "a#", "f", "bb", "eb", "d#", "ab", "e#", "db",
262 "c#", "gb", "cb", "hp",
263 ];
264 let mut names: Vec<&str> = NAMES.to_vec();
265 names.sort_by_key(|name| std::cmp::Reverse(name.len()));
267 let chars: Vec<char> = data.chars().collect();
268 let mut standard = "C".to_string();
269 let mut remain = String::new();
270 for target in names {
271 let length = target.chars().count();
272 let head: String = chars.iter().take(length).collect();
273 if head.to_lowercase() == target {
274 standard = head;
275 remain = chars.iter().skip(length).collect();
276 break;
277 }
278 }
279 let letters: Vec<char> = standard.chars().collect();
280 if letters.len() > 1 && letters[1] == 'b' {
281 standard = format!("{}-", letters[0]);
282 }
283 let remain = remain.trim().to_lowercase();
284 let mut mode: Option<&'static str> = if remain.is_empty() {
285 Some("major")
286 } else {
287 [
288 ("dor", "dorian"),
289 ("phr", "phrygian"),
290 ("lyd", "lydian"),
291 ("mix", "mixolydian"),
292 ("maj", "major"),
293 ("ion", "ionian"),
294 ("aeo", "aeolian"),
295 ("m", "minor"),
296 ]
297 .into_iter()
298 .find(|(prefix, _)| remain.starts_with(prefix))
299 .map(|(_, mode)| mode)
300 };
301 if standard == "HP" {
303 standard = "C".to_string();
304 mode = None;
305 } else if standard == "Hp" {
306 standard = "D".to_string();
307 mode = None;
308 }
309 let tonic = Pitch::from_name(&standard)?;
310 let sharps = crate::key::pitch_to_sharps(&tonic, mode)?;
311 Ok((sharps, mode))
312}
313
314fn key_of(data: &str) -> Result<StreamElement> {
317 let (sharps, mode) = key_parameters(data)?;
318 let signature = KeySignature::new(sharps);
319 Ok(match mode {
320 Some(mode) => match signature.try_as_key(Some(mode), None) {
321 Ok(key) => key.into(),
322 Err(_) => signature.into(),
323 },
324 None => signature.into(),
325 })
326}
327
328fn clef_of(data: &str) -> Option<(Clef, IntegerType)> {
331 let lower = data.to_lowercase();
332 if lower.contains("-8va") {
333 Clef::from_string("treble8vb", 0)
334 .ok()
335 .map(|clef| (clef, -12))
336 } else if lower.contains("bass") {
337 Some((Clef::bass(), -24))
338 } else {
339 None
340 }
341}
342
343fn tempo_of(data: &str) -> Result<MetronomeMark> {
345 let mut text: Option<String> = None;
346 let non_text = if data.contains('"') {
347 let mut quoted = String::new();
348 let mut outside = String::new();
349 let mut open = false;
350 for character in data.chars() {
351 if character == '"' {
352 open = !open;
353 } else if open {
354 quoted.push(character);
355 } else {
356 outside.push(character);
357 }
358 }
359 text = Some(quoted.trim().to_string()).filter(|text| !text.is_empty());
360 outside.trim().to_string()
361 } else {
362 data.trim().to_string()
363 };
364 let read = |number: &str| -> Result<FloatType> {
365 number
366 .trim()
367 .parse::<FloatType>()
368 .map_err(|_| abc_error(format!("cannot read the tempo {data:?}")))
369 };
370 let mut number: Option<FloatType> = None;
371 let mut referent: Option<FloatType> = None;
372 if !non_text.is_empty() {
373 if let Some((lengths, count)) = non_text.split_once('=') {
374 number = Some(read(count)?);
375 let mut quarters = 0.0;
376 for length in lengths.split(' ') {
377 let (numerator, denominator) = length.split_once('/').unwrap_or(("1", "1"));
378 quarters += read(numerator)? / read(denominator)? * 4.0;
379 }
380 referent = Some(quarters);
381 } else {
382 number = Some(read(&non_text)?);
383 }
384 }
385 let mut mark = match (number, text) {
386 (Some(number), Some(text)) => MetronomeMark::with_number_and_text(number, text),
387 (Some(number), None) => MetronomeMark::new(number),
388 (None, Some(text)) => MetronomeMark::from_text(text),
389 (None, None) => MetronomeMark::default(),
390 };
391 if let Some(referent) = referent {
392 mark.set_referent(Duration::new(referent)?);
393 }
394 Ok(mark)
395}
396
397fn default_quarter_length(tag: &str, data: &str) -> Result<FloatType> {
399 if tag == "L" && data.contains('/') {
400 let (numerator, denominator) = data.split_once('/').unwrap_or(("1", "8"));
401 let numerator: FloatType = numerator
402 .trim()
403 .parse()
404 .map_err(|_| abc_error(format!("cannot read the default length {data:?}")))?;
405 let denominator: FloatType = if denominator == "G" {
406 4.0
407 } else {
408 denominator
409 .trim()
410 .parse()
411 .map_err(|_| abc_error(format!("cannot read the default length {data:?}")))?
412 };
413 return Ok(numerator * 4.0 / denominator);
414 }
415 if tag == "M" {
416 return Ok(match meter_parameters(data)? {
417 None => 0.5,
418 Some((numerator, denominator))
420 if FloatType::from(numerator) / FloatType::from(denominator) < 0.75 =>
421 {
422 0.25
423 }
424 Some(_) => 0.5,
425 });
426 }
427 Err(abc_error(format!(
428 "no quarter length associated with this metadata: {data}"
429 )))
430}
431
432impl AbcNote {
433 fn new(src: &str, carried_accidental: &str, is_chord: bool) -> Self {
434 Self {
435 src: src.to_string(),
436 is_chord,
437 carried_accidental: carried_accidental.to_string(),
438 ..Self::default()
439 }
440 }
441
442 fn split_chord_symbols(src: &str) -> (Vec<String>, String) {
445 if !src.contains('"') {
446 return (Vec::new(), src.to_string());
447 }
448 let chars: Vec<char> = src.chars().collect();
449 let mut symbols = Vec::new();
450 let mut index = 0;
451 let mut after = 0;
452 while index < chars.len() {
453 if chars[index] == '"'
454 && let Some(length) = chars[index + 1..].iter().position(|c| *c == '"')
455 {
456 let close = index + 1 + length;
457 symbols.push(chars[index..=close].iter().collect::<String>());
458 index = close + 1;
459 after = index;
460 continue;
461 }
462 index += 1;
463 }
464 if symbols.is_empty() {
465 return (Vec::new(), src.to_string());
466 }
467 (symbols, chars[after..].iter().collect())
468 }
469
470 fn pitch_name(
473 &self,
474 src: &str,
475 forced_key: Option<&KeySignature>,
476 ) -> Result<(Option<String>, Option<bool>)> {
477 let chars: Vec<char> = src.chars().collect();
478 let mut text: String = if chars.len() > 1 && matches!(chars[0], 'u' | 'T') {
479 chars[1..].iter().collect()
480 } else {
481 src.to_string()
482 };
483 text = text.replace('T', "");
484 let name = text
485 .chars()
486 .find(|c| matches!(c, 'a'..='g' | 'A'..='G' | 'z'))
487 .ok_or_else(|| abc_error(format!("cannot find any pitch information in: {text:?}")))?;
488 if name == 'z' {
489 return Ok((None, None));
490 }
491 let key = forced_key.or(self.key.as_ref());
492 let count = |wanted: char| text.chars().filter(|c| *c == wanted).count();
493 let mut octave: i32 = if name.is_lowercase() { 5 } else { 4 };
494 octave -= count(',') as i32;
495 octave += count('\'') as i32;
496 let marks = |source: &str| -> String {
497 let count = |wanted: char| source.chars().filter(|c| *c == wanted).count();
498 format!(
499 "{}{}{}",
500 "-".repeat(count('_')),
501 "#".repeat(count('^')),
502 "n".repeat(count('='))
503 )
504 };
505 let written = marks(&text);
506 let carried = marks(&self.carried_accidental);
507 if !carried.is_empty() && !written.is_empty() {
508 return Err(abc_error("Carried accidentals not rendered moot."));
509 }
510 let mut name = name.to_uppercase().to_string();
511 let display = if !carried.is_empty() {
512 None
513 } else if !written.is_empty() {
514 Some(true)
515 } else {
516 match key {
517 None => None,
518 Some(key) => {
519 if let Ok(altered) = key.altered_pitches()
521 && let Some(pitch) = altered
522 .iter()
523 .find(|pitch| pitch.step().as_char().to_string() == name)
524 {
525 name = pitch.name();
526 }
527 Some(false)
528 }
529 }
530 };
531 let accidental = if carried.is_empty() { written } else { carried };
532 Ok((Some(format!("{name}{accidental}{octave}")), display))
533 }
534
535 fn read_quarter_length(
537 &self,
538 src: &str,
539 forced_default: Option<FloatType>,
540 ) -> Result<FloatType> {
541 let default = forced_default
542 .or(self.default_quarter_length)
543 .ok_or_else(|| {
544 abc_error("cannot calculate quarter length without a default quarter length")
545 })?;
546 let number: String = src
547 .chars()
548 .filter(|c| c.is_ascii_digit() || *c == '/')
549 .collect();
550 let whole = |text: &str| -> Result<FloatType> {
551 text.trim()
552 .parse::<FloatType>()
553 .map_err(|_| abc_error(format!("cannot read the length in {src:?}")))
554 };
555 let mut length = match number.as_str() {
556 "" => default,
557 "/" => default * 0.5,
558 "//" => default * 0.25,
559 "///" => default * 0.125,
560 text if text.starts_with('/') => {
561 op_frac(default / whole(text.split('/').nth(1).unwrap_or(""))?)
562 }
563 text if text.ends_with('/') => {
564 default * whole(text.split('/').next().unwrap_or(""))? / 2.0
565 }
566 text if text.matches('/').count() == 2 => 1.0,
567 text if text.contains('/') => {
568 let (numerator, denominator) = text.split_once('/').unwrap_or(("1", "1"));
569 op_frac(default * whole(numerator)? / whole(denominator)?)
570 }
571 text => default * whole(text)?,
572 };
573 if let Some((symbol, left)) = &self.broken_rhythm {
574 let (first, second) = match symbol.as_str() {
575 ">" => (1.5, 0.5),
576 "<" => (0.5, 1.5),
577 ">>" => (1.75, 0.25),
578 "<<" => (0.25, 1.75),
579 ">>>" => (1.875, 0.125),
580 "<<<" => (0.125, 1.875),
581 _ => (1.0, 1.0),
582 };
583 length *= if *left { first } else { second };
584 }
585 Ok(length)
586 }
587
588 fn parse(
590 &mut self,
591 forced_default: Option<FloatType>,
592 forced_key: Option<&KeySignature>,
593 ) -> Result<()> {
594 let (symbols, rest) = Self::split_chord_symbols(&self.src);
595 self.chord_symbols = symbols;
596 if self.is_chord {
597 let chars: Vec<char> = rest.chars().collect();
598 let close = chars.iter().position(|c| *c == ']').ok_or_else(|| {
599 abc_error(format!(
600 "Bad chord indicator: {}: no closing bracket found.",
601 self.src
602 ))
603 })?;
604 let outer: String = chars[close + 1..].iter().collect();
605 let inner: String = chars[1..close].iter().collect();
606 let outer_length = self.read_quarter_length(&outer, Some(1.0))?;
607 let key = forced_key.cloned().or_else(|| self.key.clone());
608 let mut handler = Handler::new(DEFAULT_VERSION);
609 handler.tokenize(&inner)?;
610 let mut inner_length = 0.0;
611 for token in handler.tokens {
612 let Token::Note(mut note) = token else {
613 continue;
614 };
615 note.parse(self.default_quarter_length, key.as_ref())?;
616 if note.is_rest {
617 continue;
618 }
619 if inner_length == 0.0 {
620 inner_length = note.quarter_length;
621 }
622 self.sub_tokens.push(*note);
623 }
624 self.quarter_length = outer_length * inner_length;
625 return Ok(());
626 }
627 let (name, display) = match self.pitch_name(&rest, forced_key) {
629 Ok(read) => read,
630 Err(Error::Abc(message)) if message.starts_with("cannot find any pitch") => {
631 (Some("C".to_string()), Some(false))
632 }
633 Err(error) => return Err(error),
634 };
635 self.is_rest = name.is_none();
636 self.pitch_name = name;
637 self.accidental_display = display;
638 self.quarter_length = self.read_quarter_length(&rest, forced_default)?;
639 Ok(())
640 }
641}
642
643#[derive(Clone, Debug)]
647struct Spanning {
648 kind: SpannerKind,
649 uids: Vec<usize>,
650}
651
652#[derive(Clone, Debug)]
654struct Handler {
655 version: (u32, u32, u32),
656 directives: Vec<(String, String)>,
657 tokens: Vec<Token>,
658}
659
660impl Handler {
661 fn new(version: (u32, u32, u32)) -> Self {
662 Self {
663 version,
664 directives: Vec::new(),
665 tokens: Vec::new(),
666 }
667 }
668
669 fn accidental_propagation(&self) -> &str {
671 if self.version < (2, 0, 0) {
672 return "not";
673 }
674 self.directives
675 .iter()
676 .rev()
677 .find(|(key, _)| key == "propagate-accidentals")
678 .map_or("pitch", |(_, value)| value.as_str())
679 }
680
681 fn read_version(&mut self, text: &str) {
684 let head: String = text.chars().take(100).collect();
685 let Some(at) = head.find("%abc-") else {
686 return;
687 };
688 let rest = &head[at + 5..];
689 let mut numbers = rest
690 .split(|c: char| !c.is_ascii_digit())
691 .take(3)
692 .map(|piece| piece.parse::<u32>().ok());
693 let (Some(Some(major)), Some(Some(minor))) = (numbers.next(), numbers.next()) else {
695 return;
696 };
697 if !rest[major.to_string().len()..].starts_with('.') {
698 return;
699 }
700 let patch = numbers.next().flatten().unwrap_or(0);
701 self.version = (major, minor, patch);
702 }
703
704 fn bar_tokens(text: &str) -> Vec<Bar> {
706 let pair = match text {
707 "::" => Some((":|", "|:")),
708 "|1" => Some(("|", "[1")),
709 "|2" => Some(("|", "[2")),
710 ":|1" => Some((":|", "[1")),
711 ":|2" => Some((":|", "[2")),
712 _ => None,
713 };
714 match pair {
715 Some((first, second)) => vec![Bar::new(first), Bar::new(second)],
716 None => vec![Bar::new(text)],
717 }
718 }
719
720 fn tokenize(&mut self, source: &str) -> Result<()> {
722 let src: Vec<char> = source.chars().collect();
723 let len = src.len();
724 let at = |index: usize| src.get(index).copied();
725 let slice =
726 |from: usize, to: usize| -> String { src[from.min(len)..to.min(len)].iter().collect() };
727 let next_line_break =
728 |from: usize| -> usize { (from + 1..len).find(|j| src[*j] == '\n').unwrap_or(len) };
729 const DECORATIONS: &str = ".~^=_HLMOPSTuv";
730 const ACCIDENTALS: &str = "^=_";
731
732 let mut active_chord_symbol = String::new();
733 let mut accidentalized: Vec<(String, String)> = Vec::new();
734 let mut accidental = String::new();
735 let mut abc_pitch = String::new();
736 let mut pos = 0usize;
737 while pos < len {
738 let c = src[pos];
739 let next = at(pos + 1);
740 let next_next = at(pos + 2);
741 let mut skip = 0usize;
743
744 if c == '%' {
745 let end = next_line_break(pos);
746 let line = slice(pos, end);
747 if let Some(directive) = line.strip_prefix("%%") {
748 let key: String = directive
749 .chars()
750 .take_while(|c| c.is_ascii_lowercase() || *c == '-')
751 .collect();
752 let after = &directive[key.len()..];
753 if !key.is_empty()
754 && after.starts_with(char::is_whitespace)
755 && let Some(value) = after.split_whitespace().next()
756 {
757 self.directives.push((key, value.to_string()));
758 }
759 }
760 pos = end;
761 continue;
762 }
763
764 let starts_metadata = next == Some(':')
765 && next_next.is_some()
766 && next_next != Some('|')
767 && (c == 'w' || (c.is_alphabetic() && c.is_uppercase()));
768 if starts_metadata {
769 let end = next_line_break(pos);
770 self.tokens.push(metadata_token(slice(pos, end).trim()));
771 pos = end;
772 continue;
773 }
774
775 if !c.is_whitespace() && !c.is_alphanumeric() && c != '~' && c != '(' {
776 let mut matched = None;
777 for (text, _) in BARS {
778 let wanted: Vec<char> = text.chars().collect();
779 let fits = match wanted.len() {
780 3 => next.is_some() && next_next.is_some() && slice(pos, pos + 3) == text,
781 2 => next.is_some() && slice(pos, pos + 2) == text,
782 _ => c == wanted[0],
783 };
784 if fits {
785 matched = Some(wanted.len());
786 break;
787 }
788 }
789 if let Some(length) = matched {
790 accidentalized.clear();
791 accidental.clear();
792 for bar in Self::bar_tokens(&slice(pos, pos + length)) {
793 self.tokens.push(Token::Bar(bar));
794 }
795 pos += length;
796 continue;
797 }
798 }
799
800 if c == '(' && next.is_some_and(|c| c.is_ascii_digit()) {
801 let mut j = pos + 2;
802 if j >= len {
803 return Err(abc_error(format!(
804 "bad index value {j}, max is {}",
805 len - 1
806 )));
807 }
808 if at(j) == Some(':') {
809 j += 1;
810 if at(j).is_some_and(|c| c.is_ascii_digit()) {
811 j += 1;
812 }
813 if at(j) == Some(':') {
814 j += 1;
815 if at(j).is_some_and(|c| c.is_ascii_digit()) {
816 j += 1;
817 }
818 }
819 }
820 self.tokens.push(Token::Tuplet { src: slice(pos, j) });
821 pos = j;
822 continue;
823 }
824
825 if c == '<' || c == '>' {
826 let mut j = pos + 1;
827 while j + 1 < len && matches!(src[j], '<' | '>') {
828 j += 1;
829 }
830 self.tokens
831 .push(Token::BrokenRhythm(slice(pos, j).trim().to_string()));
832 pos = j;
833 continue;
834 }
835
836 if c == '!' {
837 let mut j = pos + 1;
838 while j < pos + 20 && j < len {
839 if src[j] == '!' {
840 match slice(pos, j + 1).as_str() {
841 "!crescendo(!" => self
842 .tokens
843 .push(Token::SpannerStart(SpannerKind::Crescendo, None)),
844 "!diminuendo(!" => self
845 .tokens
846 .push(Token::SpannerStart(SpannerKind::Diminuendo, None)),
847 "!crescendo)!" | "!diminuendo)!" => self.tokens.push(Token::ParenStop),
848 _ => {}
849 }
850 skip = j - pos;
851 break;
852 }
853 j += 1;
854 }
855 pos += skip + 1;
856 continue;
857 }
858
859 if c == '(' && next.is_some() {
860 self.tokens
861 .push(Token::SpannerStart(SpannerKind::Slur, None));
862 pos += 1;
863 continue;
864 }
865 let simple = match c {
866 ')' => Some(Token::ParenStop),
867 '-' => Some(Token::Tie),
868 _ => None,
869 };
870 if let Some(token) = simple {
871 self.tokens.push(token);
872 pos += 1;
873 continue;
874 }
875
876 if c == '"' {
877 let mut j = pos + 1;
878 while j + 1 < len && src[j] != '"' {
879 j += 1;
880 }
881 j += 1;
882 active_chord_symbol.push_str(&slice(pos, j));
883 pos = j.max(pos + 1);
884 continue;
885 }
886
887 if c == '[' {
888 let mut j = pos + 1;
889 while j + 1 < len && src[j] != ']' {
890 j += 1;
891 }
892 j += 1;
893 while j < len && (src[j].is_ascii_digit() || src[j] == '/') {
894 j += 1;
895 }
896 let collected = format!("{}{}", active_chord_symbol, slice(pos, j));
897 active_chord_symbol.clear();
898 self.tokens
899 .push(Token::Note(Box::new(AbcNote::new(&collected, "", true))));
900 pos = j.max(pos + 1);
901 continue;
902 }
903
904 let mark = match c {
905 '.' => Some(Token::Staccato),
906 'u' => Some(Token::Upbow),
907 '{' => Some(Token::GraceStart),
908 '}' => Some(Token::GraceStop),
909 'v' => Some(Token::Downbow),
910 'K' => Some(Token::Accent),
911 'k' => Some(Token::Straccent),
912 'M' => Some(Token::Tenuto),
913 _ => None,
914 };
915 if let Some(token) = mark {
916 self.tokens.push(token);
917 pos += 1;
918 continue;
919 }
920
921 if c.is_alphabetic() || "~^=_".contains(c) {
922 let mut found = c.is_alphabetic() && !DECORATIONS.contains(c);
923 if found {
924 abc_pitch = c.to_string();
925 }
926 if ACCIDENTALS.contains(c) {
927 accidental = c.to_string();
928 }
929 let mut j = pos + 1;
930 while j < len {
931 let here = src[j];
932 if !found && DECORATIONS.contains(here) {
933 j += 1;
934 match at(j) {
937 Some(after) if ACCIDENTALS.contains(after) => accidental.push(after),
938 Some(_) => {}
939 None => {
940 return Err(abc_error("a decoration ends the text"));
941 }
942 }
943 } else if !found && here.is_alphabetic() && !"~wuvhHLTSN".contains(here) {
944 found = true;
945 abc_pitch = here.to_string();
946 j += 1;
947 } else if here.is_ascii_digit() || ",/'".contains(here) {
948 if here == ',' || here == '\'' {
949 abc_pitch.push(here);
950 }
951 j += 1;
952 } else {
953 break;
954 }
955 }
956 let collected = format!("{}{}", active_chord_symbol, slice(pos, j));
957 active_chord_symbol.clear();
958
959 const PASSED: [&str; 38] = [
960 "w", "u", "v", "v.", "h", "H", "vk", "uk", "U", "~", ".", "=", "V", "v.", "S",
961 "s", "i", "I", "ui", "u.", "Q", "Hy", "Hx", "r", "m", "M", "n", "N", "o", "O",
962 "P", "l", "L", "R", "y", "T", "t", "x",
963 ];
964 let chars: Vec<char> = collected.chars().collect();
965 let last = chars.last().copied().unwrap_or(' ');
966 let passed = PASSED.contains(&collected.as_str())
967 || collected == "Z"
968 || (collected.starts_with('"')
969 && ("uvkKQ.yTwhx".contains(last) || collected.ends_with("v.")))
970 || collected.starts_with('x')
971 || collected.starts_with('H')
972 || collected.starts_with('Z')
973 || (chars.len() > 1 && chars[0] == '=' && chars[1].is_ascii_digit());
974 if !passed {
975 let mut carried = String::new();
976 if !abc_pitch.is_empty() {
977 let class: String = abc_pitch
978 .chars()
979 .take(1)
980 .flat_map(char::to_uppercase)
981 .collect();
982 let key = match self.accidental_propagation() {
983 "octave" => Some(abc_pitch.clone()),
984 "pitch" => Some(class),
985 _ => None,
986 };
987 if !accidental.is_empty() {
988 if let Some(key) = key {
989 accidentalized.retain(|(known, _)| *known != key);
990 accidentalized.push((key, accidental.clone()));
991 }
992 accidental.clear();
993 } else if let Some(key) = key
994 && let Some((_, held)) =
995 accidentalized.iter().find(|(known, _)| *known == key)
996 {
997 carried = held.clone();
998 }
999 }
1000 self.tokens.push(Token::Note(Box::new(AbcNote::new(
1001 &collected, &carried, false,
1002 ))));
1003 }
1004 pos = j.max(pos + 1);
1005 continue;
1006 }
1007
1008 pos += 1;
1009 }
1010 Ok(())
1011 }
1012
1013 fn process(&mut self) -> Result<Vec<Spanning>> {
1016 let mut spanners: Vec<Spanning> = Vec::new();
1017 let mut active_spanners: Vec<usize> = Vec::new();
1018 let mut active_parens: Vec<&'static str> = Vec::new();
1019 let mut default_length: Option<FloatType> = None;
1020 let mut key: Option<KeySignature> = None;
1021 let mut meter: Option<TimeSignature> = None;
1022 let mut tuplet: Option<(Tuplet, i32)> = None;
1024 let mut tie_waiting = false;
1025 let mut marks: Vec<&'static str> = Vec::new();
1026 let mut in_grace = false;
1027 let mut last_note: Option<usize> = None;
1028
1029 for index in 0..self.tokens.len() {
1030 let previous_is_note = index > 0 && self.tokens[index - 1].is_note();
1031 let next_is_note = self.tokens.get(index + 1).is_some_and(Token::is_note);
1032 match self.tokens[index].clone() {
1033 Token::Metadata { tag, data } => {
1034 if tag == "M" {
1035 meter = meter_of(&data)?;
1036 }
1037 if tag == "L" || (tag == "M" && default_length.is_none()) {
1038 default_length = Some(default_quarter_length(&tag, &data)?);
1039 } else if tag == "K" {
1040 let (sharps, _) = key_parameters(&data)?;
1041 key = Some(KeySignature::new(sharps));
1042 }
1043 if tag == "X" {
1044 active_parens.clear();
1045 active_spanners.clear();
1046 }
1047 }
1048 Token::BrokenRhythm(symbol) => {
1049 if previous_is_note && next_is_note {
1050 if let Token::Note(note) = &mut self.tokens[index - 1] {
1051 note.broken_rhythm = Some((symbol.clone(), true));
1052 }
1053 if let Token::Note(note) = &mut self.tokens[index + 1] {
1054 note.broken_rhythm = Some((symbol, false));
1055 }
1056 }
1057 }
1058 Token::Tuplet { src } => {
1059 let (made, count) = tuplet_of(&src, meter.as_ref())?;
1060 tuplet = Some((made, count));
1061 active_parens.push("Tuplet");
1062 }
1063 Token::SpannerStart(kind, _) => {
1064 spanners.push(Spanning {
1065 kind,
1066 uids: Vec::new(),
1067 });
1068 let made = spanners.len() - 1;
1069 self.tokens[index] = Token::SpannerStart(kind, Some(made));
1070 active_spanners.push(made);
1071 active_parens.push(match kind {
1072 SpannerKind::Crescendo => "Crescendo",
1073 SpannerKind::Diminuendo => "Diminuendo",
1074 _ => "Slur",
1075 });
1076 }
1077 Token::ParenStop => {
1078 if let Some(closed) = active_parens.pop()
1079 && closed != "Tuplet"
1080 {
1081 active_spanners.pop();
1082 }
1083 }
1084 Token::Tie => {
1085 if let Some(last) = last_note
1086 && let Token::Note(note) = &mut self.tokens[last]
1087 {
1088 note.tie = Some(if note.tie == Some(TieType::Stop) {
1089 TieType::Continue
1090 } else {
1091 TieType::Start
1092 });
1093 }
1094 tie_waiting = true;
1095 }
1096 Token::Staccato => marks.push("staccato"),
1097 Token::Upbow => marks.push("upbow"),
1098 Token::Downbow => marks.push("downbow"),
1099 Token::Accent => marks.push("accent"),
1100 Token::Straccent => marks.push("strongaccent"),
1101 Token::Tenuto => marks.push("tenuto"),
1102 Token::GraceStart => in_grace = true,
1103 Token::GraceStop => in_grace = false,
1104 Token::Bar(_) => {}
1105 Token::Note(_) => {
1106 let Some(default_length) = default_length else {
1107 return Err(abc_error(
1108 "no active default note length provided for note processing.",
1109 ));
1110 };
1111 let Token::Note(note) = &mut self.tokens[index] else {
1112 continue;
1113 };
1114 note.default_quarter_length = Some(default_length);
1115 note.key = key.clone();
1116 note.spanners = active_spanners.clone();
1117 if std::mem::take(&mut tie_waiting) {
1118 note.tie = Some(TieType::Stop);
1119 }
1120 for mark in [
1122 "staccato",
1123 "upbow",
1124 "downbow",
1125 "accent",
1126 "strongaccent",
1127 "tenuto",
1128 ] {
1129 if marks.contains(&mark) {
1130 note.articulations.push(mark);
1131 }
1132 }
1133 marks.clear();
1134 if in_grace {
1135 note.in_grace = true;
1136 }
1137 match &mut tuplet {
1138 None => {}
1139 Some((_, 0)) => tuplet = None,
1140 Some((made, count)) => {
1141 *count -= 1;
1142 note.tuplet = Some(*made);
1143 }
1144 }
1145 last_note = Some(index);
1146 }
1147 }
1148 }
1149 for token in &mut self.tokens {
1150 if let Token::Note(note) = token {
1151 note.parse(None, None)?;
1152 }
1153 }
1154 Ok(spanners)
1155 }
1156
1157 fn defines_reference_numbers(&self) -> bool {
1159 self.tokens
1160 .iter()
1161 .filter(|token| token.metadata().is_some_and(|(tag, _)| tag == "X"))
1162 .count()
1163 > 1
1164 }
1165
1166 fn split_by_reference_number(&self) -> Vec<(IntegerType, Handler)> {
1168 let mut before: Vec<Token> = Vec::new();
1169 let mut tunes: Vec<(IntegerType, Vec<Token>)> = Vec::new();
1170 for token in &self.tokens {
1171 if let Some(("X", data)) = token.metadata() {
1172 let number = data.trim().parse::<IntegerType>().unwrap_or(0);
1173 tunes.retain(|(known, _)| *known != number);
1174 tunes.push((number, Vec::new()));
1175 }
1176 match tunes.last_mut() {
1177 Some((_, tokens)) => tokens.push(token.clone()),
1178 None => before.push(token.clone()),
1179 }
1180 }
1181 tunes.sort_by_key(|(number, _)| *number);
1182 tunes
1183 .into_iter()
1184 .map(|(number, tokens)| {
1185 let mut handler = Handler::new(self.version);
1186 handler.tokens = before.iter().cloned().chain(tokens).collect();
1187 (number, handler)
1188 })
1189 .collect()
1190 }
1191
1192 fn defines_measures(&self) -> bool {
1194 self.tokens
1195 .iter()
1196 .filter(|token| matches!(token, Token::Bar(bar) if bar.is_regular()))
1197 .count()
1198 >= 2
1199 }
1200
1201 fn has_notes(tokens: &[Token]) -> bool {
1202 tokens.iter().any(Token::is_note)
1203 }
1204
1205 fn split_by_voice(&self) -> Vec<Vec<Token>> {
1208 let positions: Vec<usize> = self
1209 .tokens
1210 .iter()
1211 .enumerate()
1212 .filter(|(_, token)| {
1213 token.metadata().is_some_and(|(tag, data)| {
1214 tag == "V" && data.chars().next().is_some_and(|c| c.is_ascii_digit())
1215 })
1216 })
1217 .map(|(index, _)| index)
1218 .collect();
1219 if positions.len() <= 1 {
1220 return vec![self.tokens.clone()];
1221 }
1222 let mut pieces = vec![self.tokens[..positions[0]].to_vec()];
1223 for pair in positions.windows(2) {
1224 pieces.push(self.tokens[pair[0]..pair[1]].to_vec());
1225 }
1226 pieces.push(self.tokens[positions[positions.len() - 1]..].to_vec());
1227 pieces
1228 }
1229}
1230
1231fn tuplet_of(src: &str, meter: Option<&TimeSignature>) -> Result<(Tuplet, i32)> {
1234 let normal_switch = match meter {
1235 Some(meter) if meter.beat_division_count() == 3 => 3,
1236 _ => 2,
1237 };
1238 let pieces: Vec<&str> = src.trim().split(':').collect();
1239 let (actual, normal) = match pieces[0] {
1240 "(1" => (1, 1),
1241 "(2" => (2, 3),
1242 "(3" => (3, 2),
1243 "(4" => (4, 3),
1244 "(5" => (5, normal_switch),
1245 "(6" => (6, 2),
1246 "(7" => (7, normal_switch),
1247 "(8" => (8, 3),
1248 "(9" => (9, normal_switch),
1249 other => {
1250 return Err(abc_error(format!(
1251 "cannot handle tuplet of form: {other:?}"
1252 )));
1253 }
1254 };
1255 let read = |piece: Option<&&str>| piece.and_then(|piece| piece.parse::<u32>().ok());
1256 let normal = read(pieces.get(1)).unwrap_or(normal);
1257 let count = read(pieces.get(2)).unwrap_or(actual);
1258 Ok((Tuplet::ratio(actual, normal), count as i32))
1259}
1260
1261#[derive(Clone, Debug, Default)]
1264struct BarHandler {
1265 tokens: Vec<Token>,
1266 left: Option<Bar>,
1267 right: Option<Bar>,
1268}
1269
1270impl BarHandler {
1271 fn joined(&self, other: &BarHandler) -> BarHandler {
1273 BarHandler {
1274 tokens: self
1275 .tokens
1276 .iter()
1277 .cloned()
1278 .chain(other.tokens.iter().cloned())
1279 .collect(),
1280 left: other.left.clone().or_else(|| self.left.clone()),
1281 right: other.right.clone().or_else(|| self.right.clone()),
1282 }
1283 }
1284}
1285
1286fn split_by_measure(tokens: &[Token]) -> Vec<BarHandler> {
1288 let mut positions: Vec<usize> = Vec::new();
1290 for (index, token) in tokens.iter().enumerate() {
1291 let note_follows = tokens.get(index + 1).is_some_and(Token::is_note);
1292 if matches!(token, Token::Bar(_)) || (token.metadata().is_some() && note_follows) {
1293 positions.push(index);
1294 }
1295 }
1296 if positions.is_empty() || tokens.is_empty() {
1297 return Vec::new();
1298 }
1299 let last_valid = tokens.len() - 1;
1300 let mut pairs: Vec<(usize, usize)> = vec![(0, positions[0])];
1301 let mut start = positions[0];
1302 for end in positions.iter().skip(1).copied() {
1303 if end == start + 1 {
1305 start = end;
1306 continue;
1307 }
1308 pairs.push((start, end));
1309 start = end;
1310 }
1311 if start != last_valid {
1312 pairs.push((start, last_valid));
1313 }
1314
1315 let mut handlers = Vec::new();
1316 for (x, y) in pairs {
1317 let mut handler = BarHandler::default();
1318 let mut from = x;
1319 let mut to = y;
1320 match &tokens[x] {
1321 Token::Bar(bar) => {
1322 if !(bar.repeat && bar.form == "end") {
1324 handler.left = Some(bar.clone());
1325 }
1326 from = x + 1;
1327 }
1328 Token::Metadata { .. } if x != 0 => from = x + 1,
1329 _ => {}
1330 }
1331 match &tokens[y] {
1332 Token::Bar(bar) => {
1333 if !(bar.repeat && bar.form == "start") {
1334 handler.right = Some(bar.clone());
1335 }
1336 to = y.wrapping_sub(1);
1337 }
1338 Token::Metadata { .. } => {}
1339 token => {
1340 if !(token.is_note() && y == tokens.len() - 1) {
1341 to = y.wrapping_sub(1);
1342 }
1343 }
1344 }
1345 if to == usize::MAX || from > to {
1346 continue;
1347 }
1348 handler.tokens = tokens[from..=to].to_vec();
1349 if handler.tokens.is_empty() {
1350 continue;
1351 }
1352 handlers.push(handler);
1353 }
1354 handlers
1355}
1356
1357fn merge_leading_metadata(handlers: Vec<BarHandler>) -> Vec<BarHandler> {
1360 let sounding = handlers
1361 .iter()
1362 .filter(|handler| Handler::has_notes(&handler.tokens))
1363 .count();
1364 if sounding <= 1 {
1365 let mut whole = BarHandler::default();
1366 for handler in &handlers {
1367 whole = whole.joined(handler);
1368 }
1369 return vec![whole];
1370 }
1371 let mut merged = Vec::new();
1372 let mut index = 0;
1373 while index < handlers.len() {
1374 let silent = !Handler::has_notes(&handlers[index].tokens);
1375 if silent && index != handlers.len() - 1 {
1376 merged.push(handlers[index].joined(&handlers[index + 1]));
1377 index += 2;
1378 } else {
1379 merged.push(handlers[index].clone());
1380 index += 1;
1381 }
1382 }
1383 merged
1384}
1385
1386#[derive(Clone, Debug)]
1390struct Item {
1391 offset: FloatType,
1392 seq: usize,
1393 uid: Option<usize>,
1394 element: StreamElement,
1395}
1396
1397#[derive(Clone, Debug, Default)]
1400struct Line {
1401 items: Vec<Item>,
1402 end: FloatType,
1403 seq: usize,
1404}
1405
1406impl Line {
1407 fn append(&mut self, element: impl Into<StreamElement>, uid: Option<usize>) {
1409 let element = element.into();
1410 let length = element.quarter_length();
1411 self.items.push(Item {
1412 offset: self.end,
1413 seq: self.seq,
1414 uid,
1415 element,
1416 });
1417 self.seq += 1;
1418 self.end = op_frac(self.end + length);
1419 }
1420
1421 fn set_at_start(&mut self, element: StreamElement) {
1424 let same = |held: &StreamElement| {
1425 matches!(
1426 (held, &element),
1427 (
1428 StreamElement::TimeSignature(_),
1429 StreamElement::TimeSignature(_)
1430 ) | (StreamElement::Clef(_), StreamElement::Clef(_))
1431 | (
1432 StreamElement::KeySignature(_) | StreamElement::Key(_),
1433 StreamElement::KeySignature(_) | StreamElement::Key(_)
1434 )
1435 )
1436 };
1437 self.items.retain(|item| !same(&item.element));
1438 self.items.push(Item {
1439 offset: 0.0,
1440 seq: self.seq,
1441 uid: None,
1442 element,
1443 });
1444 self.seq += 1;
1445 }
1446
1447 fn meter(&self) -> Option<&TimeSignature> {
1448 self.items.iter().find_map(|item| match &item.element {
1449 StreamElement::TimeSignature(meter) => Some(meter),
1450 _ => None,
1451 })
1452 }
1453
1454 fn sorted(&self) -> Vec<&Item> {
1456 let mut sorted: Vec<&Item> = self.items.iter().collect();
1457 sorted.sort_by(|left, right| {
1458 let grace = |item: &Item| item.element.duration().is_some_and(Duration::is_grace);
1459 left.offset
1460 .total_cmp(&right.offset)
1461 .then(class_sort_order(&left.element).cmp(&class_sort_order(&right.element)))
1462 .then(grace(right).cmp(&grace(left)))
1463 .then(left.seq.cmp(&right.seq))
1464 });
1465 sorted
1466 }
1467}
1468
1469pub(super) fn class_sort_order(element: &StreamElement) -> i32 {
1471 match element {
1472 StreamElement::TextExpression(_) => -30,
1473 StreamElement::Instrument(_) => -25,
1474 StreamElement::Stream(_) => -20,
1475 StreamElement::Clef(_) => 0,
1476 StreamElement::MetronomeMark(_) | StreamElement::TempoText(_) => 1,
1477 StreamElement::KeySignature(_) | StreamElement::Key(_) => 2,
1478 StreamElement::TimeSignature(_) => 4,
1479 StreamElement::Dynamic(_) => 10,
1480 StreamElement::ChordSymbol(_) => 19,
1481 _ => 20,
1482 }
1483}
1484
1485#[derive(Clone, Debug, Default)]
1486struct MeasureIr {
1487 line: Line,
1488 number: IntegerType,
1489 left: Option<Barline>,
1490 right: Option<Barline>,
1491 padding_left: FloatType,
1492}
1493
1494#[derive(Clone, Debug)]
1496struct Bracket {
1497 number: u32,
1498 measures: Vec<usize>,
1499 complete: bool,
1500}
1501
1502struct PartReader {
1504 spanners: Vec<Spanning>,
1505 next_uid: usize,
1506 lyric_targets: Vec<(Option<usize>, usize)>,
1508 post_transposition: IntegerType,
1509}
1510
1511impl PartReader {
1512 fn uid(&mut self) -> usize {
1513 self.next_uid += 1;
1514 self.next_uid
1515 }
1516}
1517
1518fn add_lyrics(data: &str, targets: &mut [&mut StreamElement]) -> Result<()> {
1521 let mut at = 0usize;
1522 for word in data.split_whitespace() {
1523 if word == "*" || word == "-" {
1524 at += 1;
1525 continue;
1526 }
1527 let syllables: Vec<&str> = word.split('-').collect();
1528 for (index, syllable) in syllables.iter().enumerate() {
1529 if syllable.is_empty() {
1530 at += 1;
1531 continue;
1532 }
1533 let Some(target) = targets.get_mut(at) else {
1534 return Ok(());
1535 };
1536 let text = format!(
1537 "{}{syllable}{}",
1538 if index > 0 { "-" } else { "" },
1539 if index + 1 < syllables.len() { "-" } else { "" }
1540 );
1541 match target {
1542 StreamElement::Note(note) => note.add_lyric(&text, None, false)?,
1543 StreamElement::Chord(chord) => chord.add_lyric(&text, None, false)?,
1544 _ => {}
1545 }
1546 at += 1;
1547 }
1548 }
1549 Ok(())
1550}
1551
1552type Placed = (StreamElement, Option<usize>);
1554
1555fn note_elements(
1558 token: &AbcNote,
1559 reader: &mut PartReader,
1560) -> Result<(Option<ChordSymbol>, Option<Placed>)> {
1561 let mut symbol = None;
1562 if let Some(first) = token.chord_symbols.first() {
1563 let mut name: String = first.replace('"', "").trim().to_string();
1564 name = name.replace(['(', ')'], "");
1565 let chars: Vec<char> = name.chars().collect();
1567 let mut cleaned = String::new();
1568 for (index, character) in chars.iter().enumerate() {
1569 let after_letter = index > 0 && matches!(chars[index - 1], 'A'..='G' | 'a'..='g');
1570 cleaned.push(if *character == 'b' && after_letter {
1571 '-'
1572 } else {
1573 *character
1574 });
1575 }
1576 if matches!(cleaned.as_str(), "NC" | "N.C." | "No Chord" | "None") {
1577 symbol = Some(ChordSymbol::no_chord(Some(cleaned)));
1578 } else if cleaned.starts_with('>') {
1579 return Ok((None, None));
1580 } else if let Ok(read) = ChordSymbol::parse_music21(cleaned) {
1581 symbol = Some(read);
1582 }
1583 }
1584
1585 let with_tuplet = |duration: &mut Duration, tuplet: Option<Tuplet>| {
1586 if let Some(mut tuplet) = tuplet {
1587 if tuplet.duration_normal().is_none()
1588 && let Some((kind, dots)) = duration.type_and_dots()
1589 {
1590 tuplet.set_duration_type(kind, dots);
1591 }
1592 duration.append_tuplet(tuplet);
1593 }
1594 };
1595
1596 if token.is_chord {
1597 if token.sub_tokens.is_empty() {
1598 return Ok((symbol, None));
1599 }
1600 let mut members = Vec::new();
1601 for sub in &token.sub_tokens {
1602 let Some(name) = &sub.pitch_name else {
1603 continue;
1604 };
1605 let mut pitch = Pitch::from_name(name)?;
1606 if let Some(accidental) = pitch.written_accidental_mut() {
1607 accidental.set_display_status(sub.accidental_display);
1608 }
1609 members.push(Note::from_pitch(pitch));
1610 }
1611 let mut duration = Duration::new(token.quarter_length)?;
1612 with_tuplet(&mut duration, token.tuplet);
1613 let chord = Chord::new(members)?.with_duration(duration);
1614 let uid = reader.uid();
1615 return Ok((symbol, Some((chord.into(), Some(uid)))));
1616 }
1617
1618 let mut duration = Duration::new(token.quarter_length)?;
1619 with_tuplet(&mut duration, token.tuplet);
1620 if token.is_rest {
1621 let uid = reader.uid();
1622 for spanner in &token.spanners {
1623 reader.spanners[*spanner].uids.push(uid);
1624 }
1625 let duration = if token.in_grace {
1626 grace_of(&duration)
1627 } else {
1628 duration
1629 };
1630 let placed = if token.in_grace { reader.uid() } else { uid };
1632 let mut rest = Rest::new(duration);
1633 rest.set_tie(tie_of(token.tie));
1634 *rest.articulations_mut() = articulations_of(&token.articulations);
1635 return Ok((symbol, Some((rest.into(), Some(placed)))));
1636 }
1637 let name = token
1638 .pitch_name
1639 .as_deref()
1640 .ok_or_else(|| abc_error("a note with no pitch"))?;
1641 let mut pitch = Pitch::from_name(name)?;
1642 if let Some(accidental) = pitch.written_accidental_mut() {
1643 accidental.set_display_status(token.accidental_display);
1644 }
1645 let mut note = Note::from_pitch(pitch);
1646 note.set_tie(tie_of(token.tie));
1647 let uid = reader.uid();
1648 for spanner in &token.spanners {
1649 if !reader.spanners[*spanner].uids.contains(&uid) {
1650 reader.spanners[*spanner].uids.push(uid);
1651 }
1652 }
1653 let placed = if token.in_grace {
1656 duration = grace_of(&duration);
1657 reader.uid()
1658 } else {
1659 uid
1660 };
1661 note.set_duration(duration);
1662 *note.articulations_mut() = articulations_of(&token.articulations);
1663 Ok((symbol, Some((note.into(), Some(placed)))))
1664}
1665
1666fn tie_of(tie: Option<TieType>) -> Option<Tie> {
1668 match tie? {
1669 tie_type @ (TieType::Start | TieType::Continue) => {
1670 let mut tie = Tie::new(tie_type);
1671 tie.set_style(TieStyle::Normal);
1672 Some(tie)
1673 }
1674 tie_type => Some(Tie::new(tie_type)),
1675 }
1676}
1677
1678fn articulations_of(marks: &[&'static str]) -> Vec<Articulation> {
1681 marks
1682 .iter()
1683 .rev()
1684 .filter_map(|mark| {
1685 let class = match *mark {
1686 "staccato" => "Staccato",
1687 "upbow" => "UpBow",
1688 "downbow" => "DownBow",
1689 "accent" => "Accent",
1690 "strongaccent" => "StrongAccent",
1691 "tenuto" => "Tenuto",
1692 _ => return None,
1693 };
1694 ArticulationKind::from_class_name(class).map(Articulation::of_kind)
1695 })
1696 .collect()
1697}
1698
1699fn grace_of(duration: &Duration) -> Duration {
1702 duration.grace_duration()
1703}
1704
1705fn part_of(
1708 tokens: &[Token],
1709 spanners: &[Spanning],
1710) -> Result<(Stream, Vec<Option<usize>>, Vec<Spanning>)> {
1711 let handler = Handler {
1712 version: DEFAULT_VERSION,
1713 directives: Vec::new(),
1714 tokens: tokens.to_vec(),
1715 };
1716 let merged: Vec<BarHandler> = if handler.defines_measures() {
1717 merge_leading_metadata(split_by_measure(tokens))
1718 } else {
1719 vec![BarHandler {
1720 tokens: tokens.to_vec(),
1721 ..BarHandler::default()
1722 }]
1723 };
1724 let use_measures = merged.len() > 1;
1725
1726 let mut reader = PartReader {
1727 spanners: spanners.to_vec(),
1728 next_uid: 0,
1729 lyric_targets: Vec::new(),
1730 post_transposition: 0,
1731 };
1732 let mut started: Vec<usize> = Vec::new();
1734 let mut part = Line::default();
1735 let mut measures: Vec<MeasureIr> = Vec::new();
1736 let mut brackets: Vec<Bracket> = Vec::new();
1737 let mut bar_count = 0;
1738 let mut measure_number = 1;
1739
1740 for handler in &merged {
1741 let in_measure = use_measures && Handler::has_notes(&handler.tokens);
1742 let mut measure = MeasureIr::default();
1743 if in_measure {
1744 let index = measures.len();
1745 if let Some(left) = &handler.left {
1746 measure.left = left.barline();
1747 if let Some(number) = left.repeat_bracket() {
1748 match brackets.iter_mut().find(|bracket| !bracket.complete) {
1749 None => brackets.push(Bracket {
1750 number,
1751 measures: vec![index],
1752 complete: number == 2,
1753 }),
1754 Some(open) => {
1755 if !open.measures.contains(&index) {
1756 open.measures.push(index);
1757 }
1758 open.complete = true;
1759 }
1760 }
1761 }
1762 }
1763 if let Some(right) = &handler.right {
1764 measure.right = right.barline().map(|barline| {
1766 if barline.repeat_direction() == Some(RepeatDirection::Start) {
1767 Barline::repeat(RepeatDirection::End, None)
1768 } else {
1769 barline
1770 }
1771 });
1772 if right.repeat
1773 && let Some(open) = brackets.iter_mut().find(|bracket| !bracket.complete)
1774 {
1775 if !open.measures.contains(&index) {
1776 open.measures.push(index);
1777 }
1778 open.complete = true;
1779 }
1780 }
1781 bar_count += 1;
1782 }
1783
1784 reader.post_transposition = 0;
1786 let place = in_measure.then_some(measures.len());
1787 {
1788 let line = if in_measure {
1789 &mut measure.line
1790 } else {
1791 &mut part
1792 };
1793 for token in &handler.tokens {
1794 match token {
1795 Token::Metadata { tag, data } => {
1796 if tag == "w" {
1797 let wanted = std::mem::take(&mut reader.lyric_targets);
1798 let mut targets: Vec<&mut StreamElement> = Vec::new();
1799 let mut here: Vec<usize> = wanted
1802 .iter()
1803 .filter(|(held, _)| *held == place)
1804 .map(|(_, index)| *index)
1805 .collect();
1806 here.sort_unstable();
1807 let outside = wanted.iter().any(|(held, _)| *held != place);
1808 if !outside {
1809 let mut rest: &mut [Item] = &mut line.items;
1810 let mut passed = 0;
1811 for index in here {
1812 let (_, tail) = rest.split_at_mut(index - passed);
1813 let (item, tail) = tail
1814 .split_first_mut()
1815 .ok_or_else(|| abc_error("a lyric's note is missing"))?;
1816 targets.push(&mut item.element);
1817 rest = tail;
1818 passed = index + 1;
1819 }
1820 add_lyrics(data, &mut targets)?;
1821 } else {
1822 add_lyrics_across(data, &wanted, &mut measures, line, place)?;
1823 }
1824 }
1825 match tag.as_str() {
1826 "M" => {
1827 if let Some(meter) = meter_of(data)? {
1828 if use_measures {
1829 line.set_at_start(meter.into());
1830 } else {
1831 line.append(meter, None);
1832 }
1833 }
1834 }
1835 "K" => {
1836 let key = key_of(data)?;
1837 if use_measures {
1838 line.set_at_start(key);
1839 } else {
1840 line.append(key, None);
1841 }
1842 if let Some((clef, transposition)) = clef_of(data) {
1843 if use_measures {
1844 line.set_at_start(clef.into());
1845 } else {
1846 line.append(clef, None);
1847 }
1848 reader.post_transposition = transposition;
1849 }
1850 }
1851 "Q" => line.append(tempo_of(data)?, None),
1852 _ => {}
1853 }
1854 }
1855 Token::Note(note) => {
1856 let (symbol, made) = note_elements(note, &mut reader)?;
1857 if let Some(symbol) = symbol {
1858 line.append(symbol, None);
1859 }
1860 if let Some((element, uid)) = made {
1861 let sung = !matches!(element, StreamElement::Rest(_)) && !note.in_grace;
1862 line.append(element, uid);
1863 if sung {
1864 reader.lyric_targets.push((place, line.items.len() - 1));
1865 }
1866 }
1867 }
1868 Token::SpannerStart(_, Some(index)) => started.push(*index),
1869 _ => {}
1870 }
1871 }
1872 }
1873
1874 if in_measure {
1875 if bar_count == 1
1876 && let Some(meter) = measure.line.meter()
1877 {
1878 let bar = meter.bar_quarter_length();
1880 let highest = measure_stream(&measure.line).end_offset();
1881 if highest < bar {
1882 measure.padding_left = bar - highest;
1883 }
1884 measure.number = 0;
1885 } else {
1886 measure.number = measure_number;
1887 measure_number += 1;
1888 }
1889 measures.push(measure);
1891 }
1892 }
1893
1894 re_bar(&mut measures, &mut brackets);
1895
1896 let mut endings: Vec<Option<Ending>> = vec![None; measures.len()];
1898 for bracket in brackets.iter().filter(|bracket| bracket.complete) {
1900 for (place, index) in bracket.measures.iter().enumerate() {
1901 if let Some(slot) = endings.get_mut(*index)
1902 && slot.is_none()
1903 {
1904 *slot = Some(Ending::new(
1905 vec![bracket.number],
1906 place == 0,
1907 place + 1 == bracket.measures.len(),
1908 ));
1909 }
1910 }
1911 }
1912
1913 let has_clef = measures
1915 .iter()
1916 .flat_map(|measure| &measure.line.items)
1917 .chain(&part.items)
1918 .any(|item| matches!(item.element, StreamElement::Clef(_)));
1919 if !has_clef {
1920 let mut pitches: Vec<Pitch> = Vec::new();
1921 for item in measures
1922 .iter()
1923 .flat_map(|measure| measure.line.sorted())
1924 .chain(part.sorted())
1925 {
1926 match &item.element {
1927 StreamElement::Note(note) => pitches.push(note.pitch().clone()),
1928 StreamElement::Chord(chord) => pitches.extend(chord.pitches()),
1929 StreamElement::ChordSymbol(symbol) => {
1930 pitches.extend(symbol.pitches().unwrap_or_default());
1931 }
1932 _ => {}
1933 }
1934 }
1935 let clef = Clef::best_for(&pitches, false);
1936 match measures.first_mut() {
1937 Some(first) if use_measures => first.line.set_at_start(clef.into()),
1938 _ => {
1939 part.items.push(Item {
1940 offset: 0.0,
1941 seq: part.seq,
1942 uid: None,
1943 element: clef.into(),
1944 });
1945 part.seq += 1;
1946 }
1947 }
1948 }
1949
1950 if reader.post_transposition != 0 {
1951 let interval = Interval::from_semitones(reader.post_transposition)?;
1955 for item in measures
1956 .iter_mut()
1957 .flat_map(|measure| &mut measure.line.items)
1958 .chain(&mut part.items)
1959 {
1960 if item.element.is_note_or_chord() {
1961 item.element = item.element.transpose(&interval)?;
1962 }
1963 }
1964 }
1965
1966 let mut uids: Vec<Option<usize>> = Vec::new();
1968 let mut events = Vec::new();
1969 let mut offset = 0.0;
1970 let has_meter = part.meter().is_some()
1971 || measures
1972 .iter()
1973 .any(|measure| measure.line.meter().is_some());
1974 for (index, measure) in measures.into_iter().enumerate() {
1975 let mut inner = Vec::new();
1976 for item in measure.line.sorted() {
1977 uids.push(item.uid);
1978 inner.push(StreamEvent::new(item.offset, item.element.clone()));
1979 }
1980 let mut stream = Stream::from_events(inner);
1981 stream.set_kind(StreamKind::Measure);
1982 stream.set_number(measure.number);
1983 stream.set_left_barline(measure.left);
1984 stream.set_right_barline(measure.right);
1985 stream.set_ending(endings[index].clone());
1986 stream.set_padding_left(measure.padding_left);
1987 let length = measure.line.end;
1988 events.push(StreamEvent::new(offset, stream));
1989 offset = op_frac(offset + length);
1990 }
1991 for item in part.sorted() {
1992 uids.push(item.uid);
1993 events.push(StreamEvent::new(item.offset, item.element.clone()));
1994 }
1995 let mut stream = Stream::from_events(events);
1996 stream.set_kind(StreamKind::Part);
1997
1998 if use_measures && has_meter {
1999 let _ = crate::makenotation::make_beams(&mut stream);
2001 }
2002
2003 let held: Vec<Spanning> = started
2004 .into_iter()
2005 .map(|index| reader.spanners[index].clone())
2006 .collect();
2007 Ok((stream, uids, held))
2008}
2009
2010fn add_lyrics_across(
2012 data: &str,
2013 wanted: &[(Option<usize>, usize)],
2014 measures: &mut [MeasureIr],
2015 line: &mut Line,
2016 place: Option<usize>,
2017) -> Result<()> {
2018 let mut elements: Vec<StreamElement> = Vec::new();
2020 for (held, index) in wanted {
2021 let item = if *held == place {
2022 line.items.get(*index)
2023 } else {
2024 held.and_then(|measure| measures.get(measure))
2025 .and_then(|measure| measure.line.items.get(*index))
2026 };
2027 elements.push(
2028 item.map(|item| item.element.clone())
2029 .ok_or_else(|| abc_error("a lyric's note is missing"))?,
2030 );
2031 }
2032 {
2033 let mut targets: Vec<&mut StreamElement> = elements.iter_mut().collect();
2034 add_lyrics(data, &mut targets)?;
2035 }
2036 for ((held, index), element) in wanted.iter().zip(elements) {
2037 let slot = if *held == place {
2038 line.items.get_mut(*index)
2039 } else {
2040 held.and_then(|measure| measures.get_mut(measure))
2041 .and_then(|measure| measure.line.items.get_mut(*index))
2042 };
2043 if let Some(slot) = slot {
2044 slot.element = element;
2045 }
2046 }
2047 Ok(())
2048}
2049
2050fn measure_stream(line: &Line) -> Stream {
2052 let mut stream = Stream::from_events(
2053 line.sorted()
2054 .into_iter()
2055 .map(|item| StreamEvent::new(item.offset, item.element.clone())),
2056 );
2057 stream.set_kind(StreamKind::Measure);
2058 stream
2059}
2060
2061fn re_bar(measures: &mut Vec<MeasureIr>, brackets: &mut [Bracket]) {
2069 let mut meter: Option<TimeSignature> = None;
2070 let mut shift = 0;
2071 let mut places: Vec<usize> = (0..measures.len()).collect();
2073 let mut index = 0;
2074 let mut original = 0;
2075 let count = measures.len();
2076 'measures: while original < count {
2077 if let Some(own) = measures[index].line.meter() {
2078 meter = Some(own.clone());
2079 }
2080 let Some(current) = meter.clone() else {
2081 break;
2082 };
2083 places[original] = index;
2084 let bar = op_frac(current.bar_quarter_length());
2085 let end = measures[index].line.end;
2086 measures[index].number += shift;
2087 if end > bar + 1e-9 {
2088 let mut second = Line::default();
2089 let mut kept: Vec<Item> = Vec::new();
2090 let mut moved: Vec<Item> = Vec::new();
2091 let items = std::mem::take(&mut measures[index].line.items);
2092 let mut broken = false;
2093 for item in items {
2094 let length = item.element.quarter_length();
2095 if (item.offset - bar).abs() <= 1e-9 && length == 0.0 {
2096 kept.push(item);
2099 } else if item.offset >= bar - 1e-9 {
2100 moved.push(item);
2101 } else if item.offset + length > bar + 1e-9 {
2102 match split_element(&item.element, op_frac(bar - item.offset)) {
2103 Ok((first, remain)) => {
2104 second.items.push(Item {
2105 offset: 0.0,
2106 seq: second.seq,
2107 uid: None,
2108 element: remain,
2109 });
2110 second.seq += 1;
2111 kept.push(Item {
2112 element: first,
2113 ..item
2114 });
2115 }
2116 Err(_) => {
2117 broken = true;
2118 kept.push(item);
2119 }
2120 }
2121 } else {
2122 kept.push(item);
2123 }
2124 }
2125 measures[index].line.items = kept;
2126 measures[index].line.end = bar;
2127 if broken {
2128 break 'measures;
2129 }
2130 for item in moved {
2131 second.items.push(Item {
2132 offset: op_frac(item.offset - bar),
2133 seq: second.seq,
2134 ..item
2135 });
2136 second.seq += 1;
2137 }
2138 second.end = op_frac(end - bar);
2139 if (bar - second.end).abs() > 1e-9
2140 && let Ok(best) = crate::meter::best_time_signature(&measure_stream(&second))
2141 {
2142 second.set_at_start(best.into());
2143 if original + 1 < count && measures[index + 1].line.meter().is_none() {
2144 let mut again = current.clone();
2147 again.set_restated(true);
2148 measures[index + 1].line.set_at_start(again.into());
2149 }
2150 }
2151 let number = measures[index].number + 1;
2152 shift += 1;
2153 let right = measures[index].right.take();
2155 measures.insert(
2156 index + 1,
2157 MeasureIr {
2158 line: second,
2159 number,
2160 left: None,
2161 right,
2162 padding_left: 0.0,
2163 },
2164 );
2165 index += 1;
2166 }
2167 index += 1;
2168 original += 1;
2169 }
2170 for (passed, place) in places.iter_mut().skip(original).enumerate() {
2171 *place = index + passed;
2172 }
2173 for bracket in brackets {
2174 for measure in &mut bracket.measures {
2175 *measure = places[*measure];
2176 }
2177 }
2178}
2179
2180fn score_of(handler: &Handler, spanners: &[Spanning]) -> Result<Stream> {
2182 let mut metadata = Metadata::new();
2183 let mut titles = 0;
2184 for token in &handler.tokens {
2185 let Some((tag, data)) = token.metadata() else {
2186 continue;
2187 };
2188 match tag {
2189 "T" => {
2190 metadata.add_text(
2191 if titles == 0 {
2192 "title"
2193 } else {
2194 "alternativeTitle"
2195 },
2196 data,
2197 );
2198 titles += 1;
2199 }
2200 "C" => metadata.add_contributor("composer", data),
2201 "O" => metadata.add_text("localeOfComposition", data),
2202 "X" => {
2203 let number = data.trim().parse::<IntegerType>().map_err(|_| {
2204 abc_error(format!("the reference number {data:?} is no number"))
2205 })?;
2206 metadata.add_text("number", number.to_string());
2207 }
2208 _ => {}
2209 }
2210 }
2211
2212 let voices = handler.split_by_voice();
2213 let parts: Vec<Vec<Token>> = if voices.len() == 1 {
2214 voices
2215 } else {
2216 voices[1..]
2218 .iter()
2219 .map(|voice| {
2220 voices[0]
2221 .iter()
2222 .cloned()
2223 .chain(voice.iter().cloned())
2224 .collect()
2225 })
2226 .collect()
2227 };
2228
2229 let mut events = Vec::new();
2230 let mut uids: Vec<Option<(usize, usize)>> = Vec::new();
2231 let mut held: Vec<(usize, Spanning)> = Vec::new();
2232 for (index, tokens) in parts.iter().enumerate() {
2233 let (part, part_uids, part_spanners) = part_of(tokens, spanners)?;
2234 uids.extend(part_uids.into_iter().map(|uid| uid.map(|uid| (index, uid))));
2235 held.extend(part_spanners.into_iter().map(|spanner| (index, spanner)));
2236 events.push(StreamEvent::new(0.0, part));
2237 }
2238 let mut score = Stream::from_events(events);
2239 score.set_kind(StreamKind::Score);
2240 score.set_metadata(Some(metadata));
2241 for (part, spanner) in held {
2242 let positions: Vec<Option<usize>> = spanner
2243 .uids
2244 .iter()
2245 .map(|uid| uids.iter().position(|held| *held == Some((part, *uid))))
2246 .collect();
2247 let made = match spanner.kind {
2248 SpannerKind::Crescendo | SpannerKind::Diminuendo => {
2249 let template = Spanner::wedge(spanner.kind, Vec::new());
2250 let mut wedge = Spanner::with_unplaced(spanner.kind, positions);
2251 wedge.set_placement(template.placement());
2252 wedge.set_spread(template.spread());
2253 wedge
2254 }
2255 kind => Spanner::with_unplaced(kind, positions),
2256 };
2257 score.add_spanner(made);
2258 }
2259 Ok(score)
2260}
2261
2262fn extract_reference_number(text: &str, number: IntegerType) -> Result<String> {
2264 let mut collected = Vec::new();
2265 let mut gathering = false;
2266 for line in text.split('\n') {
2267 let starts = line.trim().starts_with("X:");
2268 if starts && !gathering {
2269 let named = line.replace(' ', "");
2270 let named = named.trim_end().trim_start_matches("X:");
2271 if named.parse::<IntegerType>() == Ok(number) {
2272 gathering = true;
2273 }
2274 } else if starts && gathering {
2275 break;
2276 }
2277 if gathering {
2278 collected.push(line);
2279 }
2280 }
2281 if collected.is_empty() {
2282 return Err(abc_error(format!(
2283 "cannot find requested reference number in source file: {number}"
2284 )));
2285 }
2286 Ok(collected.join("\n"))
2287}
2288
2289fn handler_of(text: &str) -> Result<(Handler, Vec<Spanning>)> {
2290 let mut handler = Handler::new(DEFAULT_VERSION);
2291 handler.read_version(text);
2292 handler.tokenize(text)?;
2293 let spanners = handler.process()?;
2294 Ok((handler, spanners))
2295}
2296
2297pub fn from_abc(text: &str) -> Result<Stream> {
2315 let (handler, spanners) = handler_of(text)?;
2316 if handler.defines_reference_numbers() {
2317 let mut events = Vec::new();
2318 let mut offset = 0.0;
2319 for (_, tune) in handler.split_by_reference_number() {
2320 let score = score_of(&tune, &spanners)?;
2321 let length = score.end_offset();
2322 events.push(StreamEvent::new(offset, score));
2323 offset += length;
2324 }
2325 let mut opus = Stream::from_events(events);
2326 opus.set_kind(StreamKind::Opus);
2327 return Ok(opus);
2328 }
2329 score_of(&handler, &spanners)
2330}
2331
2332pub fn from_abc_number(text: &str, number: IntegerType) -> Result<Stream> {
2335 let (handler, spanners) = handler_of(&extract_reference_number(text, number)?)?;
2336 score_of(&handler, &spanners)
2337}
2338
2339#[cfg(test)]
2340mod tests {
2341 use super::*;
2342
2343 fn tokens_of(text: &str) -> Vec<Token> {
2344 let mut handler = Handler::new(DEFAULT_VERSION);
2345 handler.tokenize(text).unwrap();
2346 handler.tokens
2347 }
2348
2349 #[test]
2350 fn a_bar_says_what_it_is() {
2351 let bar = Bar::new("|");
2353 assert!(bar.is_regular() && !bar.repeat);
2354 let end = Bar::new(":|");
2355 assert!(end.repeat && end.form == "end" && end.style == "light-heavy");
2356 let first = Bar::new("[1");
2357 assert_eq!(first.repeat_bracket(), Some(1));
2358 assert_eq!(
2359 Bar::new("||").barline().unwrap().bar_type(),
2360 BarlineType::Double
2361 );
2362 }
2363
2364 #[test]
2365 fn text_is_cut_into_tokens_as_music21_cuts_it() {
2366 let tokens = tokens_of("M:6/8\nL:1/8\nK:G\nB3 A3 | (3GAB c2 :|\n");
2367 let kinds: Vec<&str> = tokens
2368 .iter()
2369 .map(|token| match token {
2370 Token::Metadata { .. } => "meta",
2371 Token::Bar(_) => "bar",
2372 Token::Tuplet { .. } => "tuplet",
2373 Token::Note(_) => "note",
2374 _ => "other",
2375 })
2376 .collect();
2377 assert_eq!(
2378 kinds,
2379 [
2380 "meta", "meta", "meta", "note", "note", "bar", "tuplet", "note", "note", "note",
2381 "note", "bar"
2382 ]
2383 );
2384 }
2385
2386 #[test]
2387 fn a_key_line_gives_its_sharps_and_mode() {
2388 assert_eq!(key_parameters("Eb").unwrap(), (-3, Some("major")));
2390 assert_eq!(
2391 key_parameters("A mixolydian").unwrap(),
2392 (2, Some("mixolydian"))
2393 );
2394 assert_eq!(key_parameters("F#m").unwrap(), (3, Some("minor")));
2395 assert_eq!(key_parameters("HP").unwrap(), (0, None));
2396 assert_eq!(key_parameters("Hp").unwrap(), (2, None));
2397 }
2398
2399 #[test]
2400 fn a_length_is_read_against_the_default() {
2401 let mut note = AbcNote::new("", "", false);
2403 note.default_quarter_length = Some(0.5);
2404 assert_eq!(note.read_quarter_length("f", None).unwrap(), 0.5);
2405 assert_eq!(note.read_quarter_length("f2", None).unwrap(), 1.0);
2406 assert_eq!(note.read_quarter_length("f/", None).unwrap(), 0.25);
2407 assert_eq!(note.read_quarter_length("f3/2", None).unwrap(), 0.75);
2408 note.broken_rhythm = Some((">".to_string(), true));
2409 assert_eq!(note.read_quarter_length("A", None).unwrap(), 0.75);
2410 }
2411
2412 #[test]
2413 fn a_pitch_takes_its_accidental_from_the_key() {
2414 let mut note = AbcNote::new("f", "", false);
2415 note.key = Some(KeySignature::new(1));
2416 assert_eq!(
2417 note.pitch_name("f", None).unwrap(),
2418 (Some("F#5".to_string()), Some(false))
2419 );
2420 assert_eq!(
2421 note.pitch_name("=f", None).unwrap(),
2422 (Some("Fn5".to_string()), Some(true))
2423 );
2424 assert_eq!(note.pitch_name("z", None).unwrap(), (None, None));
2425 assert_eq!(
2426 note.pitch_name("C,,", None).unwrap(),
2427 (Some("C2".to_string()), Some(false))
2428 );
2429 }
2430
2431 #[test]
2432 fn a_tune_is_a_score_of_measures() {
2433 let score =
2434 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();
2435 assert_eq!(score.kind(), StreamKind::Score);
2436 let metadata = score.metadata().unwrap();
2437 assert_eq!(metadata.first_text("title"), Some("Tune"));
2438 let part = score.parts()[0];
2439 let measures = part.measures();
2440 assert_eq!(measures.len(), 3);
2441 let names: Vec<String> = measures[0]
2442 .pitches()
2443 .iter()
2444 .map(|pitch| pitch.name_with_octave())
2445 .collect();
2446 assert_eq!(names, ["D4", "E4", "F#4"]);
2447 assert_eq!(
2448 measures[2].right_barline().unwrap().bar_type(),
2449 BarlineType::Final
2450 );
2451 }
2452
2453 #[test]
2454 fn several_tunes_are_an_opus_and_one_can_be_asked_for() {
2455 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";
2456 let opus = from_abc(text).unwrap();
2457 assert_eq!(opus.kind(), StreamKind::Opus);
2458 assert_eq!(opus.events().len(), 2);
2459 let second = from_abc_number(text, 2).unwrap();
2460 assert_eq!(second.metadata().unwrap().first_text("title"), Some("Two"));
2461 assert!(from_abc_number(text, 3).is_err());
2462 }
2463
2464 #[test]
2465 fn a_measure_holding_more_than_its_bar_is_cut_in_two() {
2466 let score = from_abc(
2470 "X:1
2471M:4/4
2472L:1/4
2473K:C
2474CDEF|GAB4|CDEF|
2475",
2476 )
2477 .unwrap();
2478 let part = score.events()[0].element().as_stream().unwrap();
2479 let measures = part.measures();
2480 let numbers: Vec<_> = measures.iter().map(|measure| measure.number()).collect();
2481 assert_eq!(numbers, [0, 1, 2, 3]);
2482 let meter = |measure: &Stream| {
2483 measure
2484 .events()
2485 .iter()
2486 .find_map(|event| match event.element() {
2487 StreamElement::TimeSignature(meter) => Some(meter.ratio_string()),
2488 _ => None,
2489 })
2490 };
2491 assert_eq!(meter(measures[1]), None);
2492 assert_eq!(meter(measures[2]).as_deref(), Some("2/4"));
2493 assert_eq!(meter(measures[3]).as_deref(), Some("4/4"));
2494 let ties: Vec<_> = measures[1..3]
2495 .iter()
2496 .flat_map(|measure| measure.events())
2497 .filter_map(|event| match event.element() {
2498 StreamElement::Note(note) if note.pitch().name() == "B" => Some((
2499 event.element().quarter_length(),
2500 note.tie().map(Tie::tie_type),
2501 )),
2502 _ => None,
2503 })
2504 .collect();
2505 assert_eq!(
2506 ties,
2507 [(2.0, Some(TieType::Start)), (2.0, Some(TieType::Stop))]
2508 );
2509 }
2510}