1use crate::chord::Chord;
12use crate::clef::Clef;
13use crate::defaults::FloatType;
14use crate::duration::Duration;
15use crate::error::{Error, Result};
16use crate::figuredbass::Notation;
17use crate::figuredbass::rules::Rules;
18use crate::figuredbass::scale::{FiguredBassMode, FiguredBassScale};
19use crate::figuredbass::segment::{Possibility, Segment};
20use crate::key::{Key, KeySignature};
21use crate::makenotation::{make_part_notation_by, op_frac};
22use crate::meter::TimeSignature;
23use crate::note::Note;
24use crate::pitch::Pitch;
25use crate::stream::{Stream, StreamElement, StreamKind};
26
27#[derive(Clone, Debug, PartialEq)]
29enum Element {
30 Figured {
32 bass: Pitch,
33 quarter_length: FloatType,
34 notation: Option<String>,
35 },
36 Named {
39 bass: Pitch,
40 quarter_length: FloatType,
41 pitch_names: Vec<String>,
42 },
43}
44
45#[derive(Clone, Debug, PartialEq)]
48struct Sounding {
49 offset: FloatType,
50 quarter_length: FloatType,
51 pitch: Option<Pitch>,
52}
53
54impl Sounding {
55 fn end(&self) -> FloatType {
56 op_frac(self.offset + self.quarter_length)
57 }
58}
59
60#[derive(Clone, Debug)]
63struct Piece {
64 offset: FloatType,
65 note: Note,
66 notation: Option<String>,
67}
68
69impl Piece {
70 fn quarter_length(&self) -> FloatType {
71 self.note.duration().map_or(1.0, Duration::quarter_length)
72 }
73}
74
75#[derive(Clone, Copy, Debug, PartialEq)]
77enum Voice {
78 Upper(usize, usize),
81 Bass(usize),
83}
84
85type Moment = ((FloatType, FloatType), Vec<Voice>);
88
89#[derive(Clone, Debug, PartialEq)]
105#[must_use]
106pub struct FiguredBassLine {
107 scale: FiguredBassScale,
108 key_signature: KeySignature,
109 time: TimeSignature,
110 elements: Vec<Element>,
111 overlaid: Vec<Vec<Sounding>>,
112}
113
114impl Default for FiguredBassLine {
115 fn default() -> Self {
117 Self::new(FiguredBassScale::default())
118 }
119}
120
121fn common_time() -> TimeSignature {
123 TimeSignature::new(4, 4).expect("four quarters make a bar")
124}
125
126impl FiguredBassLine {
127 pub fn new(scale: FiguredBassScale) -> Self {
129 Self {
130 key_signature: scale.key_signature().clone(),
131 scale,
132 time: common_time(),
133 elements: Vec::new(),
134 overlaid: Vec::new(),
135 }
136 }
137
138 pub fn in_key(key: &Key) -> Result<Self> {
145 let tonic = key.pitch_from_degree(1)?;
146 let mode = FiguredBassMode::from_name(key.mode())?;
147 Ok(Self::new(FiguredBassScale::new(tonic, mode)?))
148 }
149
150 pub fn in_key_and_time(key: &Key, time: TimeSignature) -> Result<Self> {
157 let mut line = Self::in_key(key)?;
158 line.time = time;
159 Ok(line)
160 }
161
162 pub fn scale(&self) -> &FiguredBassScale {
164 &self.scale
165 }
166
167 pub fn time_signature(&self) -> &TimeSignature {
169 &self.time
170 }
171
172 pub fn set_time_signature(&mut self, time: TimeSignature) {
174 self.time = time;
175 }
176
177 pub fn key_signature(&self) -> &KeySignature {
179 &self.key_signature
180 }
181
182 pub fn set_key_signature(&mut self, key_signature: KeySignature) {
186 self.key_signature = key_signature;
187 }
188
189 pub fn add_element(&mut self, bass: Pitch, quarter_length: FloatType, notation: Option<&str>) {
192 self.elements.push(Element::Figured {
193 bass,
194 quarter_length,
195 notation: notation.map(str::to_string),
196 });
197 }
198
199 pub fn add_chord(&mut self, bass: Pitch, quarter_length: FloatType, pitch_names: Vec<String>) {
204 self.elements.push(Element::Named {
205 bass,
206 quarter_length: if quarter_length == 0.0 {
207 1.0
208 } else {
209 quarter_length
210 },
211 pitch_names,
212 });
213 }
214
215 pub fn len(&self) -> usize {
217 self.elements.len()
218 }
219
220 pub fn is_empty(&self) -> bool {
222 self.elements.is_empty()
223 }
224
225 pub fn overlay_part(&mut self, part: &Stream) {
237 let flat = part.flatten();
238 let mut sounding: Vec<Sounding> = flat
239 .events()
240 .iter()
241 .filter_map(|event| {
242 let pitch = match event.element() {
243 StreamElement::Note(note) => Some(note.pitch().clone()),
244 StreamElement::Chord(_)
245 | StreamElement::Rest(_)
246 | StreamElement::Unpitched(_)
247 | StreamElement::PercussionChord(_)
248 | StreamElement::ChordSymbol(_) => None,
249 _ => return None,
250 };
251 Some(Sounding {
252 offset: event.offset(),
253 quarter_length: event.element().quarter_length(),
254 pitch,
255 })
256 })
257 .collect();
258 sounding.sort_by(|left, right| left.offset.total_cmp(&right.offset));
259 self.overlaid.push(sounding);
260 }
261
262 pub fn generate_bass_line(&self) -> Result<Stream> {
288 let mut line = Stream::with_kind(StreamKind::Part);
289 line.push(Clef::bass());
290 line.push(self.key_signature.clone());
291 line.push(self.time.clone());
292 for element in &self.elements {
293 let Element::Figured {
294 bass,
295 quarter_length,
296 notation,
297 } = element
298 else {
299 return Err(Error::FiguredBass(
300 "a bass line is written from bass notes and their figures, not from chords"
301 .to_string(),
302 ));
303 };
304 line.push(bass_note(bass, *quarter_length, notation.as_deref())?);
305 }
306 notated(&line)
307 }
308
309 fn pieces(&self) -> Result<Vec<Piece>> {
312 let mut spans: Vec<(FloatType, FloatType, Option<&str>)> = Vec::new();
314 let mut start = 0.0;
315 for element in &self.elements {
316 if let Element::Figured {
317 quarter_length,
318 notation,
319 ..
320 } = element
321 {
322 let stop = op_frac(start + quarter_length);
323 spans.push((start, stop, notation.as_deref()));
324 start = stop;
325 }
326 }
327 let written = self.generate_bass_line()?.flatten();
328 Ok(written
329 .events()
330 .iter()
331 .filter_map(|event| match event.element() {
332 StreamElement::Note(note) => {
333 let offset = event.offset();
334 let notation = spans
335 .iter()
336 .find(|(start, stop, _)| *start <= offset + 1e-9 && offset < stop - 1e-9)
337 .or(spans.last())
338 .and_then(|(_, _, notation)| *notation);
339 Some(Piece {
340 offset,
341 note: note.clone(),
342 notation: notation.map(str::to_string),
343 })
344 }
345 _ => None,
346 })
347 .collect())
348 }
349
350 fn moments(&self, pieces: &[Piece]) -> Vec<Moment> {
354 let bass: Vec<(Sounding, Voice)> = pieces
355 .iter()
356 .enumerate()
357 .map(|(index, piece)| {
358 let sounding = Sounding {
359 offset: piece.offset,
360 quarter_length: piece.quarter_length(),
361 pitch: None,
362 };
363 (sounding, Voice::Bass(index))
364 })
365 .collect();
366 let mut parts: Vec<Vec<(Sounding, Voice)>> = self
367 .overlaid
368 .iter()
369 .enumerate()
370 .map(|(part, sounding)| {
371 sounding
372 .iter()
373 .enumerate()
374 .map(|(index, each)| (each.clone(), Voice::Upper(part, index)))
375 .collect()
376 })
377 .collect();
378 parts.push(bass);
379
380 let mut moments: Vec<Moment> = Vec::new();
383 for (sounding, voice) in &parts[0] {
384 let key = (sounding.offset, sounding.end());
385 match moments.iter_mut().find(|(held, _)| *held == key) {
386 Some((_, voices)) => voices.push(*voice),
387 None => moments.push((key, vec![*voice])),
388 }
389 }
390 for part in &parts[1..] {
392 moments.sort_by(|left, right| compare_spans(left.0, right.0));
393 let mut cut: Vec<Moment> = Vec::new();
394 for ((start, end), voices) in &moments {
395 for (sounding, voice) in part {
396 if !overlaps(sounding, *start, *end) {
397 continue;
398 }
399 let begins = if sounding.offset < *start {
400 *start
401 } else {
402 sounding.offset
403 };
404 let ends = if sounding.offset + sounding.quarter_length > *end {
405 *end
406 } else {
407 sounding.end()
408 };
409 let mut together = voices.clone();
410 together.push(*voice);
411 match cut.iter_mut().find(|(held, _)| *held == (begins, ends)) {
412 Some((_, held)) => *held = together,
413 None => cut.push(((begins, ends), together)),
414 }
415 }
416 }
417 moments = cut;
418 }
419 moments.sort_by(|left, right| compare_spans(left.0, right.0));
420 moments
421 }
422
423 pub fn segments(
437 &self,
438 rules: &Rules,
439 num_parts: usize,
440 max_pitch: &Pitch,
441 ) -> Result<Vec<Segment>> {
442 Ok(self
443 .written_segments(rules, num_parts, max_pitch)?
444 .into_iter()
445 .map(|(segment, _)| segment)
446 .collect())
447 }
448
449 fn written_segments(
452 &self,
453 rules: &Rules,
454 num_parts: usize,
455 max_pitch: &Pitch,
456 ) -> Result<Vec<(Segment, Note)>> {
457 if self.elements.is_empty() {
458 return Ok(Vec::new());
459 }
460 if self
463 .elements
464 .iter()
465 .any(|element| matches!(element, Element::Named { .. }))
466 {
467 return self
468 .elements
469 .iter()
470 .map(|element| match element {
471 Element::Figured {
472 bass,
473 quarter_length,
474 notation,
475 } => Ok((
476 Segment::new(
477 bass.clone(),
478 *quarter_length,
479 &Notation::parse(notation.as_deref().unwrap_or(""))?,
480 &self.scale,
481 rules.clone(),
482 num_parts,
483 max_pitch.clone(),
484 )?
485 .overlaid(),
486 bass_note(bass, *quarter_length, notation.as_deref())?,
487 )),
488 Element::Named {
489 bass,
490 quarter_length,
491 pitch_names,
492 } => Ok((
493 Segment::from_pitch_names(
494 bass.clone(),
495 *quarter_length,
496 pitch_names.clone(),
497 rules.clone(),
498 num_parts,
499 max_pitch.clone(),
500 )?,
501 Note::from_pitch(Pitch::from_name(bass.name_with_octave())?)
502 .with_duration(Duration::new(*quarter_length)?),
503 )),
504 })
505 .collect();
506 }
507
508 let pieces = self.pieces()?;
509 let moments = self.moments(&pieces);
510 let segment_of = |piece: &Piece, quarter_length: FloatType| -> Result<Segment> {
511 Ok(Segment::new(
512 piece.note.pitch().clone(),
513 quarter_length,
514 &Notation::parse(piece.notation.as_deref().unwrap_or(""))?,
515 &self.scale,
516 rules.clone(),
517 num_parts,
518 max_pitch.clone(),
519 )?
520 .overlaid())
521 };
522 let bass_of = |voices: &[Voice]| -> Result<usize> {
523 match voices.last() {
524 Some(Voice::Bass(index)) => Ok(*index),
525 _ => Err(Error::FiguredBass(
526 "a moment of the line has no bass note".to_string(),
527 )),
528 }
529 };
530
531 let mut made: Vec<(Segment, Note)> = Vec::new();
532 let Some((_, first)) = moments.first() else {
533 return Ok(made);
534 };
535 let first = &pieces[bass_of(first)?];
536 made.push((
537 segment_of(first, pieces[0].quarter_length())?,
538 first.note.clone(),
539 ));
540 let mut reached = 0;
542 for ((start, _), voices) in &moments[1..] {
543 let piece = &pieces[bass_of(voices)?];
544 let before = &pieces[reached];
545 let quarter_length = if *start == op_frac(before.offset + before.quarter_length()) {
546 reached += 1;
547 let Some(next) = pieces.get(reached) else {
548 return Err(Error::FiguredBass(
549 "the parts laid over the line run past its last bass note".to_string(),
550 ));
551 };
552 next.quarter_length()
553 } else {
554 if let Some((previous, _)) = made.last_mut() {
557 previous
558 .rules
559 .parts_to_check
560 .extend(voices.len()..=num_parts);
561 }
562 0.0
563 };
564 let mut segment = segment_of(piece, quarter_length)?;
565 for (number, voice) in voices[..voices.len() - 1].iter().enumerate() {
566 let Voice::Upper(part, index) = voice else {
567 continue;
568 };
569 let Some(pitch) = self.overlaid[*part][*index].pitch.clone() else {
570 return Err(Error::FiguredBass(
571 "only a note of a part laid over the line can hold a part to its pitch"
572 .to_string(),
573 ));
574 };
575 segment.rules.part_pitch_limits.push((number + 1, pitch));
576 }
577 made.push((segment, piece.note.clone()));
578 }
579 Ok(made)
580 }
581
582 pub fn realize(
590 &self,
591 rules: &Rules,
592 num_parts: usize,
593 max_pitch: &Pitch,
594 ) -> Result<Realization> {
595 if self.elements.is_empty() {
596 return Err(Error::FiguredBass(
597 "No (bassNote, notationString) pairs to realize.".to_string(),
598 ));
599 }
600 let (segments, bass_notes) = self
601 .written_segments(rules, num_parts, max_pitch)?
602 .into_iter()
603 .unzip();
604 let mut realization = Realization::of(segments)?;
605 realization.key_signature = self.key_signature.clone();
606 realization.time = self.time.clone();
607 realization.bass_notes = bass_notes;
608 Ok(realization)
609 }
610}
611
612fn compare_spans(
614 left: (FloatType, FloatType),
615 right: (FloatType, FloatType),
616) -> std::cmp::Ordering {
617 left.0.total_cmp(&right.0).then(left.1.total_cmp(&right.1))
618}
619
620fn overlaps(sounding: &Sounding, start: FloatType, end: FloatType) -> bool {
624 let stop = sounding.end();
625 if sounding.offset > end || stop < start {
626 return false;
627 }
628 if start == end && sounding.quarter_length == 0.0 {
629 return true;
630 }
631 sounding.offset != end && stop != start
632}
633
634fn bass_note(bass: &Pitch, quarter_length: FloatType, notation: Option<&str>) -> Result<Note> {
637 let mut note = Note::from_pitch(bass.clone()).with_duration(Duration::new(quarter_length)?);
638 let notation = Notation::parse(notation.unwrap_or(""))?;
639 let figures = notation.figure_strings();
640 let width = figures
641 .iter()
642 .map(|figure| figure.chars().count())
643 .max()
644 .unwrap_or(0);
645 for figure in figures {
646 note.add_lyric(&format!("{figure:>width$}"), None, true)?;
647 }
648 Ok(note)
649}
650
651fn notated(part: &Stream) -> Result<Stream> {
655 let mut made = part.clone();
656 make_part_notation_by(&mut made, false)?;
657 Ok(made)
658}
659
660type Movements = Vec<(Possibility, Vec<Possibility>)>;
663
664#[derive(Clone, Debug)]
666#[must_use]
667pub struct Realization {
668 segments: Vec<Segment>,
669 movements: Vec<Movements>,
671 single: Vec<Possibility>,
673 fallbacks: Vec<String>,
675 key_signature: KeySignature,
677 time: TimeSignature,
678 bass_notes: Vec<Note>,
680 keyboard_style: bool,
681}
682
683impl Realization {
684 pub fn of(mut segments: Vec<Segment>) -> Result<Self> {
693 if segments.is_empty() {
694 return Err(Error::FiguredBass(
695 "No (bassNote, notationString) pairs to realize.".to_string(),
696 ));
697 }
698 let mut movements: Vec<Movements> = Vec::new();
699 let mut fallbacks = Vec::new();
700 let mut single = Vec::new();
701 if segments.len() == 1 {
702 single = segments[0].all_correct_single_possibilities()?;
703 }
704 for index in 0..segments.len().saturating_sub(1) {
705 let (before, after) = segments.split_at_mut(index + 1);
706 let found = before[index].all_correct_consecutive_possibilities(&mut after[0])?;
707 fallbacks.extend(found.fallback);
708 let mut moves: Movements = Vec::new();
709 for (from, to) in found.pairs {
710 match moves.iter_mut().find(|(known, _)| *known == from) {
711 Some((_, targets)) => targets.push(to),
712 None => moves.push((from, vec![to])),
713 }
714 }
715 movements.push(moves);
716 }
717 trim(&mut movements);
718 let bass_notes = segments
719 .iter()
720 .map(|segment| {
721 Ok(Note::from_pitch(segment.bass().clone())
722 .with_duration(Duration::new(segment.quarter_length())?))
723 })
724 .collect::<Result<Vec<Note>>>()?;
725 Ok(Self {
726 segments,
727 movements,
728 single,
729 fallbacks,
730 key_signature: KeySignature::new(0),
731 time: common_time(),
732 bass_notes,
733 keyboard_style: true,
734 })
735 }
736
737 pub fn segments(&self) -> &[Segment] {
739 &self.segments
740 }
741
742 pub fn fallbacks(&self) -> &[String] {
745 &self.fallbacks
746 }
747
748 pub fn num_solutions(&self) -> usize {
751 if self.segments.len() == 1 {
752 return self.single.len();
753 }
754 let mut paths: Vec<(&Possibility, usize)> = Vec::new();
755 for (depth, moves) in self.movements.iter().rev().enumerate() {
756 paths = moves
757 .iter()
758 .map(|(from, targets)| {
759 let count = if depth == 0 {
760 targets.len()
761 } else {
762 targets
763 .iter()
764 .map(|target| {
765 paths
766 .iter()
767 .find(|(known, _)| *known == target)
768 .map_or(0, |(_, count)| *count)
769 })
770 .sum()
771 };
772 (from, count)
773 })
774 .collect();
775 }
776 paths.iter().map(|(_, count)| count).sum()
777 }
778
779 pub fn all_possibility_progressions(&self) -> Vec<Vec<Possibility>> {
782 if self.segments.len() == 1 {
783 return self
784 .single
785 .iter()
786 .map(|voicing| vec![voicing.clone()])
787 .collect();
788 }
789 let Some(first) = self.movements.first() else {
790 return Vec::new();
791 };
792 let mut progressions: Vec<Vec<Possibility>> = first
793 .iter()
794 .flat_map(|(from, targets)| {
795 targets
796 .iter()
797 .map(move |target| vec![from.clone(), target.clone()])
798 })
799 .collect();
800 for moves in &self.movements[1..] {
801 progressions = progressions
802 .into_iter()
803 .flat_map(|progression| {
804 let last = progression.last().cloned().unwrap_or_default();
805 moves
806 .iter()
807 .find(|(from, _)| *from == last)
808 .map(|(_, targets)| targets.clone())
809 .unwrap_or_default()
810 .into_iter()
811 .map(move |target| {
812 let mut longer = progression.clone();
813 longer.push(target);
814 longer
815 })
816 })
817 .collect();
818 }
819 progressions
820 }
821
822 pub fn possibility_progression_by(
831 &self,
832 mut choose: impl FnMut(usize) -> usize,
833 ) -> Result<Vec<Possibility>> {
834 let mut pick = |options: &[Possibility]| -> Result<Possibility> {
835 let index = choose(options.len());
836 options.get(index).cloned().ok_or_else(|| {
837 Error::FiguredBass(format!("no voicing {index} of {}", options.len()))
838 })
839 };
840 if self.segments.len() == 1 {
841 return Ok(vec![pick(&self.single)?]);
842 }
843 if self.num_solutions() == 0 {
844 return Err(Error::FiguredBass("Zero solutions".to_string()));
845 }
846 let firsts: Vec<Possibility> = self.movements[0]
847 .iter()
848 .map(|(from, _)| from.clone())
849 .collect();
850 let mut previous = pick(&firsts)?;
851 let mut progression = vec![previous.clone()];
852 for moves in &self.movements {
853 let targets = moves
854 .iter()
855 .find(|(from, _)| *from == previous)
856 .map(|(_, targets)| targets.as_slice())
857 .unwrap_or_default();
858 previous = pick(targets)?;
859 progression.push(previous.clone());
860 }
861 Ok(progression)
862 }
863
864 pub fn keyboard_style_output(&self) -> bool {
869 self.keyboard_style
870 }
871
872 pub fn set_keyboard_style_output(&mut self, keyboard_style: bool) {
875 self.keyboard_style = keyboard_style;
876 }
877
878 pub fn generate_realization_from_possibility_progression(
910 &self,
911 progression: &[Possibility],
912 ) -> Result<Stream> {
913 if progression.len() < self.segments.len() {
914 return Err(Error::FiguredBass(format!(
915 "a progression of {} voicings does not voice a line of {} segments",
916 progression.len(),
917 self.segments.len()
918 )));
919 }
920 let opening = |part: &mut Stream| {
921 part.push(self.key_signature.clone());
922 part.push(self.time.clone());
923 };
924 let mut score = Stream::with_kind(StreamKind::Score);
925
926 let mut bass = Stream::with_kind(StreamKind::Part);
927 opening(&mut bass);
928 for note in &self.bass_notes {
929 bass.push(note.clone());
930 }
931 bass.insert(0.0, Clef::bass());
932
933 if self.keyboard_style {
934 let mut right = Stream::with_kind(StreamKind::Part);
935 opening(&mut right);
936 for (segment, voicing) in self.segments.iter().zip(progression) {
937 let upper = &voicing[..voicing.len().saturating_sub(1)];
938 let chord =
939 Chord::new(upper)?.with_duration(Duration::new(segment.quarter_length())?);
940 right.push(chord);
941 }
942 right.insert(0.0, Clef::treble());
943 score.insert(0.0, notated(&right)?);
944 } else {
945 let count = progression
946 .first()
947 .map_or(0, |voicing| voicing.len().saturating_sub(1));
948 for number in 0..count {
949 let mut part = Stream::with_kind(StreamKind::Part);
950 opening(&mut part);
951 for (segment, voicing) in self.segments.iter().zip(progression) {
952 let Some(pitch) = voicing.get(number) else {
953 return Err(Error::FiguredBass(format!(
954 "a voicing of {} parts has no part {}",
955 voicing.len(),
956 number + 1
957 )));
958 };
959 part.push(
960 Note::from_pitch(pitch.clone())
961 .with_duration(Duration::new(segment.quarter_length())?),
962 );
963 }
964 let clef = Clef::best_for(&part.pitches(), true);
965 part.insert(0.0, clef);
966 score.insert(0.0, notated(&part)?);
967 }
968 }
969
970 score.insert(0.0, notated(&bass)?);
971 Ok(score)
972 }
973
974 pub fn generate_all_realizations(&self) -> Result<Stream> {
983 let progressions = self.all_possibility_progressions();
984 if progressions.is_empty() {
985 return Err(Error::FiguredBass("Zero solutions".to_string()));
986 }
987 let mut written = progressions
988 .iter()
989 .map(|progression| self.generate_realization_from_possibility_progression(progression));
990 let first = written
991 .next()
992 .ok_or_else(|| Error::FiguredBass("Zero solutions".to_string()))??;
993 gathered(first, written)
994 }
995
996 pub fn generate_random_realization(
1005 &self,
1006 choose: impl FnMut(usize) -> usize,
1007 ) -> Result<Stream> {
1008 let progression = self.possibility_progression_by(choose)?;
1009 self.generate_realization_from_possibility_progression(&progression)
1010 }
1011
1012 pub fn generate_random_realizations(
1024 &self,
1025 amount: usize,
1026 mut choose: impl FnMut(usize) -> usize,
1027 ) -> Result<Stream> {
1028 if amount > self.num_solutions() {
1029 return self.generate_all_realizations();
1030 }
1031 let first = self.generate_random_realization(&mut choose)?;
1032 let mut rest = Vec::new();
1033 for _ in 1..amount {
1034 rest.push(self.generate_random_realization(&mut choose));
1035 }
1036 gathered(first, rest.into_iter())
1037 }
1038}
1039
1040fn gathered(first: Stream, rest: impl Iterator<Item = Result<Stream>>) -> Result<Stream> {
1045 let mut parts: Vec<Stream> = first
1046 .events()
1047 .iter()
1048 .filter_map(|event| event.element().as_stream().cloned())
1049 .collect();
1050 let starts: Vec<FloatType> = parts
1053 .iter()
1054 .scan(0.0, |reached, part| {
1055 let start = *reached;
1056 *reached = op_frac(start + part.end_offset());
1057 Some(start)
1058 })
1059 .collect();
1060 for realization in rest {
1061 let realization = realization?;
1062 let held = realization
1063 .events()
1064 .iter()
1065 .filter_map(|event| event.element().as_stream());
1066 for (part, more) in parts.iter_mut().zip(held) {
1067 for event in more.events() {
1068 part.push(event.element().clone());
1069 }
1070 }
1071 }
1072 let mut score = Stream::with_kind(StreamKind::Score);
1073 for (start, part) in starts.into_iter().zip(parts) {
1074 score.insert(start, part);
1075 }
1076 Ok(score)
1077}
1078
1079fn trim(movements: &mut [Movements]) {
1082 if movements.len() < 2 {
1083 return;
1084 }
1085 for index in (1..movements.len()).rev() {
1086 movements[index].retain(|(_, targets)| !targets.is_empty());
1087 let (before, after) = movements.split_at_mut(index);
1088 let reachable = &after[0];
1089 for (_, targets) in &mut before[index - 1] {
1090 targets.retain(|target| reachable.iter().any(|(from, _)| from == target));
1091 }
1092 }
1093 movements[0].retain(|(_, targets)| !targets.is_empty());
1094}
1095
1096#[cfg(test)]
1097mod tests {
1098 use super::*;
1099
1100 fn line(key: &str, notes: &[(&str, FloatType, Option<&str>)]) -> FiguredBassLine {
1101 let key = Key::from_tonic(key).unwrap();
1102 let mut line = FiguredBassLine::in_key(&key).unwrap();
1103 for (bass, length, notation) in notes {
1104 line.add_element(Pitch::from_name(*bass).unwrap(), *length, *notation);
1105 }
1106 line
1107 }
1108
1109 type Case = (
1112 &'static str,
1113 &'static str,
1114 Vec<(&'static str, FloatType, Option<&'static str>)>,
1115 usize,
1116 [&'static str; 4],
1117 [&'static str; 4],
1118 );
1119
1120 fn names(voicing: &[Pitch]) -> Vec<String> {
1121 voicing.iter().map(Pitch::name_with_octave).collect()
1122 }
1123
1124 #[test]
1126 fn a_line_realizes_as_music21_s_does() {
1127 let top = Pitch::from_name("B5").unwrap();
1128 let cases: [Case; 6] = [
1129 (
1130 "intro",
1131 "C",
1132 vec![
1133 ("C3", 1.0, None),
1134 ("D3", 1.0, Some("4,3")),
1135 ("C3", 2.0, None),
1136 ],
1137 30,
1138 ["G3", "G3", "E3", "C3"],
1139 ["G5", "E5", "C5", "C3"],
1140 ),
1141 (
1142 "minor",
1143 "a",
1144 vec![
1145 ("A2", 1.0, None),
1146 ("B2", 1.0, Some("6")),
1147 ("C3", 1.0, Some("6")),
1148 ("D3", 1.0, Some("6")),
1149 ("E3", 1.0, None),
1150 ("A2", 2.0, None),
1151 ],
1152 2829,
1153 ["A3", "E3", "C3", "A2"],
1154 ["A5", "E5", "C5", "A2"],
1155 ),
1156 (
1157 "dominant seventh",
1158 "C",
1159 vec![("G2", 1.0, Some("7")), ("C3", 1.0, None)],
1160 7,
1161 ["F3", "D3", "B2", "G2"],
1162 ["E5", "C5", "C5", "C3"],
1163 ),
1164 (
1165 "diminished seventh",
1166 "c",
1167 vec![("B2", 1.0, Some("-7")), ("C3", 1.0, None)],
1168 35,
1169 ["Abb3", "F3", "D3", "B2"],
1170 ["G5", "G5", "Eb5", "C3"],
1171 ),
1172 (
1173 "German sixth",
1174 "C",
1175 vec![("Ab2", 1.0, Some("#6,b5,3")), ("G2", 1.0, None)],
1176 7,
1177 ["F#3", "Eb3", "C3", "Ab2"],
1178 ["G5", "D5", "B4", "G2"],
1179 ),
1180 (
1181 "one chord",
1182 "C",
1183 vec![("C3", 1.0, None)],
1184 21,
1185 ["G3", "E3", "C3", "C3"],
1186 ["G5", "G5", "E5", "C3"],
1187 ),
1188 ];
1189 for (label, key, notes, count, first, last) in cases {
1190 let realization = line(key, ¬es)
1191 .realize(&Rules::default(), 4, &top)
1192 .unwrap();
1193 assert_eq!(realization.num_solutions(), count, "{label}");
1194 let progressions = realization.all_possibility_progressions();
1195 assert_eq!(progressions.len(), count, "{label}");
1196 assert_eq!(names(&progressions[0][0]), first, "{label}: first");
1197 let final_voicing = progressions.last().unwrap().last().unwrap();
1198 assert_eq!(names(final_voicing), last, "{label}: last");
1199 }
1200
1201 let limited = Rules {
1202 part_movement_limits: vec![(1, 2), (2, 12), (3, 12)],
1203 ..Rules::default()
1204 };
1205 let realization = line(
1206 "C",
1207 &[
1208 ("C3", 1.0, None),
1209 ("D3", 1.0, Some("4,3")),
1210 ("C3", 2.0, None),
1211 ],
1212 )
1213 .realize(&limited, 4, &top)
1214 .unwrap();
1215 assert_eq!(realization.num_solutions(), 20);
1216
1217 let picked = line("C", &[("G2", 1.0, Some("7")), ("C3", 1.0, None)])
1218 .realize(&Rules::default(), 4, &top)
1219 .unwrap()
1220 .possibility_progression_by(|_| 0)
1221 .unwrap();
1222 assert_eq!(names(&picked[0]), ["F3", "D3", "B2", "G2"]);
1223 assert_eq!(names(&picked[1]), ["E3", "C3", "C3", "C3"]);
1224 }
1225
1226 #[test]
1228 fn a_line_is_realized_as_it_is_written() {
1229 let top = Pitch::from_name("B5").unwrap();
1230 let rules = Rules::default();
1231
1232 let key = Key::from_tonic("B").unwrap();
1234 let meter = TimeSignature::new(3, 4).unwrap();
1235 let mut tied = FiguredBassLine::in_key_and_time(&key, meter).unwrap();
1236 tied.add_element(Pitch::from_name("B2").unwrap(), 1.0, None);
1237 tied.add_element(Pitch::from_name("C#3").unwrap(), 1.0, Some("6"));
1238 tied.add_element(Pitch::from_name("D#3").unwrap(), 2.5, Some("6,#4"));
1239 tied.add_element(Pitch::from_name("E3").unwrap(), 0.5, None);
1240 let realization = tied.realize(&rules, 4, &top).unwrap();
1241 let lengths: Vec<FloatType> = realization
1242 .segments()
1243 .iter()
1244 .map(Segment::quarter_length)
1245 .collect();
1246 assert_eq!(lengths, [1.0, 1.0, 1.0, 1.5, 0.5]);
1247 assert_eq!(realization.num_solutions(), 4748);
1248
1249 let written = tied.generate_bass_line().unwrap();
1252 let sung: Vec<Vec<String>> = written
1253 .notes()
1254 .iter()
1255 .map(|(_, element)| match element {
1256 StreamElement::Note(note) => {
1257 note.lyrics().iter().map(|lyric| lyric.text()).collect()
1258 }
1259 _ => Vec::new(),
1260 })
1261 .collect();
1262 assert_eq!(
1263 sung,
1264 [
1265 vec![String::new()],
1266 vec!["6".to_string()],
1267 vec![" 6".to_string(), "#4".to_string()],
1268 Vec::new(),
1269 vec![String::new()]
1270 ]
1271 );
1272 }
1273
1274 #[test]
1276 fn a_part_laid_over_the_line_is_kept() {
1277 let top = Pitch::from_name("B5").unwrap();
1278 let mut held = line(
1279 "C",
1280 &[
1281 ("C3", 1.0, None),
1282 ("D3", 1.0, Some("6")),
1283 ("E3", 2.0, Some("6")),
1284 ],
1285 );
1286 let mut melody = Stream::with_kind(StreamKind::Part);
1287 for name in ["E5", "F5", "G5", "C5"] {
1288 melody.push(
1289 Note::from_name(name)
1290 .unwrap()
1291 .with_duration(Duration::quarter()),
1292 );
1293 }
1294 held.overlay_part(&melody);
1295 let segments = held.segments(&Rules::default(), 4, &top).unwrap();
1296 let lengths: Vec<FloatType> = segments.iter().map(Segment::quarter_length).collect();
1297 assert_eq!(lengths, [1.0, 1.0, 2.0, 0.0]);
1299 assert!(segments[0].rules.part_pitch_limits.is_empty());
1300 assert_eq!(segments[2].rules.parts_to_check, [2, 3, 4]);
1301 let realization = held.realize(&Rules::default(), 4, &top).unwrap();
1302 assert_eq!(realization.num_solutions(), 9);
1303 for progression in realization.all_possibility_progressions() {
1304 let melody: Vec<String> = progression[1..]
1305 .iter()
1306 .map(|voicing| voicing[0].name_with_octave())
1307 .collect();
1308 assert_eq!(melody, ["F5", "G5", "C5"]);
1309 }
1310 }
1311
1312 #[test]
1313 fn realizations_are_written_one_after_another() {
1314 let top = Pitch::from_name("B5").unwrap();
1315 let mut realization = line("C", &[("G2", 2.0, Some("7")), ("C3", 2.0, None)])
1316 .realize(&Rules::default(), 4, &top)
1317 .unwrap();
1318 let count = realization.num_solutions();
1319 let all = realization.generate_all_realizations().unwrap();
1320 assert_eq!(all.parts().len(), 2);
1321 assert_eq!(all.parts()[0].measures().len(), count);
1322 let chosen = realization.generate_random_realizations(3, |_| 0).unwrap();
1324 assert_eq!(chosen.parts()[1].measures().len(), 3);
1325 assert_eq!(
1326 realization
1327 .generate_random_realizations(count + 1, |_| 0)
1328 .unwrap()
1329 .parts()[0]
1330 .measures()
1331 .len(),
1332 count
1333 );
1334 realization.set_keyboard_style_output(false);
1336 let chorale = realization.generate_random_realization(|_| 0).unwrap();
1337 assert_eq!(chorale.parts().len(), 4);
1338 let mut chords = FiguredBassLine::default();
1340 chords.add_chord(
1341 Pitch::from_name("C3").unwrap(),
1342 1.0,
1343 vec!["C".to_string(), "E".to_string(), "G".to_string()],
1344 );
1345 assert!(chords.generate_bass_line().is_err());
1346 }
1347}