Skip to main content

music21/figuredbass/
realizer.rs

1//! Realizing a figured bass line: music21's `figuredBass.realizer`.
2//!
3//! A [`FiguredBassLine`] is a run of bass notes, each with its figures, in a
4//! key and a meter. Realizing it makes a [`Segment`] of each note as the
5//! line is written -- a note cut at a barline is two -- finds every pair of
6//! voicings each segment may move to the next by, and drops the voicings
7//! that lead nowhere, leaving a [`Realization`]: every way of voicing the
8//! whole line that keeps the rules, which it can count, list, pick from,
9//! and write out as a score.
10
11use 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/// One thing a bass line is realized over.
28#[derive(Clone, Debug, PartialEq)]
29enum Element {
30    /// A bass note and the figures written under it.
31    Figured {
32        bass: Pitch,
33        quarter_length: FloatType,
34        notation: Option<String>,
35    },
36    /// A bass note and the names of the notes above it, as music21 reads a
37    /// chord symbol or a roman numeral.
38    Named {
39        bass: Pitch,
40        quarter_length: FloatType,
41        pitch_names: Vec<String>,
42    },
43}
44
45/// One note or rest of a part laid over the line: where it starts, how long
46/// it lasts, and its pitch where it is a note.
47#[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/// One written note of the bass line: a bass note, or one of the pieces a
61/// barline cut it into.
62#[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/// What sounds in one part during a moment of the line.
76#[derive(Clone, Copy, Debug, PartialEq)]
77enum Voice {
78    /// A note of the part laid over the line of that number, by its place
79    /// there.
80    Upper(usize, usize),
81    /// A piece of the bass line, by its place there.
82    Bass(usize),
83}
84
85/// A stretch of the line through which every part holds one note: its
86/// start, its end, and what each part sounds, highest first.
87type Moment = ((FloatType, FloatType), Vec<Voice>);
88
89/// A bass line and its figures, in a key and a meter.
90///
91/// ```
92/// use music21::Pitch;
93/// use music21::figuredbass::realizer::FiguredBassLine;
94/// use music21::figuredbass::rules::Rules;
95///
96/// let mut line = FiguredBassLine::default();
97/// line.add_element(Pitch::from_name("C3")?, 1.0, None);
98/// line.add_element(Pitch::from_name("D3")?, 1.0, Some("4,3"));
99/// line.add_element(Pitch::from_name("C3")?, 2.0, None);
100/// let realization = line.realize(&Rules::default(), 4, &Pitch::from_name("B5")?)?;
101/// assert_eq!(realization.num_solutions(), 30);
102/// # Ok::<(), music21::Error>(())
103/// ```
104#[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    /// A line in C major and common time, with nothing in it yet.
116    fn default() -> Self {
117        Self::new(FiguredBassScale::default())
118    }
119}
120
121/// music21's meter for a line that names none.
122fn common_time() -> TimeSignature {
123    TimeSignature::new(4, 4).expect("four quarters make a bar")
124}
125
126impl FiguredBassLine {
127    /// An empty line in common time whose figures are read in `scale`.
128    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    /// An empty line in `key` and common time. The key must be in one of
139    /// the five modes a figured bass is read in.
140    ///
141    /// # Errors
142    ///
143    /// A key in another mode.
144    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    /// An empty line in `key` and `time`: music21's
151    /// `FiguredBassLine(inKey, inTime)`.
152    ///
153    /// # Errors
154    ///
155    /// A key in a mode no figured bass is read in.
156    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    /// The scale its figures are read in.
163    pub fn scale(&self) -> &FiguredBassScale {
164        &self.scale
165    }
166
167    /// The meter it is written in: music21's `inTime`.
168    pub fn time_signature(&self) -> &TimeSignature {
169        &self.time
170    }
171
172    /// Writes it in another meter. The figures are counted as before.
173    pub fn set_time_signature(&mut self, time: TimeSignature) {
174        self.time = time;
175    }
176
177    /// The key signature it is written with: the scale's, unless set.
178    pub fn key_signature(&self) -> &KeySignature {
179        &self.key_signature
180    }
181
182    /// Writes it with another key signature, as music21 writes
183    /// `inKey.sharps` as it stands. The figures are still counted in the
184    /// scale the line was made with, as music21's are.
185    pub fn set_key_signature(&mut self, key_signature: KeySignature) {
186        self.key_signature = key_signature;
187    }
188
189    /// Adds a bass note lasting `quarter_length`, with the figures written
190    /// under it, if any: music21's `addElement` of a note.
191    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    /// Adds a bass note with the names of the notes above it rather than
200    /// figures, as music21 reads a chord symbol or a roman numeral into a
201    /// line. A chord lasting nothing is realized as lasting a quarter, as
202    /// music21's is.
203    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    /// How many bass notes it has.
216    pub fn len(&self) -> usize {
217        self.elements.len()
218    }
219
220    /// Whether it has none.
221    pub fn is_empty(&self) -> bool {
222        self.elements.is_empty()
223    }
224
225    /// Lays a written part over the line, to be kept as it is by every
226    /// realization: music21's `overlayPart`.
227    ///
228    /// Each note of the part holds one part of the voicing to its pitch
229    /// while it sounds, the first part laid over being the highest. Where
230    /// it moves and the bass does not, the line gains a segment of no
231    /// length, into which only the parts laid over may move. As in music21,
232    /// the first segment of the line is not held to the parts laid over it.
233    ///
234    /// Only the part's notes and rests are read, at their offsets from its
235    /// start.
236    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    /// The bass line written out as a part: a bass clef, the key signature,
263    /// the meter and the bass notes one after another, each with its
264    /// figures under it as lyrics, cut into measures with the notes that
265    /// run past a barline tied, tuplets completed and bracketed and the
266    /// notes beamed. music21's `generateBassLine`.
267    ///
268    /// ```
269    /// use music21::figuredbass::realizer::FiguredBassLine;
270    /// use music21::{Key, Pitch, TimeSignature};
271    ///
272    /// let key = Key::from_tonic("B")?;
273    /// let mut line = FiguredBassLine::in_key_and_time(&key, TimeSignature::new(3, 4)?)?;
274    /// line.add_element(Pitch::from_name("B2")?, 1.0, None);
275    /// line.add_element(Pitch::from_name("C#3")?, 1.0, Some("6"));
276    /// line.add_element(Pitch::from_name("D#3")?, 2.5, Some("6"));
277    /// let written = line.generate_bass_line()?;
278    /// assert_eq!(written.measures().len(), 2);
279    /// assert_eq!(written.notes().len(), 4);
280    /// # Ok::<(), music21::Error>(())
281    /// ```
282    ///
283    /// # Errors
284    ///
285    /// A line holding chords rather than bass notes and figures, figures
286    /// that cannot be read, or a length no duration has.
287    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    /// The bass line as its written notes, each with the figures of the
310    /// bass note it is, or is a piece of.
311    fn pieces(&self) -> Result<Vec<Piece>> {
312        // Where each bass note starts and stops.
313        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    /// The moments of the line and the parts laid over it, in order:
351    /// music21's `checker.extractHarmonies` over the parts and the bass,
352    /// or its `createOffsetMapping` of the bass where no part is laid over.
353    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        // The first part's notes, those starting and ending together sharing
381        // a moment.
382        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        // Each part after it cuts the moments where its own notes change.
391        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    /// A segment for each bass note as the line is written, voiced in
424    /// `num_parts` parts under `rules`, no part above `max_pitch`: music21's
425    /// `retrieveSegments`.
426    ///
427    /// A bass note cut by a barline is a segment for each piece, and a part
428    /// laid over the line holds its part of each segment to its pitch. A
429    /// line of chords is a segment for each chord.
430    ///
431    /// # Errors
432    ///
433    /// Figures the line's scale cannot read, or a part laid over the line
434    /// that sounds something other than a note where a segment needs its
435    /// pitch.
436    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    /// [`FiguredBassLine::segments`], each with the bass note written under
450    /// it.
451    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        // music21 reads a line holding any chord as a line of chords, one
461        // segment each, with no bass line written.
462        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        // The last piece of the bass a segment has taken its length from.
541        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                // The bass holds while a part laid over it moves: the parts
555                // not laid over stay where they were.
556                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    /// Every way of voicing the line in `num_parts` parts that keeps
583    /// `rules`, no part above `max_pitch`: music21's `realize`.
584    ///
585    /// # Errors
586    ///
587    /// A line with nothing in it, figures its scale cannot read, or a
588    /// resolution that fails.
589    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
612/// Which of two spans comes first, by its start and then by its end.
613fn 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
620/// Whether a note sounds during a span: music21's `getElementsByOffset`
621/// taking in what begins before the span and leaving out what only touches
622/// either end of it.
623fn 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
634/// A bass note with its figures written under it as lyrics, one a line,
635/// padded to one width: music21's `addLyricsToBassNote`.
636fn 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
651/// A part cut into measures and written out: music21's `makeNotation` with
652/// `cautionaryNotImmediateRepeat=False`, which is how the realizer writes
653/// every part it makes.
654fn notated(part: &Stream) -> Result<Stream> {
655    let mut made = part.clone();
656    make_part_notation_by(&mut made, false)?;
657    Ok(made)
658}
659
660/// Where each voicing of one segment may go in the next, in the order the
661/// voicings were found.
662type Movements = Vec<(Possibility, Vec<Possibility>)>;
663
664/// Every way of voicing a figured bass line: music21's `Realization`.
665#[derive(Clone, Debug)]
666#[must_use]
667pub struct Realization {
668    segments: Vec<Segment>,
669    /// For each segment but the last, where its voicings may go.
670    movements: Vec<Movements>,
671    /// The voicings of a line of one segment.
672    single: Vec<Possibility>,
673    /// What each chord that fell back to an ordinary resolution warned.
674    fallbacks: Vec<String>,
675    /// The key signature and the meter a realization is written in.
676    key_signature: KeySignature,
677    time: TimeSignature,
678    /// The bass note written under each segment.
679    bass_notes: Vec<Note>,
680    keyboard_style: bool,
681}
682
683impl Realization {
684    /// The realization of `segments`, a line's segments in order. Written
685    /// out, it is in C major and common time, each segment's bass lasting
686    /// as long as the segment; a realization made by
687    /// [`FiguredBassLine::realize`] is written as its line is.
688    ///
689    /// # Errors
690    ///
691    /// No segments, or a resolution that fails.
692    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    /// The segments realized, one for each bass note.
738    pub fn segments(&self) -> &[Segment] {
739        &self.segments
740    }
741
742    /// What each chord that found no resolution of its own warned, in
743    /// order.
744    pub fn fallbacks(&self) -> &[String] {
745        &self.fallbacks
746    }
747
748    /// How many ways there are of voicing the whole line: music21's
749    /// `getNumSolutions`.
750    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    /// Every way of voicing the whole line, a voicing for each bass note:
780    /// music21's `getAllPossibilityProgressions`, in its order.
781    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    /// One way of voicing the whole line, each voicing chosen by `choose`,
823    /// which is given how many there are to choose from and answers the
824    /// index of one: music21's `getRandomPossibilityProgression`, with the
825    /// choosing left to the caller.
826    ///
827    /// # Errors
828    ///
829    /// A line with no way of voicing it, or a choice out of range.
830    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    /// Whether realizations are written in keyboard style, the upper parts
865    /// as chords on one staff over the bass, as they are to begin with, or
866    /// in chorale style with a staff for each part: music21's
867    /// `keyboardStyleOutput`.
868    pub fn keyboard_style_output(&self) -> bool {
869        self.keyboard_style
870    }
871
872    /// Says whether realizations are written in keyboard style or in
873    /// chorale style.
874    pub fn set_keyboard_style_output(&mut self, keyboard_style: bool) {
875        self.keyboard_style = keyboard_style;
876    }
877
878    /// One way of voicing the line written out as a score, a voicing for
879    /// each segment: music21's `generateRealizationFromPossibilityProgression`.
880    ///
881    /// In keyboard style the score is two parts, the upper parts of each
882    /// voicing as a chord under a treble clef and the bass under a bass
883    /// clef; in chorale style each part has a staff of its own, under the
884    /// clef that fits it best. Every part opens with the key signature and
885    /// the meter of the line, is cut into measures, and has the notes that
886    /// run past a barline tied, its tuplets bracketed and its notes beamed.
887    ///
888    /// ```
889    /// use music21::Pitch;
890    /// use music21::figuredbass::realizer::FiguredBassLine;
891    /// use music21::figuredbass::rules::Rules;
892    ///
893    /// let mut line = FiguredBassLine::default();
894    /// line.add_element(Pitch::from_name("C3")?, 2.0, None);
895    /// line.add_element(Pitch::from_name("G2")?, 2.0, Some("7"));
896    /// line.add_element(Pitch::from_name("C3")?, 4.0, None);
897    /// let realization = line.realize(&Rules::default(), 4, &Pitch::from_name("B5")?)?;
898    /// let voicings = realization.all_possibility_progressions();
899    /// let score = realization.generate_realization_from_possibility_progression(&voicings[0])?;
900    /// assert_eq!(score.parts().len(), 2);
901    /// assert_eq!(score.parts()[0].measures().len(), 2);
902    /// # Ok::<(), music21::Error>(())
903    /// ```
904    ///
905    /// # Errors
906    ///
907    /// A progression with fewer voicings than the line has segments, or a
908    /// voicing that is no chord.
909    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    /// Every way of voicing the line written out one after another in one
975    /// score: music21's `generateAllRealizations`. Each realization keeps
976    /// its own measure numbers and its closing barline.
977    ///
978    /// # Errors
979    ///
980    /// A line with no way of voicing it, or a realization that cannot be
981    /// written.
982    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    /// One way of voicing the line written out as a score, each voicing
997    /// chosen by `choose`, which is given how many there are to choose from
998    /// and answers the index of one: music21's `generateRandomRealization`,
999    /// with the choosing left to the caller.
1000    ///
1001    /// # Errors
1002    ///
1003    /// A line with no way of voicing it, or a choice out of range.
1004    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    /// So many ways of voicing the line, each chosen by `choose`, written
1013    /// out one after another in one score: music21's
1014    /// `generateRandomRealizations`. Asked for more than there are, it
1015    /// answers every one of them in order, as [`generate_all_realizations`]
1016    /// does. One way may be chosen more than once.
1017    ///
1018    /// [`generate_all_realizations`]: Realization::generate_all_realizations
1019    ///
1020    /// # Errors
1021    ///
1022    /// A line with no way of voicing it, or a choice out of range.
1023    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
1040/// Several realizations as one score: the parts of the first, each followed
1041/// by what the same part of every later realization holds. The parts are
1042/// put one after another as music21 puts them, each starting where the one
1043/// before it ended.
1044fn 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    // music21 appends each part to the score before anything is added to
1051    // it, so each starts where the one before ended as it then stood.
1052    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
1079/// Drops every move that leads to a voicing with nowhere to go, from the
1080/// end of the line back, as music21's `_trimAllMovements` does.
1081fn 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    /// A line, the key it is in, how many ways it voices, and the first
1110    /// voicing of the first way and the last voicing of the last.
1111    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    /// Every count and voicing here is music21's own.
1125    #[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, &notes)
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    /// Every count here is music21's own.
1227    #[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        // A bass note cut by a barline is a segment for each piece.
1233        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        // The figures are written under the bass, padded to one width, and
1250        // not again under the piece tied on.
1251        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    /// Every count here is music21's own.
1275    #[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        // The melody moves once while the bass holds.
1298        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        // Chosen by the caller, and as many as asked for.
1323        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        // A staff for each part in chorale style.
1335        realization.set_keyboard_style_output(false);
1336        let chorale = realization.generate_random_realization(|_| 0).unwrap();
1337        assert_eq!(chorale.parts().len(), 4);
1338        // A line of chords has no bass line to write.
1339        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}