Skip to main content

music21/stream/
template.rs

1//! A stream's skeleton without its notes, a note added into what already
2//! sounds, and voices that hold one line taken back out: music21's
3//! `template`, `insertIntoNoteOrChord` and `flattenUnnecessaryVoices`.
4
5use super::{Stream, StreamElement, StreamEvent, StreamKind};
6use crate::{
7    chord::Chord,
8    defaults::FloatType,
9    duration::Duration,
10    error::{Error, Result},
11    makenotation::{event_order, op_frac},
12    notation::StemDirection,
13    note::Note,
14    pitch::Pitch,
15    rest::Rest,
16};
17
18/// Where an event of a template came from: a leaf by its old position, a
19/// stream by where its leaves started and where each went, or nowhere, for
20/// a rest put in.
21enum Origin {
22    Leaf(usize),
23    Stream(usize, Vec<Option<usize>>),
24    New,
25}
26
27/// What [`Stream::template`] keeps: music21's `template` arguments.
28#[derive(Clone, Copy, Debug)]
29#[non_exhaustive]
30pub struct TemplateOptions {
31    /// Whether what is taken away leaves rests in its place: music21's
32    /// `fillWithRests`.
33    pub fill_with_rests: bool,
34    /// Which elements are taken away: music21's `removeClasses`, by default
35    /// notes, chords, rests and the like, dynamics and expressions.
36    pub remove: fn(&StreamElement) -> bool,
37    /// Whether voices are kept, emptied as everything else is: music21's
38    /// `retainVoices`. Without, a voice goes as a note does.
39    pub retain_voices: bool,
40    /// Whether everything but the streams is taken away: music21's
41    /// `removeAll`.
42    pub remove_all: bool,
43    /// Elements kept whatever else says: music21's `exemptFromRemove`.
44    pub exempt: Option<fn(&StreamElement) -> bool>,
45}
46
47impl Default for TemplateOptions {
48    fn default() -> Self {
49        Self {
50            fill_with_rests: true,
51            remove: removed_by_default,
52            retain_voices: true,
53            remove_all: false,
54            exempt: None,
55        }
56    }
57}
58
59/// What music21's `template` takes away unless told otherwise: its
60/// `GeneralNote`s -- notes, chords, rests, unpitched strokes, percussion
61/// chords and chord symbols -- its dynamics, and its expressions written
62/// on their own: text expressions, rehearsal marks and repeat expressions.
63pub fn removed_by_default(element: &StreamElement) -> bool {
64    matches!(
65        element,
66        StreamElement::Note(_)
67            | StreamElement::Chord(_)
68            | StreamElement::Rest(_)
69            | StreamElement::Unpitched(_)
70            | StreamElement::PercussionChord(_)
71            | StreamElement::ChordSymbol(_)
72            | StreamElement::Dynamic(_)
73            | StreamElement::TextExpression(_)
74            | StreamElement::RehearsalMark(_)
75            | StreamElement::RepeatExpression(_)
76    )
77}
78
79impl Stream {
80    /// The stream and every stream inside it with what `options` says
81    /// taken away, a rest standing in for each stretch of what went where
82    /// asked: music21's `template`. Each run of elements taken away between
83    /// two kept is one rest, from where the first starts to where the
84    /// longest of them ends. Spanners stay, naming nothing for what is gone,
85    /// unless `remove_all` takes everything.
86    pub fn template(&self, options: &TemplateOptions) -> Stream {
87        self.template_moved(options).0
88    }
89
90    /// [`Stream::template`], and where each of this stream's leaves went in
91    /// it, by old position.
92    fn template_moved(&self, options: &TemplateOptions) -> (Stream, Vec<Option<usize>>) {
93        // Each event of the template with where it came from.
94        let mut events: Vec<(StreamEvent, Origin)> = Vec::new();
95        // The stretch of what has been taken away since the last kept.
96        let mut pending: Option<(FloatType, FloatType)> = None;
97        let close = |events: &mut Vec<(StreamEvent, Origin)>,
98                     pending: &mut Option<(FloatType, FloatType)>| {
99            if let Some((start, end)) = pending.take()
100                && let Ok(duration) = Duration::new(op_frac(end - start))
101            {
102                events.push((StreamEvent::new(start, Rest::new(duration)), Origin::New));
103            }
104        };
105        let mut first_leaf = 0;
106        for event in self.events() {
107            let element = event.element();
108            let leaves = leaf_count(element);
109            let start = first_leaf;
110            first_leaf += leaves;
111            if let StreamElement::Stream(inner) = element
112                && (options.retain_voices || !is_voice(element))
113            {
114                close(&mut events, &mut pending);
115                let (inner, moved) = inner.template_moved(options);
116                events.push((
117                    StreamEvent::new(event.offset(), inner),
118                    Origin::Stream(start, moved),
119                ));
120                continue;
121            }
122            let mut skip = options.remove_all
123                || (options.remove)(element)
124                || (!options.retain_voices && is_voice(element));
125            if options.exempt.is_some_and(|exempt| exempt(element)) {
126                skip = false;
127            }
128            if skip {
129                if !options.fill_with_rests {
130                    continue;
131                }
132                let length = element.quarter_length();
133                if length != 0.0 {
134                    let end = event.offset() + length;
135                    match &mut pending {
136                        None => pending = Some((event.offset(), end)),
137                        Some((_, existing)) if end > *existing => *existing = end,
138                        Some(_) => {}
139                    }
140                }
141            } else {
142                close(&mut events, &mut pending);
143                let origin = match element {
144                    StreamElement::Stream(_) => {
145                        Origin::Stream(start, (0..leaves).map(Some).collect())
146                    }
147                    _ => Origin::Leaf(start),
148                };
149                events.push((event.clone(), origin));
150            }
151        }
152        close(&mut events, &mut pending);
153        events.sort_by(|left, right| event_order(&left.0, &right.0));
154        let mut moved: Vec<Option<usize>> = vec![None; first_leaf];
155        let mut placed = 0;
156        for (event, origin) in &events {
157            match origin {
158                Origin::Leaf(old) => moved[*old] = Some(placed),
159                Origin::Stream(start, inner) => {
160                    for (offset, place) in inner.iter().enumerate() {
161                        moved[start + offset] = place.map(|place| place + placed);
162                    }
163                }
164                Origin::New => {}
165            }
166            placed += leaf_count(event.element());
167        }
168        // music21's `cloneEmpty` keeps a measure's number and padding and a
169        // part's name, but not whether either is shown, nor how measures are
170        // numbered.
171        let mut template = self.with_events(events.into_iter().map(|(event, _)| event).collect());
172        template.set_number_hidden(false);
173        template.set_measure_numbering(None);
174        template.set_name_hidden(false);
175        template.set_abbreviation_hidden(false);
176        // A measure's barlines are among the elements music21 takes away
177        // when it takes everything.
178        if options.remove_all {
179            template.set_left_barline(None);
180            template.set_right_barline(None);
181        }
182        if !options.remove_all {
183            for spanner in self.spanners() {
184                let mut spanner = spanner.clone();
185                spanner.move_places(&moved);
186                template.add_spanner(spanner);
187            }
188        }
189        (template, moved)
190    }
191
192    /// Adds a note or chord where something already starts within its
193    /// length, merging the two into one chord: music21's
194    /// `insertIntoNoteOrChord`. Where a rest starts there it gives way to
195    /// the note or chord; where nothing does, the note or chord is simply
196    /// inserted. The merged chord, or the note or rest a merge of one pitch
197    /// or none makes, keeps the length, articulations, expressions, lyrics,
198    /// stem and notehead fill of what stood there; with `chords_only`, a
199    /// merge of one pitch is still a chord. An unpitched note or percussion
200    /// chord standing there takes no pitches in, and becomes a rest, as in
201    /// music21.
202    ///
203    /// # Errors
204    ///
205    /// More than one note, chord or rest starting within the length, which
206    /// music21 refuses; a chord symbol whose pitches cannot be read; or
207    /// lyrics to carry onto a chord of no pitches.
208    pub fn insert_into_note_or_chord(
209        &mut self,
210        offset: FloatType,
211        element: StreamElement,
212        chords_only: bool,
213    ) -> Result<()> {
214        let end = op_frac(offset + element.quarter_length());
215        let targets: Vec<usize> = self
216            .events()
217            .iter()
218            .enumerate()
219            .filter(|(_, event)| {
220                matches!(
221                    event.element(),
222                    StreamElement::Note(_)
223                        | StreamElement::Chord(_)
224                        | StreamElement::Rest(_)
225                        | StreamElement::Unpitched(_)
226                        | StreamElement::PercussionChord(_)
227                        | StreamElement::ChordSymbol(_)
228                ) && offset <= event.offset()
229                    && (event.offset() < end
230                        || (end <= offset
231                            && event.offset() == offset
232                            && event.element().quarter_length() == 0.0))
233            })
234            .map(|(index, _)| index)
235            .collect();
236        let placed = match targets.as_slice() {
237            [] => element,
238            [index] => {
239                let target = self.events[*index].element().clone();
240                let placed = merged(&target, &element, chords_only)?;
241                let position: usize = self.events[..*index]
242                    .iter()
243                    .map(|event| leaf_count(event.element()))
244                    .sum();
245                self.retain_leaves(&mut |leaf, _| leaf != position);
246                placed
247            }
248            _ => {
249                return Err(Error::Stream(
250                    "more than one element found at the specified offset".to_string(),
251                ));
252            }
253        };
254        self.insert_sorted(vec![StreamEvent::new(offset, placed)]);
255        Ok(())
256    }
257
258    /// Takes away the voices holding nothing and, where one voice is left,
259    /// puts what it holds back in the stream itself: music21's
260    /// `flattenUnnecessaryVoices`. With `force`, every voice left is
261    /// flattened so.
262    pub fn flatten_unnecessary_voices(&mut self, force: bool) {
263        if !self.events.iter().any(|event| is_voice(event.element())) {
264            return;
265        }
266        self.events.retain(|event| {
267            let empty = event
268                .element()
269                .as_stream()
270                .is_some_and(|inner| inner.events().is_empty());
271            !(is_voice(event.element()) && empty)
272        });
273        let voices = self
274            .events
275            .iter()
276            .filter(|event| is_voice(event.element()))
277            .count();
278        if voices == 1 || force {
279            // Each event with where its leaves started, and the voices'
280            // spanners named by the stream's own leaves.
281            let mut held: Vec<(StreamEvent, usize)> = Vec::new();
282            let mut lifted = Vec::new();
283            let mut first = 0;
284            for event in std::mem::take(&mut self.events) {
285                match event.element() {
286                    StreamElement::Stream(inner) if inner.kind() == StreamKind::Voice => {
287                        let count = inner.leaves().len();
288                        let shift: Vec<Option<usize>> = (first..first + count).map(Some).collect();
289                        for spanner in inner.spanners() {
290                            let mut spanner = spanner.clone();
291                            spanner.move_places(&shift);
292                            lifted.push(spanner);
293                        }
294                        for inner_event in inner.events() {
295                            let leaves = leaf_count(inner_event.element());
296                            held.push((
297                                StreamEvent::new(
298                                    op_frac(event.offset() + inner_event.offset()),
299                                    inner_event.element().clone(),
300                                ),
301                                first,
302                            ));
303                            first += leaves;
304                        }
305                    }
306                    element => {
307                        let leaves = leaf_count(element);
308                        held.push((event, first));
309                        first += leaves;
310                    }
311                }
312            }
313            held.sort_by(|left, right| event_order(&left.0, &right.0));
314            let mut moved: Vec<Option<usize>> = vec![None; first];
315            let mut placed = 0;
316            for (event, start) in &held {
317                let leaves = leaf_count(event.element());
318                for offset in 0..leaves {
319                    moved[start + offset] = Some(placed + offset);
320                }
321                placed += leaves;
322            }
323            self.events = held.into_iter().map(|(event, _)| event).collect();
324            let mut spanners: Vec<_> = self.spanners().to_vec();
325            spanners.extend(lifted);
326            self.clear_spanners();
327            for mut spanner in spanners {
328                spanner.move_places(&moved);
329                self.add_spanner(spanner);
330            }
331        }
332    }
333}
334
335/// Whether an element is a voice.
336fn is_voice(element: &StreamElement) -> bool {
337    matches!(element, StreamElement::Stream(inner) if inner.kind() == StreamKind::Voice)
338}
339
340/// How many of [`Stream::leaves`] an element is.
341fn leaf_count(element: &StreamElement) -> usize {
342    match element {
343        StreamElement::Stream(inner) => inner.leaves().len(),
344        _ => 1,
345    }
346}
347
348/// The pitches and notes of a note, chord or chord symbol, none for
349/// anything else.
350fn parts_of(element: &StreamElement) -> Result<(Vec<Pitch>, Vec<Note>)> {
351    Ok(match element {
352        StreamElement::Note(note) => (vec![note.pitch().clone()], vec![note.clone()]),
353        StreamElement::Chord(chord) => (chord.pitches(), chord.notes().to_vec()),
354        StreamElement::ChordSymbol(symbol) => {
355            let pitches = symbol.pitches()?;
356            let notes = pitches.iter().cloned().map(Note::from_pitch).collect();
357            (pitches, notes)
358        }
359        _ => (Vec::new(), Vec::new()),
360    })
361}
362
363/// What music21's `insertIntoNoteOrChord` makes of what stood there and
364/// what is put in with it.
365fn merged(
366    target: &StreamElement,
367    added: &StreamElement,
368    chords_only: bool,
369) -> Result<StreamElement> {
370    // A rest gives way to what is added and a note, chord or chord symbol
371    // takes it in; anything else, unpitched, takes nothing in.
372    let (mut pitches, mut components) = parts_of(target)?;
373    if matches!(
374        target,
375        StreamElement::Rest(_)
376            | StreamElement::Note(_)
377            | StreamElement::Chord(_)
378            | StreamElement::ChordSymbol(_)
379    ) {
380        let (added_pitches, added_components) = parts_of(added)?;
381        pitches.extend(added_pitches);
382        components.extend(added_components);
383    }
384    let duration = target.duration().cloned().unwrap_or_default();
385    let (articulations, expressions, lyrics, stem, fill) = match target {
386        StreamElement::Note(note) => (
387            note.articulations().to_vec(),
388            note.expressions().to_vec(),
389            note.lyrics().to_vec(),
390            Some(note.stem_direction()),
391            Some(note.notehead_fill()),
392        ),
393        StreamElement::Chord(chord) => (
394            chord.articulations().to_vec(),
395            chord.expressions().to_vec(),
396            chord.lyrics().to_vec(),
397            Some(chord.stem_direction()),
398            Some(chord.notehead_fill()),
399        ),
400        StreamElement::Rest(rest) => (
401            rest.articulations().to_vec(),
402            rest.expressions().to_vec(),
403            rest.lyrics().to_vec(),
404            None,
405            None,
406        ),
407        StreamElement::ChordSymbol(symbol) => (
408            Vec::new(),
409            Vec::new(),
410            symbol.lyrics().to_vec(),
411            Some(StemDirection::default()),
412            Some(None),
413        ),
414        StreamElement::Unpitched(unpitched) => {
415            let written = unpitched.written();
416            (
417                written.articulations().to_vec(),
418                written.expressions().to_vec(),
419                written.lyrics().to_vec(),
420                Some(written.stem_direction()),
421                Some(written.notehead_fill()),
422            )
423        }
424        StreamElement::PercussionChord(chord) => {
425            let written = chord.written();
426            (
427                written.articulations().to_vec(),
428                written.expressions().to_vec(),
429                written.lyrics().to_vec(),
430                Some(written.stem_direction()),
431                Some(written.notehead_fill()),
432            )
433        }
434        _ => (Vec::new(), Vec::new(), Vec::new(), None, None),
435    };
436    let texts: Vec<String> = lyrics
437        .iter()
438        .filter_map(|lyric| lyric.explicit_text())
439        .filter(|text| !text.is_empty())
440        .collect();
441    if pitches.len() > 1 || chords_only {
442        let mut chord = Chord::new(pitches.as_slice())?.with_duration(duration);
443        chord.articulations_mut().extend(articulations);
444        chord.expressions_mut().extend(expressions);
445        for text in &texts {
446            chord.add_lyric(text, None, false)?;
447        }
448        if let Some(stem) = stem {
449            chord.set_stem_direction(stem);
450        }
451        if let Some(fill) = fill {
452            chord.set_notehead_fill(fill);
453        }
454        for (note, component) in chord.notes_mut().iter_mut().zip(&components) {
455            note.set_notehead_fill(component.notehead_fill());
456        }
457        Ok(StreamElement::Chord(chord))
458    } else if let [pitch] = pitches.as_slice() {
459        let mut note = Note::from_pitch(pitch.clone()).with_duration(duration);
460        note.articulations_mut().extend(articulations);
461        note.expressions_mut().extend(expressions);
462        for text in &texts {
463            note.add_lyric(text, None, false)?;
464        }
465        if let Some(stem) = stem {
466            note.set_stem_direction(stem);
467        }
468        if let Some(fill) = fill {
469            note.set_notehead_fill(fill);
470        }
471        Ok(StreamElement::Note(note))
472    } else {
473        let mut rest = Rest::new(duration);
474        rest.articulations_mut().extend(articulations);
475        rest.expressions_mut().extend(expressions);
476        for text in &texts {
477            rest.add_lyric(text, None, false);
478        }
479        Ok(StreamElement::Rest(rest))
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    use super::*;
486    use crate::tinynotation::from_tiny_notation;
487
488    #[test]
489    fn a_template_keeps_the_skeleton_and_rests_where_notes_were() -> Result<()> {
490        let line = from_tiny_notation("4/4 c4 d e f g1")?;
491        let template = line.template(&TemplateOptions::default());
492        let rests: Vec<(FloatType, FloatType)> = template
493            .recurse()
494            .into_iter()
495            .filter_map(|(offset, element)| match element {
496                StreamElement::Rest(rest) => Some((offset, rest.duration().quarter_length())),
497                _ => None,
498            })
499            .collect();
500        // music21: one rest a measure, as long as what it held.
501        assert_eq!(rests, [(0.0, 4.0), (4.0, 4.0)]);
502        Ok(())
503    }
504
505    /// `remove_all` takes a measure's barlines with everything else, which
506    /// music21 holds among the elements it removes.
507    #[test]
508    fn removing_all_takes_the_barlines() -> Result<()> {
509        let line = from_tiny_notation("4/4 c4 d e f")?;
510        let options = TemplateOptions {
511            remove_all: true,
512            ..TemplateOptions::default()
513        };
514        let template = line.template(&options);
515        let measures = template.measures();
516        assert!(measures.iter().all(|bar| bar.right_barline().is_none()));
517        assert!(line.measures()[0].right_barline().is_some());
518        Ok(())
519    }
520
521    #[test]
522    fn a_note_is_merged_into_what_starts_there() -> Result<()> {
523        let mut line = from_tiny_notation("4/4 c4 r d e")?;
524        let measure = match line.events_mut()[0].element_mut() {
525            StreamElement::Stream(measure) => measure,
526            _ => panic!("a measure"),
527        };
528        let note = StreamElement::Note(Note::from_name("G4")?);
529        measure.insert_into_note_or_chord(0.0, note.clone(), false)?;
530        measure.insert_into_note_or_chord(1.0, note, false)?;
531        let kinds: Vec<String> = measure
532            .events()
533            .iter()
534            .filter_map(|event| match event.element() {
535                StreamElement::Chord(chord) => Some(format!("chord {}", chord.pitches().len())),
536                StreamElement::Note(note) => Some(format!("note {}", note.pitch().name())),
537                StreamElement::Rest(_) => Some("rest".to_string()),
538                _ => None,
539            })
540            .collect();
541        assert_eq!(kinds, ["chord 2", "note G", "note D", "note E"]);
542        Ok(())
543    }
544}