Skip to main content

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