1use super::exact::{Exact, at_offset};
6use super::{Stream, StreamElement, StreamEvent};
7use crate::defaults::{FloatType, IntegerType};
8use crate::duration::Duration;
9use crate::error::{Error, Result};
10use crate::key::KeySignature;
11use crate::makenotation::{event_order, op_frac};
12use crate::meter::{TimeSignature, best_time_signature};
13use crate::notation::{Tie, TieType};
14use crate::pitch::Pitch;
15
16fn stream_error(message: impl Into<String>) -> Error {
17 Error::Stream(message.into())
18}
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum Anchor {
24 Lowest,
26 Highest,
28 Zero,
30}
31
32fn flat_order(
35 a: (FloatType, &StreamElement),
36 b: (FloatType, &StreamElement),
37) -> std::cmp::Ordering {
38 let grace = |element: &StreamElement| element.duration().is_some_and(Duration::is_grace);
39 a.0.total_cmp(&b.0)
40 .then(a.1.class_sort_order().cmp(&b.1.class_sort_order()))
41 .then(grace(b.1).cmp(&grace(a.1)))
42}
43
44#[derive(Clone, Debug)]
47struct Sounded {
48 leaf: usize,
49 note: usize,
50 name: String,
51 tie: Option<Tie>,
52 kept: bool,
54}
55
56fn sounded(leaf: usize, element: &StreamElement) -> Option<Vec<Sounded>> {
57 let of = |note: usize, pitch: &Pitch, tie: Option<&Tie>, kept: bool| Sounded {
58 leaf,
59 note,
60 name: pitch.name_with_octave(),
61 tie: tie.cloned(),
62 kept,
63 };
64 Some(match element {
65 StreamElement::Note(note) => vec![of(0, note.pitch(), note.tie(), true)],
66 StreamElement::Chord(chord) => chord
67 .notes()
68 .iter()
69 .enumerate()
70 .map(|(index, note)| of(index, note.pitch(), note.tie(), true))
71 .collect(),
72 StreamElement::ChordSymbol(symbol) => symbol
73 .pitches()
74 .unwrap_or_default()
75 .iter()
76 .enumerate()
77 .map(|(index, pitch)| of(index, pitch, None, false))
78 .collect(),
79 _ => return None,
80 })
81}
82
83impl Stream {
84 pub fn extend_ties(&mut self, ignore_rests: bool) {
107 let leaves = self.leaves();
110 let mut flat: Vec<(usize, FloatType, &StreamElement)> = leaves
111 .iter()
112 .enumerate()
113 .filter(|(_, (_, element))| element.is_instance("NotRest"))
114 .map(|(leaf, (offset, element))| (leaf, *offset, *element))
115 .collect();
116 flat.sort_by(|a, b| flat_order((a.1, a.2), (b.1, b.2)));
117 let mut pitches: Vec<Option<Vec<Sounded>>> = flat
118 .iter()
119 .map(|(leaf, _, element)| sounded(*leaf, element))
120 .collect();
121 for i in 0..flat.len() {
122 if pitches[i].is_none() || i + 1 == flat.len() {
123 continue;
124 }
125 let target = if ignore_rests {
128 Exact::held(flat[i + 1].1)
129 } else {
130 Exact::held(flat[i].1).plus(Exact::held(flat[i].2.quarter_length()))
131 };
132 let connections: Vec<usize> = (0..flat.len())
133 .filter(|&j| at_offset(flat[j].1, flat[j].2.quarter_length(), target))
134 .collect();
135 let sources = pitches[i].as_ref().map_or(0, Vec::len);
136 for p in 0..sources {
137 for &m in &connections {
138 let count = pitches[m].as_ref().map_or(0, Vec::len);
139 for q in 0..count {
140 let (ours, theirs) = match (&pitches[i], &pitches[m]) {
141 (Some(ours), Some(theirs)) => (&ours[p].name, &theirs[q].name),
142 _ => continue,
143 };
144 if ours != theirs {
145 continue;
146 }
147 if let Some(sources) = pitches[i].as_mut() {
148 let source = &mut sources[p];
149 match source.tie.as_mut() {
150 None => source.tie = Some(Tie::new(TieType::Start)),
151 Some(tie) if tie.tie_type() == TieType::Stop => {
152 tie.set_tie_type(TieType::Continue);
153 }
154 Some(_) => {}
155 }
156 }
157 if let Some(targets) = pitches[m].as_mut() {
158 targets[q].tie = Some(Tie::new(TieType::Stop));
159 }
160 break;
161 }
162 }
163 }
164 }
165 let mut ties: std::collections::HashMap<(usize, usize), Option<Tie>> =
166 std::collections::HashMap::new();
167 for list in pitches.into_iter().flatten() {
168 for sounded in list.into_iter().filter(|sounded| sounded.kept) {
169 ties.insert((sounded.leaf, sounded.note), sounded.tie);
170 }
171 }
172 let mut leaf = 0;
173 self.for_each_mut(&mut |_, element| {
174 match element {
175 StreamElement::Note(note) => {
176 if let Some(tie) = ties.get(&(leaf, 0)) {
177 note.set_tie(tie.clone());
178 }
179 }
180 StreamElement::Chord(chord) => {
181 for (index, note) in chord.notes_mut().iter_mut().enumerate() {
182 if let Some(tie) = ties.get(&(leaf, index)) {
183 note.set_tie(tie.clone());
184 }
185 }
186 }
187 _ => {}
188 }
189 leaf += 1;
190 });
191 }
192
193 pub fn scale_offsets(
201 &self,
202 amount: FloatType,
203 anchor: Anchor,
204 nested: Anchor,
205 ) -> Result<Stream> {
206 if amount.partial_cmp(&0.0) != Some(std::cmp::Ordering::Greater) {
207 return Err(stream_error("amountToScale must be greater than zero"));
208 }
209 let mut out = self.clone();
210 out.scale_offsets_in_place(amount, anchor, nested);
211 Ok(out)
212 }
213
214 fn scale_offsets_in_place(&mut self, amount: FloatType, anchor: Anchor, nested: Anchor) {
215 let shift = match anchor {
216 Anchor::Lowest => self.lowest_offset(),
217 Anchor::Highest => self.highest_offset(),
218 Anchor::Zero => 0.0,
219 };
220 for event in self.events_mut() {
221 let offset = op_frac((event.offset() - shift) * amount + shift);
222 let mut element = event.element().clone();
223 if let StreamElement::Stream(inner) = &mut element {
224 inner.scale_offsets_in_place(amount, nested, nested);
225 }
226 *event = StreamEvent::new(offset, element);
227 }
228 }
229
230 pub fn scale_durations(&self, amount: FloatType) -> Result<Stream> {
237 if amount.partial_cmp(&0.0) != Some(std::cmp::Ordering::Greater) {
238 return Err(stream_error("amountToScale must be greater than zero"));
239 }
240 let mut out = self.clone();
241 let mut failed = None;
242 out.for_each_mut(&mut |_, element| {
243 if failed.is_some() {
244 return;
245 }
246 if let Err(error) = scale_duration(element, amount) {
247 failed = Some(error);
248 }
249 });
250 failed.map_or(Ok(out), Err)
251 }
252
253 pub fn augment_or_diminish(&self, amount: FloatType) -> Result<Stream> {
270 self.scale_offsets(amount, Anchor::Lowest, Anchor::Zero)?
271 .scale_durations(amount)
272 }
273
274 pub fn invert_diatonic(&self, inversion: Option<&Pitch>) -> Result<Stream> {
284 let inversion = match inversion {
285 Some(pitch) => pitch.diatonic_note_number(),
286 None => Pitch::from_name("C4")?.diatonic_note_number(),
287 };
288 let signatures: Vec<KeySignature> = self
289 .recurse()
290 .into_iter()
291 .filter_map(|(_, element)| signature_of(element))
292 .collect();
293 let only = match signatures.len() {
294 0 => Some(KeySignature::new(0)),
295 1 => signatures.into_iter().next(),
296 _ => None,
297 };
298 let leaves = self.leaves();
301 let mut order: Vec<usize> = (0..leaves.len()).collect();
302 order.sort_by(|a, b| flat_order(leaves[*a], leaves[*b]));
303 let mut in_force: std::collections::HashMap<usize, KeySignature> =
304 std::collections::HashMap::new();
305 let mut current: Option<KeySignature> = None;
306 for leaf in order {
307 if let Some(signature) = signature_of(leaves[leaf].1) {
308 current = Some(signature);
309 }
310 if let Some(signature) = ¤t {
311 in_force.insert(leaf, signature.clone());
312 }
313 }
314 let mut out = self.clone();
315 let mut leaf = 0;
316 let mut failed = None;
317 out.for_each_mut(&mut |_, element| {
318 if let StreamElement::Note(note) = element
319 && failed.is_none()
320 {
321 let signature = only.as_ref().or_else(|| in_force.get(&leaf));
322 if let Err(error) = invert_note(note, inversion, signature) {
323 failed = Some(error);
324 }
325 }
326 leaf += 1;
327 });
328 failed.map_or(Ok(out), Err)
329 }
330
331 pub fn shift_elements(
335 &mut self,
336 offset: FloatType,
337 start: Option<FloatType>,
338 end: Option<FloatType>,
339 ) {
340 let events: Vec<(StreamEvent, Option<usize>)> = self
341 .events()
342 .iter()
343 .enumerate()
344 .map(|(index, event)| {
345 let at = event.offset();
346 let moves = start.is_none_or(|start| at >= start) && end.is_none_or(|end| at < end);
347 let offset = if moves { op_frac(at + offset) } else { at };
348 (
349 StreamEvent::new(offset, event.element().clone()),
350 Some(index),
351 )
352 })
353 .collect();
354 self.reorder_events(events);
355 }
356
357 fn reorder_events(&mut self, mut events: Vec<(StreamEvent, Option<usize>)>) {
360 events.sort_by(|a, b| event_order(&a.0, &b.0));
361 self.replace_events(events);
362 }
363
364 pub fn repeat_append(&mut self, element: &StreamElement, times: usize) {
367 for _ in 0..times {
368 let offset = self.end_offset();
369 self.insert_sorted(vec![StreamEvent::new(offset, element.clone())]);
370 }
371 }
372
373 pub fn repeat_insert(&mut self, element: &StreamElement, offsets: &[FloatType]) {
376 self.insert_sorted(
377 offsets
378 .iter()
379 .map(|offset| StreamEvent::new(op_frac(*offset), element.clone()))
380 .collect(),
381 );
382 }
383
384 pub fn insert_and_shift(&mut self, offset: FloatType, element: StreamElement) {
388 let end = offset + element.quarter_length();
389 let nearest = self
390 .events()
391 .iter()
392 .map(StreamEvent::offset)
393 .filter(|at| at - offset >= 0.0)
394 .fold(None, |best: Option<FloatType>, at| {
395 Some(best.map_or(at, |best| {
396 if at - offset < best - offset {
397 at
398 } else {
399 best
400 }
401 }))
402 });
403 let shift = nearest.map_or(0.0, |nearest| end - nearest);
404 if shift > 0.0 {
405 let events: Vec<(StreamEvent, Option<usize>)> = self
406 .events()
407 .iter()
408 .enumerate()
409 .map(|(index, event)| {
410 let at = event.offset();
411 let moved = if at - offset >= 0.0 {
412 op_frac(at + shift)
413 } else {
414 at
415 };
416 (
417 StreamEvent::new(moved, event.element().clone()),
418 Some(index),
419 )
420 })
421 .collect();
422 self.reorder_events(events);
423 }
424 self.insert_sorted(vec![StreamEvent::new(op_frac(offset), element)]);
425 }
426
427 pub fn bar_duration_proportion(&self, meter: Option<&TimeSignature>) -> Result<FloatType> {
439 let bar = self.bar_length(meter)?;
440 self.proportion_of(bar)
441 }
442
443 fn proportion_of(&self, bar: FloatType) -> Result<FloatType> {
444 if bar == 0.0 {
445 return Err(stream_error("a bar of no length"));
446 }
447 Ok(op_frac(self.end_offset() / bar))
448 }
449
450 fn bar_length(&self, meter: Option<&TimeSignature>) -> Result<FloatType> {
451 let own = self
452 .events()
453 .iter()
454 .take_while(|event| event.offset() == 0.0)
455 .find_map(|event| match event.element() {
456 StreamElement::TimeSignature(found) => Some(found.clone()),
457 _ => None,
458 });
459 let meter = match (own, meter) {
460 (Some(own), _) => own,
461 (None, Some(given)) => given.clone(),
462 (None, None) => match best_time_signature(self) {
463 Ok(best) => best,
464 Err(_) => return Ok(self.end_offset()),
465 },
466 };
467 Ok(meter.bar_quarter_length())
468 }
469
470 pub fn pad_as_anacrusis(
480 &mut self,
481 meter: Option<&TimeSignature>,
482 use_initial_rests: bool,
483 ) -> Result<()> {
484 if use_initial_rests {
485 let rests: Vec<usize> = self
486 .events()
487 .iter()
488 .enumerate()
489 .filter(|(_, event)| event.element().is_instance("GeneralNote"))
490 .take_while(|(_, event)| matches!(event.element(), StreamElement::Rest(_)))
491 .map(|(index, _)| index)
492 .collect();
493 if !rests.is_empty() {
494 self.remove_shifting(&rests);
495 }
496 }
497 let bar = self.bar_length(meter)?;
498 let proportion = self.proportion_of(bar)?;
499 if proportion < 1.0 {
500 self.set_padding_left(op_frac(bar * (1.0 - proportion)));
501 }
502 Ok(())
503 }
504
505 fn remove_shifting(&mut self, indices: &[usize]) {
509 let mut offsets: Vec<FloatType> = self.events().iter().map(StreamEvent::offset).collect();
510 let mut gone = vec![false; offsets.len()];
511 let mut shift = 0.0;
512 for (i, &index) in indices.iter().enumerate() {
513 gone[index] = true;
514 let length = self.events()[index].element().quarter_length();
515 let region_start = offsets[index] + length;
516 let region_end = match indices.get(i + 1) {
517 Some(&next) => offsets[next],
518 None => self
519 .events()
520 .iter()
521 .zip(&offsets)
522 .zip(&gone)
523 .filter(|(_, gone)| !**gone)
524 .map(|((event, offset), _)| op_frac(offset + event.element().quarter_length()))
525 .fold(0.0, FloatType::max),
526 };
527 shift += length;
528 if shift != 0.0 {
529 let span = super::span::OffsetSpan {
530 include_end_boundary: false,
531 ..super::span::OffsetSpan::between(region_start, region_end)
532 };
533 for (index, at) in offsets.iter_mut().enumerate() {
534 if gone[index] {
535 continue;
536 }
537 if span.takes_at(*at, self.events[index].element().quarter_length()) {
538 *at = op_frac(*at - shift);
539 }
540 }
541 }
542 }
543 let events: Vec<(StreamEvent, Option<usize>)> = self
544 .events()
545 .iter()
546 .enumerate()
547 .filter(|(index, _)| !gone[*index])
548 .map(|(index, event)| {
549 (
550 StreamEvent::new(offsets[index], event.element().clone()),
551 Some(index),
552 )
553 })
554 .collect();
555 self.reorder_events(events);
556 }
557}
558
559fn signature_of(element: &StreamElement) -> Option<KeySignature> {
560 match element {
561 StreamElement::KeySignature(signature) => Some(signature.clone()),
562 StreamElement::Key(key) => Some(key.key_signature()),
563 _ => None,
564 }
565}
566
567fn invert_note(
568 note: &mut crate::note::Note,
569 inversion: IntegerType,
570 signature: Option<&KeySignature>,
571) -> Result<()> {
572 let mut pitch = note.pitch().clone();
573 let number = 2 * inversion - pitch.diatonic_note_number();
574 pitch.set_diatonic_note_number(number)?;
575 if let Some(signature) = signature {
576 let step = pitch.name().chars().next().unwrap_or('C');
577 let mut accidental = signature.accidental_by_step(step)?;
578 if let Some(accidental) = accidental.as_mut() {
579 accidental.set_display_status(None);
580 }
581 pitch.set_written_accidental(accidental);
582 }
583 note.set_pitch(pitch);
584 Ok(())
585}
586
587fn scale_duration(element: &mut StreamElement, amount: FloatType) -> Result<()> {
590 map_duration(element, &mut |duration| {
591 duration
593 .map(|duration| duration.augment_or_diminish(amount))
594 .transpose()
595 })
596}
597
598pub(crate) fn map_duration(
604 element: &mut StreamElement,
605 change: &mut impl FnMut(Option<&Duration>) -> Result<Option<Duration>>,
606) -> Result<()> {
607 match element {
608 StreamElement::Note(note) => {
609 if let Some(next) = change(note.duration())? {
610 note.set_duration(next);
611 }
612 }
613 StreamElement::Chord(chord) => {
614 if let Some(next) = change(chord.duration())? {
615 chord.set_duration(next);
616 }
617 }
618 StreamElement::Rest(rest) => {
619 if let Some(next) = change(Some(rest.duration()))? {
620 rest.set_duration(next);
621 }
622 }
623 StreamElement::Unpitched(stroke) => {
624 if let Some(next) = change(stroke.written().duration())? {
625 stroke.written_mut().set_duration(next);
626 }
627 }
628 StreamElement::PercussionChord(chord) => {
629 if let Some(next) = change(chord.written().duration())? {
630 chord.written_mut().set_duration(next);
631 }
632 }
633 StreamElement::ChordSymbol(symbol) => {
634 if let Some(next) = change(Some(symbol.duration()))? {
635 symbol.set_duration(next);
636 }
637 }
638 _ => {}
639 }
640 Ok(())
641}
642
643#[cfg(test)]
644mod tests {
645 use super::*;
646 use crate::note::Note;
647 use crate::rest::Rest;
648 use crate::stream::StreamKind;
649
650 fn note(name: &str, quarter_length: FloatType) -> Result<StreamElement> {
651 Ok(Note::from_name(name)?
652 .with_duration(Duration::new(quarter_length)?)
653 .into())
654 }
655
656 fn placed(stream: &Stream) -> Vec<(String, FloatType)> {
657 stream
658 .events()
659 .iter()
660 .filter_map(|event| match event.element() {
661 StreamElement::Note(note) => {
662 Some((note.pitch().name_with_octave(), event.offset()))
663 }
664 StreamElement::Rest(_) => Some(("rest".to_string(), event.offset())),
665 _ => None,
666 })
667 .collect()
668 }
669
670 fn named(pairs: &[(&str, FloatType)]) -> Vec<(String, FloatType)> {
671 pairs
672 .iter()
673 .map(|(name, offset)| ((*name).to_string(), *offset))
674 .collect()
675 }
676
677 #[test]
680 fn insert_and_shift_makes_room() -> Result<()> {
681 let mut stream = Stream::new();
682 stream.insert(0.0, note("C4", 2.0)?);
683 stream.insert(2.0, note("D4", 2.0)?);
684 stream.insert_and_shift(1.0, note("E4", 2.0)?);
685 assert_eq!(
686 placed(&stream),
687 named(&[("C4", 0.0), ("E4", 1.0), ("D4", 3.0)])
688 );
689 Ok(())
690 }
691
692 #[test]
693 fn shift_elements_moves_a_range() -> Result<()> {
694 let mut stream = Stream::new();
695 for (offset, name) in ["C4", "D4", "E4", "F4"].into_iter().enumerate() {
696 stream.insert(offset as FloatType, note(name, 1.0)?);
697 }
698 stream.shift_elements(1.0, Some(1.0), Some(3.0));
699 assert_eq!(
700 placed(&stream),
701 named(&[("C4", 0.0), ("D4", 2.0), ("E4", 3.0), ("F4", 3.0)])
702 );
703 Ok(())
704 }
705
706 #[test]
707 fn scale_offsets_holds_its_anchor() -> Result<()> {
708 let mut stream = Stream::new();
709 for (offset, name) in ["C4", "D4", "E4"].into_iter().enumerate() {
710 stream.insert(offset as FloatType + 1.0, note(name, 1.0)?);
711 }
712 let high = stream.scale_offsets(2.0, Anchor::Highest, Anchor::Zero)?;
713 assert_eq!(
714 placed(&high),
715 named(&[("C4", -1.0), ("D4", 1.0), ("E4", 3.0)])
716 );
717 let zero = stream.scale_offsets(2.0, Anchor::Zero, Anchor::Zero)?;
718 assert_eq!(
719 placed(&zero),
720 named(&[("C4", 2.0), ("D4", 4.0), ("E4", 6.0)])
721 );
722 Ok(())
723 }
724
725 #[test]
726 fn a_pickup_is_padded_to_its_bar() -> Result<()> {
727 let mut measure = Stream::with_kind(StreamKind::Measure);
728 measure.insert(0.0, TimeSignature::new(3, 4)?);
729 measure.insert(0.0, note("C4", 2.0)?);
730 assert_eq!(measure.bar_duration_proportion(None)?, op_frac(2.0 / 3.0));
731
732 let mut measure = Stream::with_kind(StreamKind::Measure);
733 measure.insert(0.0, TimeSignature::new(3, 4)?);
734 measure.insert(0.0, note("C4", 1.0)?);
735 measure.pad_as_anacrusis(None, false)?;
736 assert_eq!(measure.padding_left(), 2.0);
737 Ok(())
738 }
739
740 #[test]
741 fn without_a_time_signature_the_notes_say_the_bar() -> Result<()> {
742 let mut measure = Stream::with_kind(StreamKind::Measure);
743 measure.insert(0.0, Rest::new(Duration::quarter()));
744 measure.insert(1.0, note("C4", 1.0)?);
745 measure.pad_as_anacrusis(None, true)?;
746 assert_eq!(measure.padding_left(), 0.0);
747 assert_eq!(placed(&measure), named(&[("C4", 0.0)]));
748 assert!(
749 Stream::with_kind(StreamKind::Measure)
750 .bar_duration_proportion(None)
751 .is_err()
752 );
753 Ok(())
754 }
755}