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}