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(
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 pub fn explode(&self) -> Result<Stream> {
371 self.voices_to_parts(false)
372 }
373
374 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 pub fn implode(&self) -> Result<Stream> {
461 self.parts_to_voices(&VoiceAllocation::default(), false, true)
462 }
463}
464
465fn join_as_voices(group: &[&Stream], set_stems: bool) -> Result<Stream> {
467 let mut active = Stream::with_kind(StreamKind::Part);
468 let mut measures: Vec<(FloatType, Stream)> = Vec::new();
470 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 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 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}