1use crate::bar::{Barline, BarlineType, RepeatDirection};
8use crate::chord::Chord;
9use crate::clef::{Clef, ClefKind};
10use crate::defaults::{FloatType, IntegerType};
11use crate::duration::{Duration, Tuplet};
12use crate::error::{Error, Result};
13use crate::key::KeySignature;
14use crate::makenotation::{make_measures, op_frac};
15use crate::meter::TimeSignature;
16use crate::notation::{Lyric, Syllabic, Tie, TieType};
17use crate::note::Note;
18use crate::pitch::Pitch;
19use crate::pitch::accidental::Accidental;
20use crate::rest::Rest;
21use crate::stream::{Stream, StreamElement, StreamEvent, StreamKind};
22use crate::xml::Xml;
23
24fn error(message: impl Into<String>) -> Error {
25 Error::Capella(message.into())
26}
27
28type Placed = Vec<(FloatType, StreamElement)>;
30
31type Staff = (String, Placed);
33
34pub fn from_capella(document: &str) -> Result<Stream> {
71 let document = document.strip_prefix('\u{feff}').unwrap_or(document);
72 let root = without_namespaces(Xml::parse(document)?);
73
74 let mut systems_found = children(&root, "systems");
75 let systems = match (systems_found.next(), systems_found.next()) {
76 (Some(systems), None) => systems,
77 (None, _) => return Err(error("Cannot find a <systems> tag in the <score> object")),
78 (Some(_), Some(_)) => {
79 return Err(error(
80 "Found more than one <systems> tag in the <score> object, what does this mean?",
81 ));
82 }
83 };
84 let systems: Vec<&Xml> = children(systems, "system").collect();
85 if systems.is_empty() {
86 return Err(error(
87 "Cannot find any <system> tags in the <systems> tag in the <score> object",
88 ));
89 }
90
91 let mut parts: Vec<(String, usize, Placed)> = Vec::new();
94 let mut system_offset = 0.0;
95 for system in systems {
96 let staves = read_system(system)?;
97 let length = staves
98 .iter()
99 .map(|(_, elements)| end_of(elements))
100 .fold(0.0, FloatType::max);
101 for (place, (id, elements)) in staves.into_iter().enumerate() {
102 let index = match parts.iter().position(|(known, _, _)| *known == id) {
103 Some(index) => index,
104 None => {
105 parts.push((id, place, Vec::new()));
106 parts.len() - 1
107 }
108 };
109 for (offset, element) in elements {
110 parts[index]
111 .2
112 .push((op_frac(offset + system_offset), element));
113 }
114 }
115 system_offset += length;
116 }
117
118 let mut slots: Vec<Option<Staff>> = (0..parts.len()).map(|_| None).collect();
121 for (id, place, elements) in parts {
122 let slot = slots
123 .get_mut(place)
124 .ok_or_else(|| error("part entries do not match partDict!"))?;
125 *slot = Some((id, elements));
126 }
127 let mut score = Stream::with_kind(StreamKind::Score);
128 for (id, elements) in slots.into_iter().flatten() {
129 let mut part = Stream::with_kind(StreamKind::Part);
130 for (offset, element) in elements {
131 part.insert_sorted(vec![StreamEvent::new(offset, element)]);
132 }
133 let part = without_restatements(part);
134 let mut measured = make_measures(&part)?;
135 measured.set_id(Some(id));
136 score.insert(0.0, measured);
137 }
138 Ok(score)
139}
140
141fn without_namespaces(mut element: Xml) -> Xml {
144 if let Some((_, local)) = element.tag.rsplit_once(':') {
145 element.tag = local.to_string();
146 }
147 element.children = element
148 .children
149 .into_iter()
150 .map(without_namespaces)
151 .collect();
152 element
153}
154
155fn children<'a>(element: &'a Xml, tag: &'a str) -> impl Iterator<Item = &'a Xml> {
156 element
157 .children
158 .iter()
159 .filter(move |child| child.tag == tag)
160}
161
162fn only<'a>(element: &'a Xml, tag: &'a str, missing: &str, several: &str) -> Result<&'a Xml> {
164 let mut found = children(element, tag);
165 match (found.next(), found.next()) {
166 (Some(child), None) => Ok(child),
167 (None, _) => Err(error(missing)),
168 (Some(_), Some(_)) => Err(error(several)),
169 }
170}
171
172fn end_of(elements: &[(FloatType, StreamElement)]) -> FloatType {
173 elements
174 .iter()
175 .map(|(offset, element)| offset + element.quarter_length())
176 .fold(0.0, FloatType::max)
177}
178
179fn read_system(system: &Xml) -> Result<Vec<Staff>> {
181 let staves = only(
182 system,
183 "staves",
184 "No <staves> tag found in this <system> element",
185 "More than one <staves> tag found in this <system> element",
186 )?;
187 let mut out = Vec::new();
188 for staff in children(staves, "staff") {
189 let id = staff.get("layout").unwrap_or("UnknownPart").to_string();
190 let voices = children(staff, "voices").next().ok_or_else(|| {
191 error(
192 "No <voices> tag found in the <staff> tag for the <staves> element for this \
193 <system> element",
194 )
195 })?;
196 let voice_list: Vec<&Xml> = children(voices, "voice").collect();
197 if voice_list.is_empty() {
198 return Err(error(
199 "No <voice> tag found in the <voices> tag for the <staff> tag for the <staves> \
200 element for this <system> element",
201 ));
202 }
203 let mut elements = Vec::new();
204 if let [voice] = voice_list.as_slice() {
205 let objects = only(
206 voice,
207 "noteObjects",
208 "No <noteObjects> tag found in the <voice> tag",
209 "More than one <noteObjects> tag found in the <voice> tag",
210 )?;
211 for object in &objects.children {
212 for element in note_object(object)? {
213 let at = end_of(&elements);
214 elements.push((at, element));
215 }
216 }
217 }
218 out.push((id, elements));
219 }
220 Ok(out)
221}
222
223fn note_object(object: &Xml) -> Result<Vec<StreamElement>> {
225 Ok(match object.tag.as_str() {
226 "clefSign" => clef(object)?.map(StreamElement::Clef).into_iter().collect(),
227 "keySign" => match object.get("fifths") {
228 Some(fifths) => vec![StreamElement::KeySignature(KeySignature::new(integer(
229 fifths,
230 )?))],
231 None => Vec::new(),
232 },
233 "timeSign" => match object.get("time") {
234 Some(time) if time != "infinite" => {
235 vec![StreamElement::TimeSignature(
236 TimeSignature::from_ratio_string(time)?,
237 )]
238 }
239 _ => Vec::new(),
240 },
241 "rest" => {
242 let written = children(object, "duration")
243 .next()
244 .ok_or_else(|| error("a rest with no duration"))?;
245 vec![StreamElement::Rest(Rest::new(duration(written)?))]
246 }
247 "chord" => vec![chord(object)?],
248 "barline" => barlines(object)?,
249 _ => Vec::new(),
250 })
251}
252
253fn integer(text: &str) -> Result<IntegerType> {
254 text.trim()
255 .parse()
256 .map_err(|_| error(format!("{text:?} is not a number")))
257}
258
259fn clef(object: &Xml) -> Result<Option<Clef>> {
261 let Some(value) = object.get("clef") else {
262 return Ok(None);
263 };
264 let kind = match value {
265 "treble" => Some(ClefKind::TrebleClef),
266 "bass" => Some(ClefKind::BassClef),
267 "alto" => Some(ClefKind::AltoClef),
268 "tenor" => Some(ClefKind::TenorClef),
269 "G2-" => Some(ClefKind::Treble8vbClef),
270 _ => None,
271 };
272 if let Some(kind) = kind {
273 return Ok(Some(Clef::of_kind(kind)));
274 }
275 if value.starts_with('p') {
276 return Ok(Some(Clef::of_kind(ClefKind::PercussionClef)));
277 }
278 let letters: Vec<char> = value.chars().collect();
279 if letters.len() > 1 {
280 let shift = match letters.get(2) {
281 Some('+') => 1,
282 Some('-') => -1,
283 _ => 0,
284 };
285 let sign_and_line: String = letters[..2].iter().collect();
286 return Clef::from_string(&sign_and_line, shift).map(Some);
287 }
288 Ok(None)
289}
290
291fn chord(object: &Xml) -> Result<StreamElement> {
293 let durations: Vec<&Xml> = children(object, "duration").collect();
294 let heads: Vec<&Xml> = children(object, "heads").collect();
295 let ([written], [heads]) = (durations.as_slice(), heads.as_slice()) else {
296 return Err(error("Malformed chord!"));
297 };
298 let mut notes = Vec::new();
299 for head in children(heads, "head") {
300 notes.push(note(head)?);
301 }
302 if notes.is_empty() {
303 return Err(error("Malformed chord!"));
304 }
305 let duration = duration(written)?;
306 let lyrics: Vec<Lyric> = match children(object, "lyric").next() {
307 Some(lyric) => children(lyric, "verse")
308 .map(verse)
309 .collect::<Result<Vec<_>>>()?
310 .into_iter()
311 .flatten()
312 .collect(),
313 None => Vec::new(),
314 };
315 Ok(if notes.len() == 1 {
316 let mut note = notes.remove(0);
317 note.set_duration(duration);
318 *note.lyrics_mut() = lyrics;
319 StreamElement::Note(note)
320 } else {
321 let mut chord = Chord::new(notes)?.with_duration(duration);
322 if let Some(first) = chord.notes_mut().first_mut() {
323 *first.lyrics_mut() = lyrics;
324 }
325 StreamElement::Chord(chord)
326 })
327}
328
329fn note(head: &Xml) -> Result<Note> {
331 let written = head
332 .get("pitch")
333 .ok_or_else(|| error("Cannot deal with <head> element without pitch!"))?;
334 let mut pitch = Pitch::from_name(written)?;
335 let octave = pitch.octave().unwrap_or(4);
336 pitch.set_octave(Some(octave - 1));
337 let alters: Vec<&Xml> = children(head, "alter").collect();
338 match alters.as_slice() {
339 [] => {}
340 [alter] => pitch.set_accidental(accidental(alter)?),
341 _ => return Err(error("Cannot deal with multiple <alter> elements!")),
342 }
343 let mut note = Note::from_pitch(pitch);
344 let ties: Vec<&Xml> = children(head, "tie").collect();
345 match ties.as_slice() {
346 [] => {}
347 [tie] => note.set_tie(tie_of(tie)),
348 _ => return Err(error("Cannot deal with multiple <tie> elements!")),
349 }
350 Ok(note)
351}
352
353fn accidental(alter: &Xml) -> Result<Accidental> {
355 let steps = match alter.get("step") {
356 Some(step) => integer(step)?,
357 None => 0,
358 };
359 let name = match steps {
360 0 => "natural",
361 1 => "sharp",
362 -1 => "flat",
363 2 => "double-sharp",
364 -2 => "double-flat",
365 3 => "triple-sharp",
366 -3 => "triple-flat",
367 4 => "quadruple-sharp",
368 -4 => "quadruple-flat",
369 other => return Err(error(format!("no accidental of {other} steps"))),
370 };
371 let mut accidental = Accidental::new(name)?;
372 if alter.get("display") == Some("suppress") {
373 accidental.set_display_type("never")?;
374 }
375 Ok(accidental)
376}
377
378fn tie_of(tie: &Xml) -> Option<Tie> {
380 let begins = tie.get("begin") == Some("true");
381 let ends = tie.get("end") == Some("true");
382 let kind = match (begins, ends) {
383 (true, true) => TieType::Continue,
384 (true, false) => TieType::Start,
385 (false, true) => TieType::Stop,
386 (false, false) => return None,
387 };
388 Some(Tie::new(kind))
389}
390
391fn verse(verse: &Xml) -> Result<Option<Lyric>> {
394 let text = match verse.text() {
395 Some(text) if !text.is_empty() => text,
396 _ => return Ok(None),
397 };
398 let mut lyric = Lyric::new(text);
399 if let Some(index) = verse.get("i") {
400 lyric.set_number(integer(index)? + 1);
401 }
402 if verse.get("hyphen") == Some("true") {
403 lyric.set_syllabic(Syllabic::Begin);
404 }
405 Ok(Some(lyric))
406}
407
408fn duration(written: &Xml) -> Result<Duration> {
411 let mut length = 0.0;
412 if let Some(base) = written.get("base")
413 && let Some((numerator, denominator)) = base.split_once('/')
414 {
415 length =
416 4.0 * FloatType::from(integer(numerator)?) / FloatType::from(integer(denominator)?);
417 }
418 let mut duration = Duration::new(length)?;
419 if let Some(dots) = written.get("dots") {
420 let dots = u32::try_from(integer(dots)?).map_err(|_| error("a negative count of dots"))?;
421 if let Some((value, _)) = duration.type_and_dots() {
422 duration = Duration::from_type_with_dots(value, dots);
423 duration.set_expression_is_inferred(true);
424 }
425 }
426 for tuplet in children(written, "tuplet") {
427 duration.append_tuplet(tuplet_of(tuplet)?);
428 }
429 Ok(duration)
430}
431
432fn tuplet_of(tuplet: &Xml) -> Result<Tuplet> {
435 let mut actual = 1;
436 let mut normal = 1;
437 if let Some(count) = tuplet.get("count") {
438 actual = u32::try_from(integer(count)?).map_err(|_| error("a negative tuplet"))?;
439 while actual > normal * 2 {
440 normal *= 2;
441 }
442 }
443 if tuplet.get("prolong") == Some("true") {
444 normal *= 2;
445 }
446 Ok(Tuplet::ratio(actual, normal))
447}
448
449fn barlines(object: &Xml) -> Result<Vec<StreamElement>> {
451 let Some(kind) = object.get("type") else {
452 return Ok(Vec::new());
453 };
454 let mut out = Vec::new();
455 if kind.starts_with("rep") {
456 let (end, start) = match kind {
457 "repEnd" => (true, false),
458 "repBegin" => (false, true),
459 "repEndBegin" => (true, true),
460 _ => (false, false),
461 };
462 if end {
463 out.push(StreamElement::Barline(Barline::repeat(
464 RepeatDirection::End,
465 None,
466 )));
467 }
468 if start {
469 out.push(StreamElement::Barline(Barline::repeat(
470 RepeatDirection::Start,
471 None,
472 )));
473 }
474 } else {
475 let bar_type = match kind {
476 "single" => BarlineType::Regular,
477 "double" => BarlineType::Double,
478 "end" => BarlineType::Final,
479 _ => return Ok(Vec::new()),
480 };
481 out.push(StreamElement::Barline(Barline::new(bar_type)));
482 }
483 Ok(out)
484}
485
486fn without_restatements(part: Stream) -> Stream {
489 let mut last_clef: Option<Clef> = None;
490 let mut last_key: Option<KeySignature> = None;
491 let mut kept = Vec::new();
492 for event in part.events() {
493 match event.element() {
494 StreamElement::Clef(clef) => {
495 if last_clef.as_ref().is_some_and(|last| same_clef(last, clef)) {
496 continue;
497 }
498 last_clef = Some(clef.clone());
499 }
500 StreamElement::KeySignature(signature) => {
501 if last_key
503 .as_ref()
504 .is_some_and(|last| last.sharps() == signature.sharps())
505 {
506 continue;
507 }
508 last_key = Some(signature.clone());
509 }
510 _ => {}
511 }
512 kept.push(event.clone());
513 }
514 part.with_events(kept)
515}
516
517fn same_clef(left: &Clef, right: &Clef) -> bool {
519 left.kind() == right.kind()
520 && left.sign() == right.sign()
521 && left.line() == right.line()
522 && left.octave_change() == right.octave_change()
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
529 fn staff(objects: &str) -> String {
530 format!(
531 "<score xmlns=\"http://www.capella.de/CapXML/2.0\"><systems><system><staves>\
532 <staff layout=\"S\"><voices><voice><noteObjects>{objects}</noteObjects></voice>\
533 </voices></staff></staves></system></systems></score>"
534 )
535 }
536
537 #[test]
538 fn a_capella_octave_is_one_higher_than_music21_s() {
539 let score = from_capella(&staff(
540 "<chord><duration base=\"1/2\"/><heads><head pitch=\"G5\"><alter step=\"1\"/>\
541 </head></heads></chord>",
542 ))
543 .unwrap();
544 assert_eq!(score.pitches()[0].name_with_octave(), "G#4");
545 }
546
547 #[test]
548 fn a_tuplet_count_takes_the_power_of_two_below_it() {
549 let tuplet = Xml::parse("<tuplet count=\"5\"/>").unwrap();
550 assert_eq!(tuplet_of(&tuplet).unwrap(), Tuplet::ratio(5, 4));
551 let prolonged = Xml::parse("<tuplet count=\"3\" prolong=\"true\"/>").unwrap();
552 assert_eq!(tuplet_of(&prolonged).unwrap(), Tuplet::ratio(3, 4));
553 let plain = Xml::parse("<tuplet count=\"3\" prolong=\"false\"/>").unwrap();
554 assert_eq!(tuplet_of(&plain).unwrap(), Tuplet::ratio(3, 2));
555 }
556
557 #[test]
558 fn a_single_barline_is_a_regular_one() {
559 assert!(from_capella(&staff("<barline type=\"single\"/>")).is_ok());
560 assert!(from_capella(&staff("<barline/>")).is_ok());
561 }
562
563 #[test]
564 fn a_document_with_no_systems_is_refused() {
565 assert!(from_capella("<score/>").is_err());
566 }
567}