Skip to main content

music21_rs/stream/
filling.rs

1//! Filling a stream from another, stretching what it holds, and emptying
2//! it: music21's `Stream.extendDuration`, `mergeElements` and `cloneEmpty`.
3
4use super::editing::map_duration;
5use super::{Stream, StreamKind};
6use crate::defaults::FloatType;
7use crate::duration::Duration;
8use crate::error::Result;
9use crate::makenotation::op_frac;
10
11impl Stream {
12    /// A copy of the stream with each element of a class stretched to
13    /// where the next one starts: music21's `extendDuration`.
14    ///
15    /// The last one reaches the end of the stream. Elements of other
16    /// classes are left alone and do not break the run, so a dynamic
17    /// standing between two notes does not stop the first note reaching
18    /// the second.
19    ///
20    /// Only what the crate gives a length to is stretched: a note, a rest,
21    /// a chord or a chord symbol. music21 would stretch any element, since
22    /// everything there carries a duration -- `extendDuration(Dynamic)`
23    /// gives the dynamic a length -- where the crate keeps the marks that
24    /// say what is in force from a point timeless. Asking for one of those
25    /// classes leaves the stream as it stands.
26    ///
27    /// ```
28    /// use music21_rs::{Dynamic, Note, Stream};
29    ///
30    /// let mut line = Stream::new();
31    /// for place in [0.0, 10.0, 20.0] {
32    ///     line.insert(place, Note::from_name("C4")?);
33    /// }
34    /// line.insert(15.0, Dynamic::new("ff"));
35    ///
36    /// let stretched = line.extend_duration(&["GeneralNote"])?;
37    /// let lengths: Vec<f64> = stretched
38    ///     .notes()
39    ///     .iter()
40    ///     .map(|(_, note)| note.quarter_length())
41    ///     .collect();
42    /// // Ten to the next note, ten again past the dynamic, and the last
43    /// // keeps the length it came with to the end of the stream.
44    /// assert_eq!(lengths, [10.0, 10.0, 1.0]);
45    /// # Ok::<(), music21_rs::Error>(())
46    /// ```
47    ///
48    /// # Errors
49    ///
50    /// A length no written value can be made of.
51    pub fn extend_duration(&self, classes: &[&str]) -> Result<Stream> {
52        let mut out = self.clone();
53        // music21 reads the whole length before stretching anything.
54        let total = out.end_offset();
55        let places: Vec<usize> = out
56            .events()
57            .iter()
58            .enumerate()
59            .filter(|(_, event)| {
60                classes
61                    .iter()
62                    .any(|class| event.element().is_instance(class))
63            })
64            .map(|(place, _)| place)
65            .collect();
66        for pair in places.windows(2) {
67            let span = op_frac(out.events()[pair[1]].offset() - out.events()[pair[0]].offset());
68            out.stretch(pair[0], span)?;
69        }
70        if let Some(&last) = places.last() {
71            let span = op_frac(total - out.events()[last].offset());
72            out.stretch(last, span)?;
73        }
74        Ok(out)
75    }
76
77    /// Writes one element's length, giving it one where it has none:
78    /// music21's elements all carry a duration, and `extendDuration`
79    /// writes to it.
80    fn stretch(&mut self, place: usize, quarter_length: FloatType) -> Result<()> {
81        let element = self.events[place].element_mut();
82        map_duration(element, &mut |_| Duration::new(quarter_length).map(Some))
83    }
84
85    /// Takes in everything another stream holds, each at the offset it
86    /// stands at there: music21's `mergeElements`.
87    ///
88    /// With `classes`, only the elements answering to one of those music21
89    /// class names come. music21 stores the other stream's own objects in
90    /// both streams; a crate stream owns what it holds, so they are
91    /// copied.
92    ///
93    /// ```
94    /// use music21_rs::{Note, Stream};
95    ///
96    /// let mut from = Stream::new();
97    /// from.insert(0.0, Note::from_name("F#4")?);
98    /// from.insert(1.0, Note::from_name("G4")?);
99    ///
100    /// let mut into = Stream::new();
101    /// into.merge_elements(&from, None);
102    /// assert_eq!(into.len(), 2);
103    /// # Ok::<(), music21_rs::Error>(())
104    /// ```
105    pub fn merge_elements(&mut self, other: &Stream, classes: Option<&[&str]>) {
106        for event in other.events() {
107            let wanted = classes.is_none_or(|classes| {
108                classes
109                    .iter()
110                    .any(|class| event.element().is_instance(class))
111            });
112            if wanted {
113                self.insert(event.offset(), event.element().clone());
114            }
115        }
116    }
117
118    /// A stream like this one holding nothing: music21's `cloneEmpty`.
119    ///
120    /// It is of the same kind and carries what music21's `mergeAttributes`
121    /// copies: the id -- and only where one was given, music21 leaving an
122    /// object's own address behind, which a crate stream has nothing of --
123    /// whether the stream is at sounding pitch, a measure's number, suffix
124    /// and padding, and a part's name and abbreviation. Nothing else
125    /// comes: not the metadata, the barlines or the spanners, which
126    /// [`Stream::template`](Self::template) keeps.
127    ///
128    /// ```
129    /// use music21_rs::{Note, Stream, StreamKind};
130    ///
131    /// let mut part = Stream::with_kind(StreamKind::Part);
132    /// part.set_id(Some("hi".to_string()));
133    /// part.set_name(Some("Flute".to_string()));
134    /// part.insert(0.0, Note::from_name("C4")?);
135    ///
136    /// let empty = part.clone_empty();
137    /// assert_eq!(empty.kind(), StreamKind::Part);
138    /// assert_eq!(empty.id(), Some("hi"));
139    /// assert_eq!(empty.name(), Some("Flute"));
140    /// assert!(empty.is_empty());
141    /// # Ok::<(), music21_rs::Error>(())
142    /// ```
143    pub fn clone_empty(&self) -> Stream {
144        let mut empty = Stream::with_kind(self.kind());
145        empty.labels.id = self.labels.id.clone();
146        empty.labels.at_sounding_pitch = self.labels.at_sounding_pitch;
147        match self.kind() {
148            StreamKind::Measure => {
149                empty.labels.number = self.labels.number;
150                empty.labels.number_suffix = self.labels.number_suffix.clone();
151                empty.labels.padding_left = self.labels.padding_left;
152                empty.labels.padding_right = self.labels.padding_right;
153            }
154            StreamKind::Part | StreamKind::PartStaff => {
155                empty.labels.name = self.labels.name.clone();
156                empty.labels.abbreviation = self.labels.abbreviation.clone();
157            }
158            _ => {}
159        }
160        empty
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167    use crate::dynamics::Dynamic;
168    use crate::note::Note;
169    use crate::stream::StreamEvent;
170    use crate::stream::StreamKind;
171
172    fn three_notes_and_a_dynamic() -> Stream {
173        let mut line = Stream::new();
174        for place in [0.0, 10.0, 20.0] {
175            line.insert(place, Note::from_name("C4").expect("a note name"));
176        }
177        line.insert(15.0, Dynamic::new("ff"));
178        line
179    }
180
181    /// The lengths here are music21's own answers for the same stream.
182    #[test]
183    fn each_element_of_a_class_reaches_the_next_one() {
184        let stretched = three_notes_and_a_dynamic()
185            .extend_duration(&["GeneralNote"])
186            .expect("stretched");
187        let lengths: Vec<FloatType> = stretched
188            .notes()
189            .iter()
190            .map(|(_, note)| note.quarter_length())
191            .collect();
192        assert_eq!(lengths, [10.0, 10.0, 1.0]);
193        // The whole stream is as long as it was.
194        assert_eq!(stretched.end_offset(), 21.0);
195    }
196
197    /// music21 gives the dynamic a length of 6.0 here, the stream's 21
198    /// less the 15 it stands at. The crate keeps a dynamic timeless, so
199    /// there is nothing to write, and the stream is unchanged.
200    #[test]
201    fn a_mark_the_crate_keeps_timeless_is_not_stretched() {
202        let line = three_notes_and_a_dynamic();
203        let stretched = line.extend_duration(&["Dynamic"]).expect("stretched");
204        let lengths: Vec<FloatType> = stretched
205            .events()
206            .iter()
207            .map(|event| event.element().quarter_length())
208            .collect();
209        assert_eq!(lengths, [1.0, 1.0, 0.0, 1.0]);
210    }
211
212    #[test]
213    fn a_class_no_element_answers_to_leaves_the_stream_alone() {
214        let line = three_notes_and_a_dynamic();
215        let stretched = line.extend_duration(&["Clef"]).expect("stretched");
216        assert_eq!(stretched.events().len(), line.events().len());
217        let lengths: Vec<FloatType> = stretched
218            .notes()
219            .iter()
220            .map(|(_, note)| note.quarter_length())
221            .collect();
222        assert_eq!(lengths, [1.0, 1.0, 1.0]);
223    }
224
225    #[test]
226    fn merging_takes_in_what_another_stream_holds_where_it_stands() {
227        let from = three_notes_and_a_dynamic();
228        let mut into = Stream::new();
229        into.merge_elements(&from, None);
230        assert_eq!(into.len(), 4);
231        let offsets: Vec<FloatType> = into.events().iter().map(StreamEvent::offset).collect();
232        assert_eq!(offsets, [0.0, 10.0, 15.0, 20.0]);
233
234        // Only the classes asked for come.
235        let mut notes_only = Stream::new();
236        notes_only.merge_elements(&from, Some(&["Note"]));
237        assert_eq!(notes_only.len(), 3);
238        let mut dynamics_only = Stream::new();
239        dynamics_only.merge_elements(&from, Some(&["Dynamic"]));
240        assert_eq!(dynamics_only.len(), 1);
241    }
242
243    /// Every answer here is music21's own for the same streams: a part's
244    /// `mergeAttributes` copies `_partName` and `_partAbbreviation`, and a
245    /// measure's its number, suffix and padding, on top of the id and the
246    /// groups the base class copies.
247    #[test]
248    fn an_emptied_copy_keeps_what_merging_a_streams_attributes_copies() {
249        let mut part = Stream::with_kind(StreamKind::Part);
250        part.set_id(Some("hi".to_string()));
251        part.set_name(Some("Flute".to_string()));
252        part.insert(0.0, Note::from_name("C4").expect("a note name"));
253
254        let empty = part.clone_empty();
255        assert_eq!(empty.kind(), StreamKind::Part);
256        assert_eq!(empty.id(), Some("hi"));
257        assert_eq!(empty.name(), Some("Flute"));
258        assert!(empty.is_empty());
259
260        let mut measure = Stream::with_kind(StreamKind::Measure);
261        measure.set_number(4);
262        measure.set_number_suffix(Some("a".to_string()));
263        measure.set_padding_left(1.0);
264        measure.push(Note::from_name("C4").expect("a note name"));
265
266        let empty = measure.clone_empty();
267        assert_eq!(empty.number(), 4);
268        assert_eq!(empty.number_suffix(), Some("a"));
269        assert_eq!(empty.padding_left(), 1.0);
270        assert!(empty.is_empty());
271    }
272}