Skip to main content

music21/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::{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::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(
272                "fewer voice ids than voices to separate by them",
273            ));
274        }
275        let mut parts: Vec<Stream> = (0..count)
276            .map(|index| {
277                let mut part = Stream::with_kind(StreamKind::Part);
278                let suffix = if separate_by_id {
279                    ids[index].clone().unwrap_or_default()
280                } else {
281                    format!("v{index}")
282                };
283                part.labels.id = Some(format!("{}-{suffix}", id_text(self)));
284                merge_elements(
285                    &mut part,
286                    self,
287                    |element| element.is_instance("Instrument"),
288                    false,
289                );
290                part
291            })
292            .collect();
293        let part_of = |index: usize, voice: &Stream| -> usize {
294            if separate_by_id {
295                let id = voice.id().map(str::to_string);
296                ids.iter().position(|known| *known == id).unwrap_or(index)
297            } else {
298                index
299            }
300        };
301
302        let measures = held(self, StreamKind::Measure);
303        if !measures.is_empty() {
304            for (offset, measure) in measures {
305                let voices = held(measure, StreamKind::Voice);
306                if voices.is_empty() {
307                    let mut whole = measure_like(measure);
308                    merge_elements(&mut whole, measure, |_| true, true);
309                    whole.labels.spanners = measure.labels.spanners.clone();
310                    parts[0].events.push(StreamEvent::new(offset, whole));
311                    for part in parts.iter_mut().skip(1) {
312                        let mut empty = measure_like(measure);
313                        merge_elements(
314                            &mut empty,
315                            measure,
316                            |element| {
317                                ["Barline", "TimeSignature", "KeySignature"]
318                                    .into_iter()
319                                    .any(|class| element.is_instance(class))
320                            },
321                            true,
322                        );
323                        part.events.push(StreamEvent::new(offset, empty));
324                    }
325                    continue;
326                }
327                let mut active = measure_like(measure);
328                merge_elements(&mut active, measure, is_measure_setting, true);
329                let mut filled = vec![false; count];
330                for (index, (_, voice)) in voices.iter().enumerate() {
331                    let target = part_of(index, voice);
332                    filled[target] = true;
333                    parts[target]
334                        .events
335                        .push(StreamEvent::new(offset, with_voice(&active, voice)));
336                }
337                for (target, part) in parts.iter_mut().enumerate() {
338                    if !filled[target] {
339                        part.events.push(StreamEvent::new(offset, active.clone()));
340                    }
341                }
342            }
343        } else if self.has_voices() {
344            for (index, (_, voice)) in held(self, StreamKind::Voice).into_iter().enumerate() {
345                if let Some(part) = parts.get_mut(index) {
346                    merge_elements(part, voice, |_| true, true);
347                }
348            }
349        } else {
350            merge_elements(&mut parts[0], self, |_| true, true);
351        }
352
353        for mut part in parts {
354            part.sort_events();
355            if !held(&part, StreamKind::Measure).is_empty() {
356                let clef = Clef::best_for(&clef_pitches(&part), false);
357                set_first_clef(&mut part, clef);
358            }
359            score.events.push(StreamEvent::new(0.0, part));
360        }
361        Ok(score)
362    }
363
364    /// A score with a part for each voice: music21's `explode`, which is
365    /// [`Stream::voices_to_parts`] by place.
366    ///
367    /// # Errors
368    ///
369    /// As [`Stream::voices_to_parts`].
370    pub fn explode(&self) -> Result<Stream> {
371        self.voices_to_parts(false)
372    }
373
374    /// A score whose parts each hold several of this score's parts as
375    /// voices, as music21's `partsToVoices` makes it.
376    ///
377    /// The parts are grouped by `allocation`. A group of one part is kept as
378    /// it is unless `permit_one_voice_per_part`. Otherwise each measure of
379    /// the new part has the first part's measure's number, barlines, meters,
380    /// clefs and keys, and a voice for each part of the group, numbered from
381    /// nought, holding the notes, chords and rests that measure holds
382    /// itself -- not those in its own voices. With `set_stems`, the notes of
383    /// the first, third ... voice have their stems up and the others down.
384    /// The parts' spanners come along; the score keeps its metadata and
385    /// nothing else.
386    ///
387    /// ```
388    /// use music21::{Note, Stream, StreamKind};
389    /// use music21::stream::VoiceAllocation;
390    ///
391    /// let mut score = Stream::with_kind(StreamKind::Score);
392    /// for name in ["E5", "C3"] {
393    ///     let mut measure = Stream::with_kind(StreamKind::Measure);
394    ///     measure.insert(0.0, Note::from_name(name)?);
395    ///     let mut part = Stream::with_kind(StreamKind::Part);
396    ///     part.insert(0.0, measure);
397    ///     score.insert(0.0, part);
398    /// }
399    /// let joined = score.parts_to_voices(&VoiceAllocation::Each(2), false, true)?;
400    /// assert_eq!(joined.parts().len(), 1);
401    /// assert_eq!(joined.parts()[0].measures()[0].voices().len(), 2);
402    /// # Ok::<(), music21::Error>(())
403    /// ```
404    ///
405    /// # Errors
406    ///
407    /// A group naming a part the score has not got, or a later part of a
408    /// group with more measures than the first.
409    pub fn parts_to_voices(
410        &self,
411        allocation: &VoiceAllocation,
412        permit_one_voice_per_part: bool,
413        set_stems: bool,
414    ) -> Result<Stream> {
415        let parts = self.parts();
416        let bundle: Vec<Vec<&Stream>> = match allocation {
417            VoiceAllocation::Each(each) => {
418                if *each == 0 {
419                    return Err(stream_error("cannot group parts in groups of nought"));
420                }
421                parts.chunks(*each).map(<[&Stream]>::to_vec).collect()
422            }
423            VoiceAllocation::Groups(groups) => groups
424                .iter()
425                .map(|group| {
426                    group
427                        .iter()
428                        .map(|index| {
429                            parts
430                                .get(*index)
431                                .copied()
432                                .ok_or_else(|| stream_error(format!("no part {index} to group")))
433                        })
434                        .collect::<Result<Vec<_>>>()
435                })
436                .collect::<Result<_>>()?,
437        };
438
439        let mut out = Stream::with_kind(self.kind());
440        out.labels.id = self.labels.id.clone();
441        out.labels.metadata = self.labels.metadata.clone();
442        for group in bundle {
443            if group.len() == 1 && !permit_one_voice_per_part {
444                out.events.push(StreamEvent::new(0.0, group[0].clone()));
445                continue;
446            }
447            out.events
448                .push(StreamEvent::new(0.0, join_as_voices(&group, set_stems)?));
449        }
450        out.sort_events();
451        Ok(out)
452    }
453
454    /// Parts joined two to a part as voices: music21's `implode`, which is
455    /// [`Stream::parts_to_voices`] with its defaults.
456    ///
457    /// # Errors
458    ///
459    /// As [`Stream::parts_to_voices`].
460    pub fn implode(&self) -> Result<Stream> {
461        self.parts_to_voices(&VoiceAllocation::default(), false, true)
462    }
463}
464
465/// One part holding each of `group` as a voice.
466fn join_as_voices(group: &[&Stream], set_stems: bool) -> Result<Stream> {
467    let mut active = Stream::with_kind(StreamKind::Part);
468    // Where each voice stands, by measure and part, to move spanners to.
469    let mut measures: Vec<(FloatType, Stream)> = Vec::new();
470    // For each part, where each of its leaves went: (measure, voice
471    // event index within the voice) by the part's own leaf position.
472    let mut placed: Vec<Vec<Option<(usize, usize)>>> = Vec::new();
473    for (index, part) in group.iter().enumerate() {
474        let first = measures.is_empty();
475        let mut moved = vec![None; part.leaf_total()];
476        let mut leaf = 0;
477        let mut measure_index = 0;
478        for event in part.events() {
479            let StreamElement::Stream(measure) = event.element() else {
480                leaf += 1;
481                continue;
482            };
483            if measure.kind() != StreamKind::Measure {
484                leaf += measure.leaf_total();
485                continue;
486            }
487            if first {
488                let mut made = measure_like(measure);
489                merge_elements(&mut made, measure, is_measure_setting, true);
490                measures.push((event.offset(), made));
491            } else if measure_index >= measures.len() {
492                return Err(stream_error("index out of range"));
493            }
494            let mut voice = Stream::with_kind(StreamKind::Voice);
495            voice.labels.id = Some(index.to_string());
496            voice.labels.spanners = measure.labels.spanners.clone();
497            let mut kept: Vec<(StreamEvent, Option<usize>)> = Vec::new();
498            for (position, inner) in measure.events().iter().enumerate() {
499                let count = super::leaf_count(inner.element());
500                if inner.element().is_instance("GeneralNote") {
501                    let mut kept_event = inner.clone();
502                    if set_stems && let StreamElement::Note(note) = &mut kept_event.element {
503                        note.set_stem_direction(if index % 2 == 0 {
504                            StemDirection::Up
505                        } else {
506                            StemDirection::Down
507                        });
508                    }
509                    moved[leaf] = Some((measure_index, kept.len()));
510                    kept.push((kept_event, Some(position)));
511                }
512                leaf += count;
513            }
514            voice.events = measure.events.clone();
515            voice.replace_events(kept);
516            measures[measure_index].1.insert(0.0, voice);
517            measure_index += 1;
518        }
519        placed.push(moved);
520    }
521
522    // Where each voice's first leaf now stands in the part.
523    let mut starts: Vec<Vec<usize>> = Vec::new();
524    let mut leaf = 0;
525    for (_, measure) in &measures {
526        let mut by_voice = vec![0; group.len()];
527        for event in measure.events() {
528            if let StreamElement::Stream(voice) = event.element()
529                && voice.kind() == StreamKind::Voice
530                && let Some(index) = voice.id().and_then(|id| id.parse::<usize>().ok())
531                && index < by_voice.len()
532            {
533                by_voice[index] = leaf;
534            }
535            leaf += super::leaf_count(event.element());
536        }
537        starts.push(by_voice);
538    }
539    for (index, part) in group.iter().enumerate() {
540        let moved: Vec<Option<usize>> = placed[index]
541            .iter()
542            .map(|place| place.map(|(measure, within)| starts[measure][index] + within))
543            .collect();
544        for spanner in part.spanners() {
545            let mut spanner = spanner.clone();
546            spanner.move_places(&moved);
547            active.labels.spanners.push(spanner);
548        }
549    }
550    for (offset, measure) in measures {
551        active.events.push(StreamEvent::new(offset, measure));
552    }
553    active.sort_events();
554    Ok(active)
555}
556
557#[cfg(test)]
558mod tests {
559    use super::*;
560    use crate::note::Note;
561    use crate::spanner::Spanner;
562
563    fn part_of(names: &[&str]) -> Result<Stream> {
564        let mut measure = Stream::with_kind(StreamKind::Measure);
565        measure.insert(0.0, Clef::best_for(&[], false));
566        for (offset, name) in names.iter().enumerate() {
567            measure.insert(offset as FloatType, Note::from_name(name)?);
568        }
569        let mut part = Stream::with_kind(StreamKind::Part);
570        part.insert(0.0, measure);
571        Ok(part)
572    }
573
574    fn slurred(stream: &Stream) -> Vec<Vec<String>> {
575        let leaves = stream.leaves();
576        stream
577            .spanners()
578            .iter()
579            .map(|spanner| {
580                spanner
581                    .spanned()
582                    .iter()
583                    .map(|place| match place.map(|place| leaves[place].1) {
584                        Some(StreamElement::Note(note)) => note.pitch().name_with_octave(),
585                        _ => "-".to_string(),
586                    })
587                    .collect()
588            })
589            .collect()
590    }
591
592    #[test]
593    fn a_parts_spanners_follow_its_notes_into_a_voice() -> Result<()> {
594        let mut upper = part_of(&["C5", "D5"])?;
595        upper.add_spanner(Spanner::slur(vec![1, 2]));
596        let mut lower = part_of(&["E3", "F3"])?;
597        lower.add_spanner(Spanner::slur(vec![1, 2]));
598        let mut score = Stream::with_kind(StreamKind::Score);
599        score.insert(0.0, upper);
600        score.insert(0.0, lower);
601
602        let joined = score.implode()?;
603        let parts = joined.parts();
604        assert_eq!(parts.len(), 1);
605        assert_eq!(
606            slurred(parts[0]),
607            vec![
608                vec!["C5".to_string(), "D5".to_string()],
609                vec!["E3".to_string(), "F3".to_string()]
610            ]
611        );
612        Ok(())
613    }
614
615    #[test]
616    fn what_music21_refuses_is_refused() -> Result<()> {
617        // A part with measures but no voices has no id to name a part by.
618        assert!(part_of(&["C4"])?.voices_to_parts(true).is_err());
619        let mut score = Stream::with_kind(StreamKind::Score);
620        score.insert(0.0, part_of(&["C4"])?);
621        assert!(
622            score
623                .parts_to_voices(&VoiceAllocation::Groups(vec![vec![0, 1]]), false, true)
624                .is_err()
625        );
626        assert!(
627            score
628                .parts_to_voices(&VoiceAllocation::Each(0), false, true)
629                .is_err()
630        );
631        Ok(())
632    }
633}