Skip to main content

music21_rs/stream/
voices.rs

1//! Moving music between voices and parts: music21's `voicesToParts` and
2//! `explode`, `partsToVoices` and `implode`.
3
4use super::{Stream, StreamElement, StreamEvent, StreamKind};
5use crate::clef::Clef;
6use crate::defaults::FloatType;
7use crate::error::{Error, Result};
8use crate::makenotation::event_order;
9use crate::notation::StemDirection;
10use crate::pitch::Pitch;
11
12fn stream_error(message: impl Into<String>) -> Error {
13    Error::Stream(message.into())
14}
15
16/// Which parts [`Stream::parts_to_voices`] puts together as the voices of
17/// one part: music21's `voiceAllocation`.
18#[derive(Clone, Debug, PartialEq, Eq)]
19pub enum VoiceAllocation {
20    /// Parts taken in order, this many to a part, the last part taking what
21    /// is left.
22    Each(usize),
23    /// The parts, by index, of each new part in turn.
24    Groups(Vec<Vec<usize>>),
25}
26
27impl Default for VoiceAllocation {
28    /// Two voices to a part, as music21 has it by default.
29    fn default() -> Self {
30        Self::Each(2)
31    }
32}
33
34/// A stream's id as music21 writes it into a new part's id.
35fn id_text(stream: &Stream) -> String {
36    stream.id().unwrap_or_default().to_string()
37}
38
39/// The streams this stream holds itself, with their offsets.
40fn held(stream: &Stream, kind: StreamKind) -> Vec<(FloatType, &Stream)> {
41    stream
42        .events()
43        .iter()
44        .filter_map(|event| match event.element() {
45            StreamElement::Stream(inner) if inner.kind() == kind => {
46                Some((event.offset(), &**inner))
47            }
48            _ => None,
49        })
50        .collect()
51}
52
53/// A new measure with what music21's `Measure.mergeAttributes` takes from
54/// `measure`: its id, number and padding.
55fn measure_like(measure: &Stream) -> Stream {
56    let mut out = Stream::with_kind(StreamKind::Measure);
57    out.labels.id = measure.labels.id.clone();
58    out.labels.number = measure.labels.number;
59    out.labels.number_suffix = measure.labels.number_suffix.clone();
60    out.labels.padding_left = measure.labels.padding_left;
61    out.labels.padding_right = measure.labels.padding_right;
62    out.labels.at_sounding_pitch = measure.labels.at_sounding_pitch;
63    out
64}
65
66/// Adds the elements of `from` that `keep` passes to `into`, at the offsets
67/// they have in `from`, as music21's `mergeElements` with a class filter;
68/// barlines come with them when `barlines` is set.
69fn merge_elements(
70    into: &mut Stream,
71    from: &Stream,
72    keep: impl Fn(&StreamElement) -> bool,
73    barlines: bool,
74) {
75    for event in from.events() {
76        if keep(event.element()) {
77            into.events.push(event.clone());
78        }
79    }
80    if barlines {
81        if from.labels.left_barline.is_some() {
82            into.labels.left_barline = from.labels.left_barline.clone();
83        }
84        if from.labels.right_barline.is_some() {
85            into.labels.right_barline = from.labels.right_barline.clone();
86        }
87    }
88    into.sort_events();
89}
90
91/// A measure's barlines, meters, clefs and keys: what music21 carries into
92/// each measure made from one holding voices.
93fn is_measure_setting(element: &StreamElement) -> bool {
94    ["Barline", "TimeSignature", "Clef", "KeySignature"]
95        .into_iter()
96        .any(|class| element.is_instance(class))
97}
98
99/// The measure `active` with all of `voice` added, as music21's
100/// `mergeElements(voice)`; the voice's spanners come along.
101fn with_voice(active: &Stream, voice: &Stream) -> Stream {
102    let mut out = voice.clone();
103    out.kind = StreamKind::Measure;
104    let spanners = std::mem::take(&mut out.labels.spanners);
105    out.labels = active.labels.clone();
106    out.labels.spanners = spanners;
107    if voice.labels.left_barline.is_some() {
108        out.labels.left_barline = voice.labels.left_barline.clone();
109    }
110    if voice.labels.right_barline.is_some() {
111        out.labels.right_barline = voice.labels.right_barline.clone();
112    }
113    let mut events: Vec<(StreamEvent, Option<usize>)> = active
114        .events()
115        .iter()
116        .map(|event| (event.clone(), None))
117        .collect();
118    events.extend(
119        voice
120            .events()
121            .iter()
122            .cloned()
123            .enumerate()
124            .map(|(index, event)| (event, Some(index))),
125    );
126    events.sort_by(|a, b| event_order(&a.0, &b.0));
127    out.replace_events(events);
128    out
129}
130
131/// The pitches music21's `bestClef` weighs: those of every note, chord and
132/// chord symbol, however deep.
133fn clef_pitches(stream: &Stream) -> Vec<Pitch> {
134    let mut pitches = Vec::new();
135    for (_, element) in stream.recurse() {
136        match element {
137            StreamElement::Note(note) => pitches.push(note.pitch().clone()),
138            StreamElement::Chord(chord) => pitches.extend(chord.pitches()),
139            StreamElement::PercussionChord(chord) => pitches.extend(chord.pitches()),
140            StreamElement::ChordSymbol(symbol) => {
141                pitches.extend(symbol.pitches().unwrap_or_default())
142            }
143            _ => {}
144        }
145    }
146    pitches
147}
148
149/// Puts `clef` in place of the clef at the start of the part's first
150/// measure, or at its start where it has none: music21's `Measure.clef`
151/// setter.
152fn set_first_clef(part: &mut Stream, clef: Clef) {
153    let Some(first) = part
154        .events
155        .iter_mut()
156        .filter_map(|event| match &mut event.element {
157            StreamElement::Stream(inner) if inner.kind() == StreamKind::Measure => Some(inner),
158            _ => None,
159        })
160        .next()
161    else {
162        return;
163    };
164    let old = first.events().iter().position(|event| {
165        event.offset() == 0.0 && matches!(event.element(), StreamElement::Clef(_))
166    });
167    let mut events: Vec<(StreamEvent, Option<usize>)> = first
168        .events()
169        .iter()
170        .cloned()
171        .enumerate()
172        .filter(|(index, _)| Some(*index) != old)
173        .map(|(index, event)| (event, Some(index)))
174        .collect();
175    events.push((StreamEvent::new(0.0, clef), None));
176    events.sort_by(|a, b| event_order(&a.0, &b.0));
177    first.replace_events(events);
178}
179
180impl Stream {
181    /// The most voices a measure of this part has, or the part itself, at
182    /// least one: music21's `_maxVoiceCount`. With `by_id`, the ids of the
183    /// voices too, in the order first met, and the count is at least theirs.
184    fn max_voice_count(&self, by_id: bool) -> (usize, Vec<Option<String>>) {
185        let mut count = 1;
186        let mut ids: Vec<Option<String>> = Vec::new();
187        let mut note = |voices: Vec<(FloatType, &Stream)>, count: &mut usize| {
188            if by_id {
189                for (_, voice) in voices {
190                    let id = voice.id().map(str::to_string);
191                    if !ids.contains(&id) {
192                        ids.push(id);
193                    }
194                }
195            } else {
196                *count = (*count).max(voices.len());
197            }
198        };
199        let measures = held(self, StreamKind::Measure);
200        if !measures.is_empty() {
201            for (_, measure) in measures {
202                note(held(measure, StreamKind::Voice), &mut count);
203            }
204        } else if self.has_voices() {
205            let voices = held(self, StreamKind::Voice);
206            if by_id {
207                note(voices, &mut count);
208            } else {
209                count = voices.len();
210            }
211        }
212        (count.max(ids.len()), ids)
213    }
214
215    /// A score with a part for each voice of this part, as music21's
216    /// `voicesToParts` makes it; a score has each of its parts so split.
217    ///
218    /// Each measure holding voices gives each part a measure of its own,
219    /// with the measure's barlines, meters, clefs and keys and one voice's
220    /// music; parts with no voice in that measure get the settings alone. A
221    /// measure without voices goes whole to the first part, and the others
222    /// get its barlines, meters and keys. Every part has the original's
223    /// instruments, and its first measure the clef that best fits its notes
224    /// ([`Clef::best_for`]). The parts are numbered by voice, `-v0` after the
225    /// part's id and so on, or with `separate_by_id`, named after the voices'
226    /// ids, each voice going to the part of its id whatever its place in the
227    /// measure.
228    ///
229    /// ```
230    /// use music21_rs::{Note, Stream, StreamKind};
231    ///
232    /// let mut upper = Stream::with_kind(StreamKind::Voice);
233    /// upper.insert(0.0, Note::from_name("E5")?);
234    /// let mut lower = Stream::with_kind(StreamKind::Voice);
235    /// lower.insert(0.0, Note::from_name("C3")?);
236    /// let mut measure = Stream::with_kind(StreamKind::Measure);
237    /// measure.insert(0.0, upper);
238    /// measure.insert(0.0, lower);
239    /// let mut part = Stream::with_kind(StreamKind::Part);
240    /// part.set_id(Some("P1".to_string()));
241    /// part.insert(0.0, measure);
242    ///
243    /// let score = part.voices_to_parts(false)?;
244    /// let parts = score.parts();
245    /// assert_eq!(parts.len(), 2);
246    /// assert_eq!(parts[1].id(), Some("P1-v1"));
247    /// assert_eq!(parts[1].pitches()[0].name_with_octave(), "C3");
248    /// # Ok::<(), music21_rs::Error>(())
249    /// ```
250    ///
251    /// # Errors
252    ///
253    /// With `separate_by_id`, a part with measures none of which hold a
254    /// voice, which music21 gives no part to put its music in.
255    pub fn voices_to_parts(&self, separate_by_id: bool) -> Result<Stream> {
256        let mut score = Stream::with_kind(StreamKind::Score);
257        if self.has_part_like_streams() {
258            for event in self.events() {
259                if let StreamElement::Stream(inner) = event.element() {
260                    for part in inner.voices_to_parts(separate_by_id)?.events {
261                        score.events.push(StreamEvent::new(0.0, part.element));
262                    }
263                }
264            }
265            score.sort_events();
266            return Ok(score);
267        }
268
269        let (count, ids) = self.max_voice_count(separate_by_id);
270        if separate_by_id && ids.len() < count {
271            return Err(stream_error("list index out of range"));
272        }
273        let mut parts: Vec<Stream> = (0..count)
274            .map(|index| {
275                let mut part = Stream::with_kind(StreamKind::Part);
276                let suffix = if separate_by_id {
277                    ids[index].clone().unwrap_or_default()
278                } else {
279                    format!("v{index}")
280                };
281                part.labels.id = Some(format!("{}-{suffix}", id_text(self)));
282                merge_elements(
283                    &mut part,
284                    self,
285                    |element| element.is_instance("Instrument"),
286                    false,
287                );
288                part
289            })
290            .collect();
291        let part_of = |index: usize, voice: &Stream| -> usize {
292            if separate_by_id {
293                let id = voice.id().map(str::to_string);
294                ids.iter().position(|known| *known == id).unwrap_or(index)
295            } else {
296                index
297            }
298        };
299
300        let measures = held(self, StreamKind::Measure);
301        if !measures.is_empty() {
302            for (offset, measure) in measures {
303                let voices = held(measure, StreamKind::Voice);
304                if voices.is_empty() {
305                    let mut whole = measure_like(measure);
306                    merge_elements(&mut whole, measure, |_| true, true);
307                    whole.labels.spanners = measure.labels.spanners.clone();
308                    parts[0].events.push(StreamEvent::new(offset, whole));
309                    for part in parts.iter_mut().skip(1) {
310                        let mut empty = measure_like(measure);
311                        merge_elements(
312                            &mut empty,
313                            measure,
314                            |element| {
315                                ["Barline", "TimeSignature", "KeySignature"]
316                                    .into_iter()
317                                    .any(|class| element.is_instance(class))
318                            },
319                            true,
320                        );
321                        part.events.push(StreamEvent::new(offset, empty));
322                    }
323                    continue;
324                }
325                let mut active = measure_like(measure);
326                merge_elements(&mut active, measure, is_measure_setting, true);
327                let mut filled = vec![false; count];
328                for (index, (_, voice)) in voices.iter().enumerate() {
329                    let target = part_of(index, voice);
330                    filled[target] = true;
331                    parts[target]
332                        .events
333                        .push(StreamEvent::new(offset, with_voice(&active, voice)));
334                }
335                for (target, part) in parts.iter_mut().enumerate() {
336                    if !filled[target] {
337                        part.events.push(StreamEvent::new(offset, active.clone()));
338                    }
339                }
340            }
341        } else if self.has_voices() {
342            for (index, (_, voice)) in held(self, StreamKind::Voice).into_iter().enumerate() {
343                if let Some(part) = parts.get_mut(index) {
344                    merge_elements(part, voice, |_| true, true);
345                }
346            }
347        } else {
348            merge_elements(&mut parts[0], self, |_| true, true);
349        }
350
351        for mut part in parts {
352            part.sort_events();
353            if !held(&part, StreamKind::Measure).is_empty() {
354                let clef = Clef::best_for(&clef_pitches(&part), false);
355                set_first_clef(&mut part, clef);
356            }
357            score.events.push(StreamEvent::new(0.0, part));
358        }
359        Ok(score)
360    }
361
362    /// A score with a part for each voice: music21's `explode`, which is
363    /// [`Stream::voices_to_parts`] by place.
364    ///
365    /// # Errors
366    ///
367    /// As [`Stream::voices_to_parts`].
368    pub fn explode(&self) -> Result<Stream> {
369        self.voices_to_parts(false)
370    }
371
372    /// A score whose parts each hold several of this score's parts as
373    /// voices, as music21's `partsToVoices` makes it.
374    ///
375    /// The parts are grouped by `allocation`. A group of one part is kept as
376    /// it is unless `permit_one_voice_per_part`. Otherwise each measure of
377    /// the new part has the first part's measure's number, barlines, meters,
378    /// clefs and keys, and a voice for each part of the group, numbered from
379    /// nought, holding the notes, chords and rests that measure holds
380    /// itself -- not those in its own voices. With `set_stems`, the notes of
381    /// the first, third ... voice have their stems up and the others down.
382    /// The parts' spanners come along; the score keeps its metadata and
383    /// nothing else.
384    ///
385    /// ```
386    /// use music21_rs::{Note, Stream, StreamKind};
387    /// use music21_rs::stream::VoiceAllocation;
388    ///
389    /// let mut score = Stream::with_kind(StreamKind::Score);
390    /// for name in ["E5", "C3"] {
391    ///     let mut measure = Stream::with_kind(StreamKind::Measure);
392    ///     measure.insert(0.0, Note::from_name(name)?);
393    ///     let mut part = Stream::with_kind(StreamKind::Part);
394    ///     part.insert(0.0, measure);
395    ///     score.insert(0.0, part);
396    /// }
397    /// let joined = score.parts_to_voices(&VoiceAllocation::Each(2), false, true)?;
398    /// assert_eq!(joined.parts().len(), 1);
399    /// assert_eq!(joined.parts()[0].measures()[0].voices().len(), 2);
400    /// # Ok::<(), music21_rs::Error>(())
401    /// ```
402    ///
403    /// # Errors
404    ///
405    /// A group naming a part the score has not got, or a later part of a
406    /// group with more measures than the first.
407    pub fn parts_to_voices(
408        &self,
409        allocation: &VoiceAllocation,
410        permit_one_voice_per_part: bool,
411        set_stems: bool,
412    ) -> Result<Stream> {
413        let parts = self.parts();
414        let bundle: Vec<Vec<&Stream>> = match allocation {
415            VoiceAllocation::Each(each) => {
416                if *each == 0 {
417                    return Err(stream_error("integer division or modulo by zero"));
418                }
419                parts.chunks(*each).map(<[&Stream]>::to_vec).collect()
420            }
421            VoiceAllocation::Groups(groups) => groups
422                .iter()
423                .map(|group| {
424                    group
425                        .iter()
426                        .map(|index| {
427                            parts
428                                .get(*index)
429                                .copied()
430                                .ok_or_else(|| stream_error("list index out of range"))
431                        })
432                        .collect::<Result<Vec<_>>>()
433                })
434                .collect::<Result<_>>()?,
435        };
436
437        let mut out = Stream::with_kind(self.kind());
438        out.labels.id = self.labels.id.clone();
439        out.labels.metadata = self.labels.metadata.clone();
440        for group in bundle {
441            if group.len() == 1 && !permit_one_voice_per_part {
442                out.events.push(StreamEvent::new(0.0, group[0].clone()));
443                continue;
444            }
445            out.events
446                .push(StreamEvent::new(0.0, join_as_voices(&group, set_stems)?));
447        }
448        out.sort_events();
449        Ok(out)
450    }
451
452    /// Parts joined two to a part as voices: music21's `implode`, which is
453    /// [`Stream::parts_to_voices`] with its defaults.
454    ///
455    /// # Errors
456    ///
457    /// As [`Stream::parts_to_voices`].
458    pub fn implode(&self) -> Result<Stream> {
459        self.parts_to_voices(&VoiceAllocation::default(), false, true)
460    }
461}
462
463/// One part holding each of `group` as a voice.
464fn join_as_voices(group: &[&Stream], set_stems: bool) -> Result<Stream> {
465    let mut active = Stream::with_kind(StreamKind::Part);
466    // Where each voice stands, by measure and part, to move spanners to.
467    let mut measures: Vec<(FloatType, Stream)> = Vec::new();
468    // For each part, where each of its leaves went: (measure, voice
469    // event index within the voice) by the part's own leaf position.
470    let mut placed: Vec<Vec<Option<(usize, usize)>>> = Vec::new();
471    for (index, part) in group.iter().enumerate() {
472        let first = measures.is_empty();
473        let mut moved = vec![None; part.leaf_total()];
474        let mut leaf = 0;
475        let mut measure_index = 0;
476        for event in part.events() {
477            let StreamElement::Stream(measure) = event.element() else {
478                leaf += 1;
479                continue;
480            };
481            if measure.kind() != StreamKind::Measure {
482                leaf += measure.leaf_total();
483                continue;
484            }
485            if first {
486                let mut made = measure_like(measure);
487                merge_elements(&mut made, measure, is_measure_setting, true);
488                measures.push((event.offset(), made));
489            } else if measure_index >= measures.len() {
490                return Err(stream_error("index out of range"));
491            }
492            let mut voice = Stream::with_kind(StreamKind::Voice);
493            voice.labels.id = Some(index.to_string());
494            voice.labels.spanners = measure.labels.spanners.clone();
495            let mut kept: Vec<(StreamEvent, Option<usize>)> = Vec::new();
496            for (position, inner) in measure.events().iter().enumerate() {
497                let count = super::leaf_count(inner.element());
498                if inner.element().is_instance("GeneralNote") {
499                    let mut kept_event = inner.clone();
500                    if set_stems && let StreamElement::Note(note) = &mut kept_event.element {
501                        note.set_stem_direction(if index % 2 == 0 {
502                            StemDirection::Up
503                        } else {
504                            StemDirection::Down
505                        });
506                    }
507                    moved[leaf] = Some((measure_index, kept.len()));
508                    kept.push((kept_event, Some(position)));
509                }
510                leaf += count;
511            }
512            voice.events = measure.events.clone();
513            voice.replace_events(kept);
514            measures[measure_index].1.insert(0.0, voice);
515            measure_index += 1;
516        }
517        placed.push(moved);
518    }
519
520    // Where each voice's first leaf now stands in the part.
521    let mut starts: Vec<Vec<usize>> = Vec::new();
522    let mut leaf = 0;
523    for (_, measure) in &measures {
524        let mut by_voice = vec![0; group.len()];
525        for event in measure.events() {
526            if let StreamElement::Stream(voice) = event.element()
527                && voice.kind() == StreamKind::Voice
528                && let Some(index) = voice.id().and_then(|id| id.parse::<usize>().ok())
529                && index < by_voice.len()
530            {
531                by_voice[index] = leaf;
532            }
533            leaf += super::leaf_count(event.element());
534        }
535        starts.push(by_voice);
536    }
537    for (index, part) in group.iter().enumerate() {
538        let moved: Vec<Option<usize>> = placed[index]
539            .iter()
540            .map(|place| place.map(|(measure, within)| starts[measure][index] + within))
541            .collect();
542        for spanner in part.spanners() {
543            let mut spanner = spanner.clone();
544            spanner.move_places(&moved);
545            active.labels.spanners.push(spanner);
546        }
547    }
548    for (offset, measure) in measures {
549        active.events.push(StreamEvent::new(offset, measure));
550    }
551    active.sort_events();
552    Ok(active)
553}
554
555#[cfg(test)]
556mod tests {
557    use super::*;
558    use crate::note::Note;
559    use crate::spanner::Spanner;
560
561    fn part_of(names: &[&str]) -> Result<Stream> {
562        let mut measure = Stream::with_kind(StreamKind::Measure);
563        measure.insert(0.0, Clef::best_for(&[], false));
564        for (offset, name) in names.iter().enumerate() {
565            measure.insert(offset as FloatType, Note::from_name(name)?);
566        }
567        let mut part = Stream::with_kind(StreamKind::Part);
568        part.insert(0.0, measure);
569        Ok(part)
570    }
571
572    fn slurred(stream: &Stream) -> Vec<Vec<String>> {
573        let leaves = stream.leaves();
574        stream
575            .spanners()
576            .iter()
577            .map(|spanner| {
578                spanner
579                    .spanned()
580                    .iter()
581                    .map(|place| match place.map(|place| leaves[place].1) {
582                        Some(StreamElement::Note(note)) => note.pitch().name_with_octave(),
583                        _ => "-".to_string(),
584                    })
585                    .collect()
586            })
587            .collect()
588    }
589
590    #[test]
591    fn a_parts_spanners_follow_its_notes_into_a_voice() -> Result<()> {
592        let mut upper = part_of(&["C5", "D5"])?;
593        upper.add_spanner(Spanner::slur(vec![1, 2]));
594        let mut lower = part_of(&["E3", "F3"])?;
595        lower.add_spanner(Spanner::slur(vec![1, 2]));
596        let mut score = Stream::with_kind(StreamKind::Score);
597        score.insert(0.0, upper);
598        score.insert(0.0, lower);
599
600        let joined = score.implode()?;
601        let parts = joined.parts();
602        assert_eq!(parts.len(), 1);
603        assert_eq!(
604            slurred(parts[0]),
605            vec![
606                vec!["C5".to_string(), "D5".to_string()],
607                vec!["E3".to_string(), "F3".to_string()]
608            ]
609        );
610        Ok(())
611    }
612
613    #[test]
614    fn what_music21_refuses_is_refused() -> Result<()> {
615        // A part with measures but no voices has no id to name a part by.
616        assert!(part_of(&["C4"])?.voices_to_parts(true).is_err());
617        let mut score = Stream::with_kind(StreamKind::Score);
618        score.insert(0.0, part_of(&["C4"])?);
619        assert!(
620            score
621                .parts_to_voices(&VoiceAllocation::Groups(vec![vec![0, 1]]), false, true)
622                .is_err()
623        );
624        assert!(
625            score
626                .parts_to_voices(&VoiceAllocation::Each(0), false, true)
627                .is_err()
628        );
629        Ok(())
630    }
631}