1mod binary;
10
11pub use binary::{from_nwc, nwc_lines};
12
13use crate::bar::{Barline, BarlineType, Ending, RepeatDirection};
14use crate::chord::Chord;
15use crate::clef::{Clef, ClefKind};
16use crate::defaults::{FloatType, IntegerType};
17use crate::duration::{Duration, DurationType, Tuplet};
18use crate::dynamics::Dynamic;
19use crate::error::{Error, Position, Result};
20use crate::expressions::TextExpression;
21use crate::instrument::Instrument;
22use crate::interval::Interval;
23use crate::key::KeySignature;
24use crate::metadata::{Metadata, MetadataValue};
25use crate::notation::{Placement, Tie, TieType};
26use crate::note::Note;
27use crate::percussion::Unpitched;
28use crate::pitch::Pitch;
29use crate::pitch::accidental::Accidental;
30use crate::repeat::{RepeatExpression, RepeatExpressionKind};
31use crate::rest::Rest;
32use crate::spanner::Spanner;
33use crate::stream::{Stream, StreamElement, StreamKind};
34use crate::tempo::MetronomeMark;
35
36fn error(message: impl Into<String>) -> Error {
37 Error::noteworthy(message.into())
38}
39
40pub fn from_noteworthy(text: &str) -> Result<Stream> {
76 from_lines(text.lines(), true)
77}
78
79fn from_lines<'a>(lines: impl IntoIterator<Item = &'a str>, numbered: bool) -> Result<Stream> {
83 let mut reader = Reader::new();
84 for (index, line) in lines.into_iter().enumerate() {
85 let here = |error: Error| {
86 if numbered {
87 return error.placed(|| Position::line(index + 1));
88 }
89 error
90 };
91 let line = line.trim_end();
92 if !line.starts_with('|') {
93 continue;
94 }
95 let sections: Vec<&str> = line.split('|').collect();
96 let command = sections.get(1).copied().unwrap_or("");
97 let mut attributes = Attributes::default();
98 for attribute in sections.iter().skip(2) {
99 match attribute.split_once(':') {
100 Some((name, value)) => attributes.add(
101 name,
102 value,
103 command == "Chord" && matches!(name, "Dur" | "Pos"),
104 ),
105 None if attribute.trim().is_empty() => {}
106 None => {
107 return Err(here(error(format!(
108 "Cannot unpack value from {attribute} in {line}"
109 ))));
110 }
111 }
112 }
113 reader.command(command, &attributes).map_err(here)?;
114 }
115 reader.finish()
116}
117
118#[derive(Default)]
121struct Attributes {
122 values: Vec<(String, Vec<String>)>,
123}
124
125impl Attributes {
126 fn add(&mut self, name: &str, value: &str, listed: bool) {
127 match self.values.iter_mut().find(|(known, _)| known == name) {
128 Some((_, values)) if listed => values.push(value.to_string()),
129 Some((_, values)) => *values = vec![value.to_string()],
130 None => self
131 .values
132 .push((name.to_string(), vec![value.to_string()])),
133 }
134 }
135
136 fn get(&self, name: &str) -> Option<&str> {
137 self.values
138 .iter()
139 .find(|(known, _)| known == name)
140 .and_then(|(_, values)| values.last())
141 .map(String::as_str)
142 }
143
144 fn list(&self, name: &str) -> Vec<String> {
145 self.values
146 .iter()
147 .find(|(known, _)| known == name)
148 .map(|(_, values)| values.clone())
149 .unwrap_or_default()
150 }
151
152 fn required(&self, name: &str) -> Result<&str> {
153 self.get(name)
154 .ok_or_else(|| error(format!("a line with no {name}")))
155 }
156}
157
158#[derive(Clone, Copy, PartialEq, Eq)]
160enum ClefState {
161 Treble,
162 TrebleDown,
163 TrebleUp,
164 Bass,
165 BassDown,
166 BassUp,
167 Alto,
168 Tenor,
169 Percussion,
170}
171
172impl ClefState {
173 fn table(self) -> (IntegerType, IntegerType, [char; 7]) {
176 const TREBLE: [char; 7] = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
177 match self {
178 Self::TrebleDown => (4, 1, TREBLE),
179 Self::TrebleUp => (6, 1, TREBLE),
180 Self::Bass | Self::Percussion => (3, -1, TREBLE),
181 Self::BassDown => (2, -1, TREBLE),
182 Self::BassUp => (4, -1, TREBLE),
183 Self::Alto => (4, 0, TREBLE),
184 Self::Tenor => (3, -5, TREBLE),
185 Self::Treble => (5, 1, TREBLE),
186 }
187 }
188}
189
190struct Item {
192 offset: FloatType,
193 content: Content,
194 inserted: usize,
196}
197
198enum Content {
199 Element(Box<StreamElement>, Option<usize>),
202 Voice(VoiceBuilt),
203}
204
205struct VoiceBuilt {
206 id: usize,
207 items: Vec<Item>,
208}
209
210fn is_general_note(element: &StreamElement) -> bool {
211 matches!(
212 element,
213 StreamElement::Note(_)
214 | StreamElement::Chord(_)
215 | StreamElement::Rest(_)
216 | StreamElement::Unpitched(_)
217 )
218}
219
220fn highest_time(items: &[Item]) -> FloatType {
222 items
223 .iter()
224 .map(|item| {
225 item.offset
226 + match &item.content {
227 Content::Element(element, _) => element.quarter_length(),
228 Content::Voice(voice) => highest_time(&voice.items),
229 }
230 })
231 .fold(0.0, FloatType::max)
232}
233
234struct MeasureBuilt {
235 number: IntegerType,
236 left: Option<Barline>,
237 right: Option<Barline>,
238 items: Vec<Item>,
239 inserted: usize,
240}
241
242impl MeasureBuilt {
243 fn new(number: IntegerType) -> Self {
244 Self {
245 number,
246 left: None,
247 right: None,
248 items: Vec::new(),
249 inserted: 0,
250 }
251 }
252
253 fn insert(&mut self, offset: FloatType, content: Content) {
254 self.items.push(Item {
255 offset,
256 content,
257 inserted: self.inserted,
258 });
259 self.inserted += 1;
260 }
261
262 fn append(&mut self, element: StreamElement, serial: Option<usize>) {
264 let at = highest_time(&self.items);
265 self.insert(at, Content::Element(Box::new(element), serial));
266 }
267
268 fn has_voices(&self) -> bool {
269 self.items
270 .iter()
271 .any(|item| matches!(item.content, Content::Voice(_)))
272 }
273
274 fn holds_anything(&self) -> bool {
277 !self.items.is_empty() || self.left.is_some() || self.right.is_some()
278 }
279
280 fn append_shortest(&mut self, element: StreamElement, serial: Option<usize>) {
283 if !self.has_voices() {
284 self.append(element, serial);
285 return;
286 }
287 let shortest = sorted_places(&self.items)
288 .into_iter()
289 .filter(|place| matches!(self.items[*place].content, Content::Voice(_)))
290 .min_by(|left, right| {
291 voice_length(&self.items[*left]).total_cmp(&voice_length(&self.items[*right]))
292 });
293 if let Some(place) = shortest
294 && let Content::Voice(voice) = &mut self.items[place].content
295 {
296 append_to_voice(voice, element, serial);
297 }
298 }
299
300 fn append_in_voices(&mut self, elements: Vec<(StreamElement, usize)>) {
305 let offset = if self.has_voices() {
306 self.items
307 .iter()
308 .filter(|item| matches!(item.content, Content::Voice(_)))
309 .map(voice_length)
310 .fold(FloatType::INFINITY, FloatType::min)
311 } else {
312 highest_time(&self.items)
313 };
314 if !self.has_voices() {
315 let mut voice = VoiceBuilt {
316 id: 0,
317 items: Vec::new(),
318 };
319 let notes: Vec<usize> = sorted_places(&self.items)
320 .into_iter()
321 .filter(|place| {
322 matches!(&self.items[*place].content,
323 Content::Element(element, _) if is_general_note(element))
324 })
325 .collect();
326 for place in ¬es {
327 if let Content::Element(element, serial) = &self.items[*place].content {
328 append_to_voice(&mut voice, (**element).clone(), *serial);
329 }
330 }
331 let mut index = 0;
332 self.items.retain(|_| {
333 let keep = !notes.contains(&index);
334 index += 1;
335 keep
336 });
337 self.insert(0.0, Content::Voice(voice));
338 }
339 let voices: Vec<usize> = sorted_places(&self.items)
340 .into_iter()
341 .filter(|place| matches!(self.items[*place].content, Content::Voice(_)))
342 .collect();
343 let mut count = voices.len();
344 let mut free: std::collections::VecDeque<usize> = voices
345 .into_iter()
346 .filter(|place| voice_length(&self.items[*place]) == offset)
347 .collect();
348 for (element, serial) in elements {
349 let place = free.pop_front().unwrap_or_else(|| {
350 self.insert(
351 0.0,
352 Content::Voice(VoiceBuilt {
353 id: count,
354 items: Vec::new(),
355 }),
356 );
357 count += 1;
358 self.items.len() - 1
359 });
360 if let Content::Voice(voice) = &mut self.items[place].content {
361 let inserted = voice.items.len();
362 voice.items.push(Item {
363 offset,
364 content: Content::Element(Box::new(element), Some(serial)),
365 inserted,
366 });
367 }
368 }
369 }
370}
371
372fn voice_length(item: &Item) -> FloatType {
373 match &item.content {
374 Content::Voice(voice) => highest_time(&voice.items),
375 Content::Element(element, _) => element.quarter_length(),
376 }
377}
378
379fn append_to_voice(voice: &mut VoiceBuilt, element: StreamElement, serial: Option<usize>) {
380 let at = highest_time(&voice.items);
381 let inserted = voice.items.len();
382 voice.items.push(Item {
383 offset: at,
384 content: Content::Element(Box::new(element), serial),
385 inserted,
386 });
387}
388
389fn sorted_places(items: &[Item]) -> Vec<usize> {
392 let mut places: Vec<usize> = (0..items.len()).collect();
393 places.sort_by(|left, right| {
394 let key = |item: &Item| {
395 let (order, grace) = match &item.content {
396 Content::Element(element, _) => (
397 element.class_sort_order(),
398 element.duration().is_some_and(Duration::is_grace),
399 ),
400 Content::Voice(_) => (5, false),
401 };
402 (item.offset, order, !grace, item.inserted)
403 };
404 let (left, right) = (key(&items[*left]), key(&items[*right]));
405 left.0
406 .total_cmp(&right.0)
407 .then(left.1.cmp(&right.1))
408 .then(left.2.cmp(&right.2))
409 .then(left.3.cmp(&right.3))
410 });
411 places
412}
413
414enum PartItem {
417 Measure(MeasureBuilt),
418 Instrument(Box<Instrument>),
419}
420
421struct PartBuilt {
422 name: Option<String>,
423 items: Vec<(FloatType, PartItem)>,
424 slurs: Vec<(usize, usize)>,
426}
427
428impl PartBuilt {
429 fn measures(&self) -> usize {
430 self.items
431 .iter()
432 .filter(|(_, item)| matches!(item, PartItem::Measure(_)))
433 .count()
434 }
435
436 fn end(&self) -> FloatType {
437 self.items
438 .iter()
439 .map(|(offset, item)| {
440 offset
441 + match item {
442 PartItem::Measure(measure) => highest_time(&measure.items),
443 PartItem::Instrument(_) => 0.0,
444 }
445 })
446 .fold(0.0, FloatType::max)
447 }
448
449 fn append(&mut self, item: PartItem) {
450 let at = self.end();
451 self.items.push((at, item));
452 }
453}
454
455struct Reader {
456 parts: Vec<PartBuilt>,
457 part: Option<PartBuilt>,
458 measure: MeasureBuilt,
459 measure_number: IntegerType,
460 ending: u32,
461 repeated: Vec<Place>,
465 endings: Vec<(Vec<Place>, u32)>,
467 metadata: Option<Metadata>,
468 clef: ClefState,
469 key: KeySignature,
470 within_slur: bool,
471 slur_start: Option<usize>,
472 within_tie: bool,
473 lyric_position: usize,
474 lyrics: Vec<String>,
475 accidentals: Vec<(String, &'static str)>,
478 serials: usize,
480}
481
482impl Reader {
483 fn new() -> Self {
484 Self {
485 parts: Vec::new(),
486 part: None,
487 measure: MeasureBuilt::new(0),
488 measure_number: 0,
489 ending: 1,
490 repeated: Vec::new(),
491 endings: Vec::new(),
492 metadata: None,
493 clef: ClefState::Treble,
494 key: KeySignature::new(0),
495 within_slur: false,
496 slur_start: None,
497 within_tie: false,
498 lyric_position: 0,
499 lyrics: Vec::new(),
500 accidentals: Vec::new(),
501 serials: 0,
502 }
503 }
504
505 fn part(&mut self) -> Result<&mut PartBuilt> {
506 self.part
507 .as_mut()
508 .ok_or_else(|| error("an object before the first staff"))
509 }
510
511 fn command(&mut self, command: &str, attributes: &Attributes) -> Result<()> {
512 match command {
513 "AddStaff" => self.add_staff(attributes),
514 "Bar" => self.bar(attributes)?,
515 "Chord" => {
516 self.chord(attributes)?;
517 self.lyric_position += 1;
518 }
519 "Clef" => self.clef(attributes)?,
520 "Dynamic" => {
521 if let Some(style) = attributes.get("Style") {
522 self.measure
523 .append(StreamElement::Dynamic(Dynamic::new(style)), None);
524 }
525 }
526 "Ending" => self.ending(attributes)?,
527 "Flow" => self.flow(attributes)?,
528 "Key" => self.key(attributes)?,
529 "Lyric1" => self.lyrics = lyrics(attributes.required("Text")?),
530 "Note" => {
531 self.note(attributes)?;
532 self.lyric_position += 1;
533 }
534 "RestChord" => {
535 self.rest_chord(attributes)?;
536 self.lyric_position += 1;
537 }
538 "Rest" => {
539 let mut rest = Rest::new(Duration::quarter());
540 let serial = self.serial();
541 let duration = self.duration(attributes.required("Dur")?, serial)?;
542 rest.set_duration(duration);
543 self.measure
544 .append_shortest(StreamElement::Rest(rest), Some(serial));
545 }
546 "SongInfo" => {
547 let mut metadata = Metadata::new();
548 if let Some(title) = attributes.get("Title") {
549 metadata.set("title", vec![MetadataValue::new(title)]);
550 }
551 self.metadata = Some(metadata);
552 }
553 "StaffInstrument" => self.staff_instrument(attributes)?,
554 "Tempo" => {
555 let tempo: IntegerType = number(attributes.required("Tempo")?)?;
556 self.measure.insert(
557 0.0,
558 Content::Element(
559 Box::new(StreamElement::MetronomeMark(MetronomeMark::new(
560 FloatType::from(tempo),
561 ))),
562 None,
563 ),
564 );
565 }
566 "Text" => {
567 let mut words = TextExpression::new(attributes.required("Text")?);
568 let position: IntegerType = number(attributes.required("Pos")?)?;
569 words.set_placement(Some(if position < 0 {
570 Placement::Above
571 } else {
572 Placement::Below
573 }));
574 self.measure
575 .append(StreamElement::TextExpression(words), None);
576 }
577 "TimeSig" => {
578 let signature = match attributes.required("Signature")? {
579 "AllaBreve" => "2/2",
580 "Common" => "4/4",
581 other => other,
582 };
583 let meter = crate::meter::TimeSignature::from_ratio_string(signature)?;
584 self.measure
585 .append(StreamElement::TimeSignature(meter), None);
586 }
587 _ => {}
588 }
589 Ok(())
590 }
591
592 fn place(&self) -> Result<Place> {
594 let part = self
595 .part
596 .as_ref()
597 .ok_or_else(|| error("an object before the first staff"))?;
598 Ok(Place {
599 part: self.parts.len(),
600 measure: part.measures(),
601 })
602 }
603
604 fn serial(&mut self) -> usize {
605 self.serials += 1;
606 self.serials - 1
607 }
608
609 fn add_staff(&mut self, attributes: &Attributes) {
610 self.new_part();
611 self.key = KeySignature::new(0);
612 self.accidentals.clear();
613 self.lyrics.clear();
614 self.lyric_position = 0;
615 if let Some(part) = &mut self.part {
616 part.name = attributes.get("Name").map(str::to_string);
617 }
618 }
619
620 fn new_part(&mut self) {
623 let measure = std::mem::replace(&mut self.measure, MeasureBuilt::new(0));
624 if let Some(mut part) = self.part.take() {
625 part.append(PartItem::Measure(measure));
626 self.parts.push(part);
627 }
628 self.part = Some(PartBuilt {
629 name: None,
630 items: Vec::new(),
631 slurs: Vec::new(),
632 });
633 self.measure_number = 0;
634 }
635
636 fn close_measure(&mut self, number: IntegerType) -> Result<()> {
638 let measure = std::mem::replace(&mut self.measure, MeasureBuilt::new(number));
639 self.part()?.append(PartItem::Measure(measure));
640 Ok(())
641 }
642
643 fn bar(&mut self, attributes: &Attributes) -> Result<()> {
644 self.accidentals.clear();
645 let Some(style) = attributes.get("Style") else {
646 self.close_measure(self.measure_number)?;
647 if !self.repeated.is_empty() {
648 let next = self.place()?;
649 self.repeated.push(next);
650 }
651 self.measure_number += 1;
652 return Ok(());
653 };
654 if !self.repeated.is_empty() {
655 let spanned = std::mem::take(&mut self.repeated);
656 self.endings.push((spanned, self.ending));
657 }
658 match style {
659 "MasterRepeatOpen" | "LocalRepeatOpen" => {
660 self.close_measure(0)?;
661 self.measure.left = Some(Barline::repeat(RepeatDirection::Start, None));
662 }
663 "MasterRepeatClose" | "LocalRepeatClose" => {
664 self.measure.right = Some(Barline::repeat(RepeatDirection::End, None));
665 self.close_measure(0)?;
666 }
667 "Double" | "SectionOpen" | "SectionClose" => {
668 self.measure.right = Some(Barline::new(match style {
669 "Double" => BarlineType::Double,
670 "SectionOpen" => BarlineType::HeavyLight,
671 _ => BarlineType::Final,
672 }));
673 self.close_measure(0)?;
674 }
675 other => return Err(error(format!("cannot find a style {other} in our list"))),
676 }
677 self.measure.number = self.measure_number;
678 self.measure_number += 1;
679 Ok(())
680 }
681
682 fn ending(&mut self, attributes: &Attributes) -> Result<()> {
683 let endings = attributes.required("Endings")?;
684 if self.measure.left.is_none() {
685 self.measure.left = Some(Barline::new(BarlineType::Regular));
686 }
687 self.repeated = vec![self.place()?];
688 let first = endings.split(',').next().unwrap_or("");
689 self.ending = number(first)?;
690 Ok(())
691 }
692
693 fn flow(&mut self, attributes: &Attributes) -> Result<()> {
694 let kind = match attributes.required("Style")? {
695 "DCalFine" => RepeatExpressionKind::DaCapoAlFine,
696 "Coda" | "ToCoda" => RepeatExpressionKind::Coda,
697 "Segno" => RepeatExpressionKind::Segno,
698 "DSalCoda" => RepeatExpressionKind::DalSegnoAlCoda,
699 "Fine" => RepeatExpressionKind::Fine,
700 _ => return Err(error("Cannot get style from a flow mark")),
701 };
702 self.measure.append(
703 StreamElement::RepeatExpression(RepeatExpression::new(kind)),
704 None,
705 );
706 Ok(())
707 }
708
709 fn clef(&mut self, attributes: &Attributes) -> Result<()> {
710 let shift = match attributes.get("OctaveShift") {
711 None => 0,
712 Some("Octave Down") => -1,
713 Some("Octave Up") => 1,
714 Some(other) => {
715 return Err(error(format!(
716 "Did not get a proper octave shift from {other}"
717 )));
718 }
719 };
720 let kind = attributes.required("Type")?;
721 let (clef, state) = match (kind, shift) {
722 ("Treble", 0) => (ClefKind::TrebleClef, ClefState::Treble),
723 ("Treble", -1) => (ClefKind::Treble8vbClef, ClefState::TrebleDown),
724 ("Treble", _) => (ClefKind::Treble8vaClef, ClefState::TrebleUp),
725 ("Bass", 0) => (ClefKind::BassClef, ClefState::Bass),
726 ("Bass", -1) => (ClefKind::Bass8vbClef, ClefState::BassDown),
727 ("Bass", _) => (ClefKind::Bass8vaClef, ClefState::BassUp),
728 ("Alto", 0) => (ClefKind::AltoClef, ClefState::Alto),
729 ("Alto", _) => return Err(error("cannot shift octaves on an alto clef")),
730 ("Tenor", 0) => (ClefKind::TenorClef, ClefState::Tenor),
731 ("Tenor", _) => return Err(error("cannot shift octaves on a tenor clef")),
732 ("Percussion", _) => (ClefKind::PercussionClef, ClefState::Percussion),
733 (other, _) => {
734 return Err(error(format!(
735 "Did not find a proper clef in type, {other}"
736 )));
737 }
738 };
739 let mut clef = Clef::of_kind(clef);
740 if state == ClefState::Percussion {
741 clef.set_line(Some(2));
742 }
743 self.measure.append(StreamElement::Clef(clef), None);
744 self.clef = state;
745 Ok(())
746 }
747
748 fn key(&mut self, attributes: &Attributes) -> Result<()> {
749 let signature = attributes.required("Signature")?;
750 let sharps = signature.chars().fold(0, |sharps, mark| match mark {
751 '#' => sharps + 1,
752 'b' => sharps - 1,
753 _ => sharps,
754 });
755 self.key = KeySignature::new(sharps);
756 self.measure
757 .append(StreamElement::KeySignature(self.key.clone()), None);
758 Ok(())
759 }
760
761 fn staff_instrument(&mut self, attributes: &Attributes) -> Result<()> {
762 let patch: IntegerType = attributes.get("Patch").map_or(Ok(0), number)?;
763 let program = u8::try_from(patch).map_err(|_| error(format!("no MIDI program {patch}")))?;
764 let mut instrument = Instrument::from_midi_program(program)?;
765 let transposition: IntegerType = attributes.get("Trans").map_or(Ok(0), number)?;
766 instrument.set_transposition(Some(Interval::from_semitones(transposition)?));
767 self.part()?
768 .append(PartItem::Instrument(Box::new(instrument)));
769 Ok(())
770 }
771
772 fn duration(&mut self, written: &str, serial: usize) -> Result<Duration> {
775 let mut parts = written.split(',');
776 let length = match parts.next().unwrap_or("") {
777 "Whole" => 4.0,
778 "Half" => 2.0,
779 "4th" => 1.0,
780 "8th" => 0.5,
781 "16th" => 0.25,
782 "32nd" => 0.125,
783 "64th" => 0.0625,
784 other => return Err(error(format!("no note length {other}"))),
785 };
786 let mut duration = Duration::new(length)?;
787 let mut slurred = false;
788 for part in written.split(',') {
789 match part {
790 "Grace" => duration = duration.grace_duration(),
791 "Slur" => {
792 if !self.within_slur {
793 self.slur_start = Some(serial);
794 }
795 slurred = true;
796 }
797 "Dotted" => duration = with_dots(&duration, 1),
798 "DblDotted" => duration = with_dots(&duration, 2),
799 "Triplet" | "Triplet=First" | "Triplet=End" => {
800 let value = duration
801 .type_and_dots()
802 .map_or(DurationType::Quarter, |(value, _)| value);
803 duration.append_tuplet(Tuplet::new(3, 2, value, 0));
804 }
805 _ => {}
806 }
807 }
808 if self.within_slur && !slurred {
809 if let (Some(start), Some(part)) = (self.slur_start, self.part.as_mut()) {
810 part.slurs.push((start, serial));
811 }
812 self.within_slur = false;
813 } else {
814 self.within_slur = slurred;
815 }
816 Ok(duration)
817 }
818
819 fn tie(&mut self, position: &str) -> Option<Tie> {
821 if position.ends_with('^') {
822 let begins = !self.within_tie;
823 self.within_tie = true;
824 return begins.then(|| Tie::new(TieType::Start));
825 }
826 if self.within_tie {
827 self.within_tie = false;
828 return Some(Tie::new(TieType::Stop));
829 }
830 None
831 }
832
833 fn pitch(&mut self, position: &str) -> Result<Pitch> {
836 let position = position
837 .trim_end_matches('^')
838 .trim_end_matches('x')
839 .trim_end_matches('X')
840 .trim_end_matches('z');
841 let (accidental, place) = match position.chars().next() {
842 Some('n') => (Some("natural"), &position[1..]),
843 Some('b') => (Some("flat"), &position[1..]),
844 Some('#') => (Some("sharp"), &position[1..]),
845 Some('x') => (Some("double-sharp"), &position[1..]),
846 Some('v') => (Some("double-flat"), &position[1..]),
847 _ => (None, position),
848 };
849 let place: IntegerType = number(place)?;
850 let (mut octave, lowest, steps) = self.clef.table();
851 let mut place = place;
852 while place < lowest || place > lowest + 6 {
853 if place < lowest {
854 place += 7;
855 octave -= 1;
856 }
857 if place > lowest + 6 {
858 place -= 7;
859 octave += 1;
860 }
861 }
862 let step = steps[usize::try_from(place - lowest).unwrap_or(0)];
863 let name = format!("{step}{octave}");
864 let mut pitch = Pitch::from_name(&name)?;
865 if let Some(accidental) = accidental {
866 pitch.set_accidental(Accidental::new(accidental)?);
867 self.accidentals.retain(|(written, _)| written != &name);
868 self.accidentals.push((name, accidental));
869 } else if let Some((_, accidental)) = self
870 .accidentals
871 .iter()
872 .find(|(written, _)| written == &name)
873 {
874 pitch.set_accidental(Accidental::new(*accidental)?);
875 } else if let Some(accidental) = self.key.accidental_by_step(step)? {
876 pitch.set_accidental(accidental);
877 }
878 Ok(pitch)
879 }
880
881 fn lyric(&self) -> Option<&str> {
882 self.lyrics.get(self.lyric_position).map(String::as_str)
883 }
884
885 fn note(&mut self, attributes: &Attributes) -> Result<()> {
886 let written = attributes.required("Dur")?;
887 let position = attributes.required("Pos")?;
888 let pitch = self.pitch(position)?;
889 let serial = self.serial();
890 let duration = self.duration(written, serial)?;
891 let tie = self.tie(position);
892 let lyric = self.lyric().map(str::to_string);
893 let element = if self.clef == ClefState::Percussion {
894 let octave = pitch.octave().unwrap_or(4);
895 let step = pitch.step().as_char();
896 let mut stroke = Unpitched::displayed_at(step, octave)?;
897 let note = stroke.written_mut();
898 note.set_duration(duration);
899 if tie.is_some() {
900 note.set_tie(tie);
901 }
902 if let Some(lyric) = lyric {
903 note.add_lyric(&lyric, None, false)?;
904 }
905 StreamElement::Unpitched(stroke)
906 } else {
907 let mut note = Note::from_pitch(pitch).with_duration(duration);
908 if tie.is_some() {
909 note.set_tie(tie);
910 }
911 if let Some(lyric) = lyric {
912 note.add_lyric(&lyric, None, false)?;
913 }
914 StreamElement::Note(note)
915 };
916 self.measure.append_shortest(element, Some(serial));
917 Ok(())
918 }
919
920 fn chord(&mut self, attributes: &Attributes) -> Result<()> {
923 attributes.required("Dur")?;
924 attributes.required("Pos")?;
925 let mut groups: Vec<(String, String)> = attributes
926 .list("Dur")
927 .into_iter()
928 .zip(attributes.list("Pos"))
929 .collect();
930 if let Some(written) = attributes.get("Dur2") {
931 groups.push((
932 written.to_string(),
933 attributes.required("Pos2")?.to_string(),
934 ));
935 }
936 let mut chords = Vec::new();
937 for (written, position) in &groups {
938 chords.push(self.chord_of(written, position)?);
939 }
940 self.simultaneous(chords)
941 }
942
943 fn rest_chord(&mut self, attributes: &Attributes) -> Result<()> {
946 let chord = self.chord_of(attributes.required("Dur2")?, attributes.required("Pos2")?)?;
947 let serial = self.serial();
948 let mut rest = Rest::new(Duration::quarter());
949 rest.set_duration(self.duration(attributes.required("Dur")?, serial)?);
950 self.simultaneous(vec![chord, (StreamElement::Rest(rest), serial)])
951 }
952
953 fn chord_of(&mut self, written: &str, position: &str) -> Result<(StreamElement, usize)> {
955 let serial = self.serial();
956 let duration = self.duration(written, serial)?;
957 let mut pitches = Vec::new();
958 for one in position.split(',') {
959 pitches.push(self.pitch(one)?);
960 }
961 let notes: Vec<Note> = pitches.into_iter().map(Note::from_pitch).collect();
962 let mut chord = Chord::new(notes)?.with_duration(duration);
963 if let Some(tie) = self.tie(position) {
964 for note in chord.notes_mut() {
965 note.set_tie(Some(tie.clone()));
966 }
967 }
968 Ok((StreamElement::Chord(chord), serial))
969 }
970
971 fn simultaneous(&mut self, mut elements: Vec<(StreamElement, usize)>) -> Result<()> {
974 if let Some(lyric) = self.lyric().map(str::to_string) {
975 if let StreamElement::Chord(chord) = &mut elements[0].0 {
977 chord.add_lyric(&lyric, None, false)?;
978 }
979 }
980 if elements.len() == 1 {
981 let (element, serial) = elements.remove(0);
982 self.measure.append_shortest(element, Some(serial));
983 } else {
984 self.measure.append_in_voices(elements);
985 }
986 Ok(())
987 }
988
989 fn finish(mut self) -> Result<Stream> {
990 let measure = std::mem::replace(&mut self.measure, MeasureBuilt::new(0));
991 let mut part = self
992 .part
993 .take()
994 .ok_or_else(|| error("a file with no staff"))?;
995 if measure.holds_anything() {
996 part.append(PartItem::Measure(measure));
997 }
998 self.parts.push(part);
999
1000 let mut score = Stream::with_kind(StreamKind::Score);
1001 if let Some(metadata) = self.metadata {
1002 score.set_metadata(Some(metadata));
1003 }
1004 for (index, part) in self.parts.into_iter().enumerate() {
1005 score.insert(0.0, assemble(part, index, &self.endings));
1006 }
1007 Ok(score)
1008 }
1009}
1010
1011fn with_dots(duration: &Duration, dots: u32) -> Duration {
1014 let Some((value, _)) = duration.type_and_dots() else {
1015 return duration.clone();
1016 };
1017 let mut dotted = Duration::from_type_with_dots(value, dots);
1018 dotted.set_tuplets(duration.tuplets());
1019 dotted.set_grace(duration.grace().cloned());
1020 dotted.set_expression_is_inferred(duration.expression_is_inferred());
1021 dotted
1022}
1023
1024fn number<T: std::str::FromStr>(text: &str) -> Result<T> {
1026 text.trim()
1027 .parse()
1028 .map_err(|_| error(format!("{text} is not a number")))
1029}
1030
1031fn lyrics(text: &str) -> Vec<String> {
1034 let text = text
1035 .trim_matches('"')
1036 .replace("\r\n", " ")
1037 .replace(['\r', '\n'], " ");
1038 let mut syllables = Vec::new();
1039 for word in text.split(' ') {
1040 let mut first = true;
1041 for part in word.split('-') {
1042 for piece in part.split('\n') {
1043 let syllable = if piece.is_empty() {
1044 " - ".to_string()
1045 } else if first {
1046 piece.to_string()
1047 } else {
1048 format!(" -{piece}")
1049 };
1050 first = false;
1051 syllables.push(syllable);
1052 }
1053 }
1054 }
1055 syllables
1056}
1057
1058#[derive(Clone, Copy, PartialEq, Eq)]
1061struct Place {
1062 part: usize,
1063 measure: usize,
1064}
1065
1066fn assemble(part: PartBuilt, index: usize, endings: &[(Vec<Place>, u32)]) -> Stream {
1070 let mut stream = Stream::with_kind(StreamKind::Part);
1071 stream.set_name(part.name.clone());
1072 stream.set_abbreviation(part.name.clone());
1073 let mut places: Vec<(usize, usize)> = Vec::new();
1075 let mut leaves = 0;
1076 let mut measures = 0;
1077 for (offset, item) in part.items {
1078 match item {
1079 PartItem::Instrument(instrument) => {
1080 stream.insert(offset, StreamElement::Instrument(instrument));
1081 leaves += 1;
1082 }
1083 PartItem::Measure(built) => {
1084 let mut measure = Stream::with_kind(StreamKind::Measure);
1085 measure.set_number(built.number);
1086 measure.set_left_barline(built.left);
1087 measure.set_right_barline(built.right);
1088 let here = Place {
1090 part: index,
1091 measure: measures,
1092 };
1093 if let Some((spanned, number)) = endings.iter().find(|(spanned, _)| {
1094 spanned.first() == Some(&here) || spanned.last() == Some(&here)
1095 }) {
1096 measure.set_ending(Some(Ending::new(
1097 vec![*number],
1098 spanned.first() == Some(&here),
1099 spanned.last() == Some(&here),
1100 )));
1101 }
1102 for place in sorted_places(&built.items) {
1103 let item = &built.items[place];
1104 match &item.content {
1105 Content::Element(element, serial) => {
1106 if let Some(serial) = serial {
1107 places.push((*serial, leaves));
1108 }
1109 leaves += 1;
1110 measure.insert(item.offset, (**element).clone());
1111 }
1112 Content::Voice(voice) => {
1113 let mut inner = Stream::with_kind(StreamKind::Voice);
1114 inner.set_id(Some(voice.id.to_string()));
1115 for place in sorted_places(&voice.items) {
1116 let held = &voice.items[place];
1117 if let Content::Element(element, serial) = &held.content {
1118 if let Some(serial) = serial {
1119 places.push((*serial, leaves));
1120 }
1121 leaves += 1;
1122 inner.insert(held.offset, (**element).clone());
1123 }
1124 }
1125 measure.insert(item.offset, inner);
1126 }
1127 }
1128 }
1129 stream.insert(offset, measure);
1130 measures += 1;
1131 }
1132 }
1133 }
1134 let place_of = |serial: usize| {
1135 places
1136 .iter()
1137 .find(|(read, _)| *read == serial)
1138 .map(|(_, place)| *place)
1139 };
1140 for (start, end) in part.slurs {
1141 stream.add_spanner(Spanner::with_unplaced(
1142 crate::spanner::SpannerKind::Slur,
1143 vec![place_of(start), place_of(end)],
1144 ));
1145 }
1146 stream
1147}
1148
1149#[cfg(test)]
1150mod tests {
1151 use super::*;
1152
1153 #[test]
1154 fn a_refusal_says_its_line() {
1155 let text = "!NoteWorthyComposer(2.0)\n|AddStaff|\n|Clef|Type:Bass\n\
1156 |Note|Dur:Whole|Pos:1\n|Note|Dur:Eon|Pos:2\n";
1157 let error = from_noteworthy(text).unwrap_err();
1158 assert_eq!(error.to_string(), "NoteWorthy error: no note length Eon");
1159 assert_eq!(error.position(), Some(&Position::line(5)));
1160
1161 let error = from_noteworthy("|AddStaff|\n|Note|Dur:4th|Pos:x\n").unwrap_err();
1162 assert_eq!(error.position(), Some(&Position::line(2)));
1163 }
1164
1165 fn names(score: &Stream) -> Vec<String> {
1166 score
1167 .pitches()
1168 .iter()
1169 .map(|pitch| pitch.name_with_octave())
1170 .collect()
1171 }
1172
1173 #[test]
1174 fn a_note_is_spelled_from_its_place_under_the_clef() {
1175 let score = from_noteworthy(
1176 "|AddStaff|\n|Clef|Type:Bass\n|Note|Dur:4th|Pos:b3\n|Note|Dur:4th|Pos:3\n|Bar\n|Note|Dur:4th|Pos:3\n",
1177 )
1178 .unwrap();
1179 assert_eq!(names(&score), ["Gb3", "Gb3", "G3"]);
1181 }
1182
1183 #[test]
1184 fn a_key_signature_spells_the_notes_after_it() {
1185 let score = from_noteworthy(
1186 "|AddStaff|\n|Key|Signature:F#,C#,G#,D#\n|Chord|Dur:Half|Pos:1,3,#5\n|Chord|Dur:Half|Pos:1,3,5\n",
1187 )
1188 .unwrap();
1189 assert_eq!(names(&score), ["C#5", "E5", "G#5", "C#5", "E5", "G#5"]);
1190 }
1191
1192 #[test]
1193 fn the_first_two_measures_are_both_numbered_nought() {
1194 let score =
1195 from_noteworthy("|AddStaff|\n|Note|Dur:Whole|Pos:1\n|Bar\n|Note|Dur:Whole|Pos:1\n|Bar\n|Note|Dur:Whole|Pos:1\n")
1196 .unwrap();
1197 let numbers: Vec<IntegerType> = score.parts()[0]
1198 .measures()
1199 .iter()
1200 .map(|measure| measure.number())
1201 .collect();
1202 assert_eq!(numbers, [0, 0, 1]);
1203 }
1204
1205 #[test]
1206 fn a_verse_is_split_into_syllables() {
1207 assert_eq!(lyrics("\"Hello world\""), ["Hello", "world"]);
1208 assert_eq!(
1209 lyrics("\"A-ve Ma-ri-a\""),
1210 ["A", " -ve", "Ma", " -ri", " -a"]
1211 );
1212 }
1213
1214 #[test]
1215 fn a_line_with_an_attribute_and_no_value_is_refused() {
1216 assert!(from_noteworthy("|AddStaff|\n|Note|Dur\n").is_err());
1217 assert!(from_noteworthy("|Note|Dur:4th|Pos:1\n").is_err());
1218 }
1219
1220 fn first_measure(lines: &str) -> Vec<(FloatType, FloatType, String)> {
1223 let score = from_noteworthy(&format!("|AddStaff|\n|Clef|Type:Treble\n{lines}")).unwrap();
1224 let mut out: Vec<(FloatType, FloatType, String)> = score.parts()[0].measures()[0]
1225 .leaves()
1226 .into_iter()
1227 .filter_map(|(offset, element)| {
1228 let sounds = match element {
1229 StreamElement::Note(note) => note.pitch().name_with_octave(),
1230 StreamElement::Chord(chord) => chord
1231 .notes()
1232 .iter()
1233 .map(|note| note.pitch().name_with_octave())
1234 .collect::<Vec<_>>()
1235 .join(" "),
1236 StreamElement::Rest(_) => "rest".to_string(),
1237 _ => return None,
1238 };
1239 Some((offset, element.quarter_length(), sounds))
1240 })
1241 .collect();
1242 out.sort_by(|left, right| left.partial_cmp(right).unwrap());
1243 out
1244 }
1245
1246 #[test]
1247 fn a_chord_of_two_lengths_is_two_chords_starting_together() {
1248 assert_eq!(
1249 first_measure(
1250 "|Note|Dur:4th|Pos:0\n\
1251 |Chord|Dur:8th|Pos:-4,n-3,b-2,#-1,x0,v1,2x|Opts:Stem=Down|Dur2:8th,DblDotted|Pos2:3x\n\
1252 |Note|Dur:4th|Pos:-5\n"
1253 ),
1254 [
1255 (0.0, 1.0, "B4".to_string()),
1256 (1.0, 0.5, "E4 F4 Gb4 A#4 B##4 Cbb5 D5".to_string()),
1257 (1.0, 0.875, "E5".to_string()),
1258 (1.5, 1.0, "D4".to_string()),
1259 ]
1260 );
1261 }
1262
1263 #[test]
1264 fn a_rest_chord_is_a_rest_and_a_chord_starting_together() {
1265 assert_eq!(
1266 first_measure(
1267 "|Note|Dur:4th|Pos:0\n\
1268 |RestChord|Dur:Half|Opts:Stem=Up|Dur2:4th|Pos2:-1,1\n\
1269 |RestChord|Dur:4th|Dur2:4th|Pos2:-5\n\
1270 |Note|Dur:4th|Pos:0\n"
1271 ),
1272 [
1273 (0.0, 1.0, "B4".to_string()),
1274 (1.0, 1.0, "A4 C5".to_string()),
1275 (1.0, 2.0, "rest".to_string()),
1276 (2.0, 1.0, "D4".to_string()),
1277 (2.0, 1.0, "rest".to_string()),
1278 (3.0, 1.0, "B4".to_string()),
1279 ]
1280 );
1281 }
1282}