1use 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#[derive(Clone, Debug, PartialEq, Eq)]
19pub enum VoiceAllocation {
20 Each(usize),
23 Groups(Vec<Vec<usize>>),
25}
26
27impl Default for VoiceAllocation {
28 fn default() -> Self {
30 Self::Each(2)
31 }
32}
33
34fn id_text(stream: &Stream) -> String {
36 stream.id().unwrap_or_default().to_string()
37}
38
39fn 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
53fn 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
66fn 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
91fn is_measure_setting(element: &StreamElement) -> bool {
94 ["Barline", "TimeSignature", "Clef", "KeySignature"]
95 .into_iter()
96 .any(|class| element.is_instance(class))
97}
98
99fn 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
131fn 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
149fn 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 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 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 pub fn explode(&self) -> Result<Stream> {
369 self.voices_to_parts(false)
370 }
371
372 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 pub fn implode(&self) -> Result<Stream> {
459 self.parts_to_voices(&VoiceAllocation::default(), false, true)
460 }
461}
462
463fn join_as_voices(group: &[&Stream], set_stems: bool) -> Result<Stream> {
465 let mut active = Stream::with_kind(StreamKind::Part);
466 let mut measures: Vec<(FloatType, Stream)> = Vec::new();
468 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 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 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}