music21_rs/stream/queries.rs
1//! What a stream holds and where: music21's questions of a stream's layout
2//! -- its gaps and overlaps, what sounds when, its measures by offset.
3
4use super::span::OffsetSpan;
5use super::{Stream, StreamElement, StreamEvent, StreamKind};
6use crate::defaults::FloatType;
7use crate::makenotation::op_frac;
8use crate::rest::Rest;
9
10/// One element of a stream with where it starts and ends and the voice it
11/// is in: music21's `OffsetMap`.
12#[derive(Clone, Debug)]
13pub struct OffsetMapEntry {
14 /// The element.
15 pub element: StreamElement,
16 /// Where it starts.
17 pub offset: FloatType,
18 /// Where it ends.
19 pub end_time: FloatType,
20 /// The voice it is in, by its place among the stream's voices, or
21 /// nothing for an element outside them.
22 pub voice: Option<usize>,
23}
24
25impl Stream {
26 /// Where the last element this stream holds itself starts, nought for
27 /// an empty stream: music21's `highestOffset`.
28 pub fn highest_offset(&self) -> FloatType {
29 self.events
30 .iter()
31 .map(StreamEvent::offset)
32 .fold(None, |most: Option<FloatType>, offset| {
33 Some(most.map_or(offset, |most| most.max(offset)))
34 })
35 .unwrap_or(0.0)
36 }
37
38 /// Where the first element this stream holds itself starts, nought for
39 /// an empty stream: music21's `lowestOffset`.
40 pub fn lowest_offset(&self) -> FloatType {
41 self.events
42 .iter()
43 .map(StreamEvent::offset)
44 .fold(None, |least: Option<FloatType>, offset| {
45 Some(least.map_or(offset, |least| least.min(offset)))
46 })
47 .unwrap_or(0.0)
48 }
49
50 /// Whether this stream holds a measure itself: music21's `hasMeasures`.
51 pub fn has_measures(&self) -> bool {
52 self.events
53 .iter()
54 .any(|event| matches!(event.element(), StreamElement::Stream(inner) if inner.kind() == StreamKind::Measure))
55 }
56
57 /// Whether this stream holds a voice itself: music21's `hasVoices`.
58 pub fn has_voices(&self) -> bool {
59 self.events
60 .iter()
61 .any(|event| matches!(event.element(), StreamElement::Stream(inner) if inner.kind() == StreamKind::Voice))
62 }
63
64 /// Whether the stream is notation as music21 writes it out: a measure
65 /// or a voice; a part of measures; a score or other stream of parts, or
66 /// an opus of scores, whose every stream holds measures; and nothing
67 /// holding notes or rests loose: music21's `isWellFormedNotation`.
68 pub fn is_well_formed_notation(&self) -> bool {
69 let all_hold_measures = |stream: &Stream| {
70 stream
71 .events
72 .iter()
73 .filter_map(|event| event.element().as_stream())
74 .all(Stream::has_measures)
75 };
76 match self.kind() {
77 StreamKind::Measure | StreamKind::Voice => true,
78 _ if self
79 .events
80 .iter()
81 .any(|event| event.element().is_instance("GeneralNote")) =>
82 {
83 false
84 }
85 StreamKind::Part | StreamKind::PartStaff => self.has_measures(),
86 StreamKind::Opus => self
87 .streams_of_kind(StreamKind::Score)
88 .into_iter()
89 .all(all_hold_measures),
90 _ if self.has_part_like_streams() => all_hold_measures(self),
91 _ => false,
92 }
93 }
94
95 /// The stretches of this stream, between its own elements, where
96 /// nothing sounds, each as a rest, or nothing where there are none:
97 /// music21's `findGaps`.
98 ///
99 /// ```
100 /// use music21_rs::{Duration, Note, Stream};
101 ///
102 /// let mut line = Stream::new();
103 /// line.insert(0.0, Note::from_name("C4")?.with_duration(Duration::quarter()));
104 /// line.insert(2.0, Note::from_name("D4")?.with_duration(Duration::quarter()));
105 /// let gaps = line.find_gaps().expect("a gap");
106 /// assert_eq!(gaps.events()[0].offset(), 1.0);
107 /// assert_eq!(gaps.events()[0].element().quarter_length(), 1.0);
108 /// assert!(!line.is_gapless());
109 /// # Ok::<(), music21_rs::Error>(())
110 /// ```
111 pub fn find_gaps(&self) -> Option<Stream> {
112 let mut gaps = Stream::with_kind(self.kind());
113 let mut highest: FloatType = 0.0;
114 for event in &self.events {
115 let offset = event.offset();
116 if offset > highest {
117 let length = op_frac(offset - highest);
118 if let Ok(duration) = crate::duration::Duration::new(length) {
119 gaps.insert_sorted(vec![StreamEvent::new(
120 highest,
121 StreamElement::Rest(Rest::new(duration)),
122 )]);
123 }
124 }
125 highest = op_frac(highest.max(offset + event.element().quarter_length()));
126 }
127 (!gaps.is_empty()).then_some(gaps)
128 }
129
130 /// Whether this stream has no gaps: music21's `isGapless`.
131 pub fn is_gapless(&self) -> bool {
132 self.find_gaps().is_none()
133 }
134
135 /// The flattened stream, each element with where it starts and ends.
136 fn spans(&self) -> (Stream, Vec<(FloatType, FloatType)>) {
137 let flat = self.flatten();
138 let spans = flat
139 .events
140 .iter()
141 .map(|event| {
142 let offset = event.offset();
143 (offset, op_frac(offset + event.element().quarter_length()))
144 })
145 .collect();
146 (flat, spans)
147 }
148
149 /// music21's `_findLayering`: for each element of the flattened stream,
150 /// the others it overlaps, found looking on from it until the first that
151 /// does not.
152 fn layering(spans: &[(FloatType, FloatType)]) -> Vec<Vec<usize>> {
153 let overlap = |a: (FloatType, FloatType), b: (FloatType, FloatType)| {
154 let (first, second) = if (b.0, b.1) < (a.0, a.1) {
155 (b, a)
156 } else {
157 (a, b)
158 };
159 second.0 < first.1
160 };
161 let mut map = vec![Vec::new(); spans.len()];
162 for i in 0..spans.len() {
163 for j in (i + 1)..spans.len() {
164 if overlap(spans[i], spans[j]) {
165 map[i].push(j);
166 map[j].push(i);
167 } else {
168 break;
169 }
170 }
171 }
172 for list in &mut map {
173 list.sort_unstable();
174 }
175 map
176 }
177
178 /// The elements of the flattened stream that sound over one another,
179 /// gathered by the offset where each overlapping group starts:
180 /// music21's `getOverlaps`. Only elements found overlapping looking on
181 /// from one until the first that does not are gathered, as music21
182 /// gathers them.
183 ///
184 /// ```
185 /// use music21_rs::{Duration, Note, Stream};
186 ///
187 /// let mut line = Stream::new();
188 /// line.insert(0.0, Note::from_name("C4")?.with_duration(Duration::half()));
189 /// line.insert(1.0, Note::from_name("E4")?.with_duration(Duration::quarter()));
190 /// line.insert(3.0, Note::from_name("G4")?.with_duration(Duration::quarter()));
191 /// let overlaps = line.overlaps();
192 /// assert_eq!(overlaps.len(), 1);
193 /// assert_eq!(overlaps[0].0, 0.0);
194 /// assert_eq!(overlaps[0].1.len(), 2);
195 /// assert!(!line.is_sequence());
196 /// # Ok::<(), music21_rs::Error>(())
197 /// ```
198 pub fn overlaps(&self) -> Vec<(FloatType, Vec<StreamEvent>)> {
199 let flat = self.flatten();
200 self.overlap_groups()
201 .into_iter()
202 .map(|(offset, members)| {
203 (
204 offset,
205 members
206 .into_iter()
207 .map(|index| flat.events[index].clone())
208 .collect(),
209 )
210 })
211 .collect()
212 }
213
214 /// [`Stream::overlaps`], each group's members by their position among
215 /// [`Stream::leaves`] rather than as values.
216 ///
217 /// music21 hands back the elements themselves, so a caller keeping an
218 /// object per element -- a binding keeping what it read the stream
219 /// from -- finds each again by that position.
220 ///
221 /// ```
222 /// use music21_rs::{Duration, Note, Stream, StreamKind};
223 ///
224 /// let mut part = Stream::with_kind(StreamKind::Part);
225 /// let mut measure = Stream::with_kind(StreamKind::Measure);
226 /// measure.insert(0.0, Note::from_name("C4")?.with_duration(Duration::half()));
227 /// measure.insert(1.0, Note::from_name("E4")?);
228 /// part.insert(0.0, measure);
229 ///
230 /// // The two notes overlap, and are the part's first two leaves. The
231 /// // one overlapped is listed before the one looking on from itself,
232 /// // which is the order music21's own dictionary takes them in.
233 /// let found = part.overlap_positions();
234 /// assert_eq!(found.len(), 1);
235 /// assert_eq!(found[0], (0.0, vec![1, 0]));
236 /// # Ok::<(), music21_rs::Error>(())
237 /// ```
238 pub fn overlap_positions(&self) -> Vec<(FloatType, Vec<usize>)> {
239 let leaves = self.leaves();
240 // The flattened stream is the leaves in `flatten`'s order, so the
241 // nth element of it is the leaf that order puts nth.
242 let order = Stream::flatten_order(&leaves);
243 self.overlap_groups()
244 .into_iter()
245 .map(|(offset, members)| {
246 (
247 offset,
248 members.into_iter().map(|index| order[index]).collect(),
249 )
250 })
251 .collect()
252 }
253
254 /// The groups [`Stream::overlaps`] finds, each holding indices into the
255 /// flattened stream, in the order music21's dictionary takes them.
256 fn overlap_groups(&self) -> Vec<(FloatType, Vec<usize>)> {
257 let (flat, spans) = self.spans();
258 let map = Self::layering(&spans);
259 // Each group by its offset, holding indices of the flattened stream,
260 // in the order music21's dictionary takes them.
261 let mut groups: Vec<(FloatType, Vec<usize>)> = Vec::new();
262 let held_at = |groups: &[(FloatType, Vec<usize>)], index: usize| {
263 groups
264 .iter()
265 .find(|(_, members)| members.contains(&index))
266 .map(|(offset, _)| *offset)
267 };
268 let push = |groups: &mut Vec<(FloatType, Vec<usize>)>, offset: FloatType, index: usize| {
269 match groups.iter_mut().find(|(known, _)| *known == offset) {
270 Some((_, members)) => members.push(index),
271 None => groups.push((offset, vec![index])),
272 }
273 };
274 for (index, indices) in map.iter().enumerate() {
275 if indices.is_empty() {
276 continue;
277 }
278 let source = flat.events[index].offset();
279 let mut destination = None;
280 for &other in indices {
281 let mut store = true;
282 if let Some(offset) = held_at(&groups, other) {
283 store = false;
284 destination = Some(offset);
285 }
286 let at = *destination.get_or_insert(source);
287 if store {
288 push(&mut groups, at, other);
289 }
290 }
291 if held_at(&groups, index).is_none() {
292 let at = destination.unwrap_or(source);
293 push(&mut groups, at, index);
294 }
295 }
296 groups
297 }
298
299 /// Whether no element of the flattened stream overlaps another, as
300 /// [`Stream::overlaps`] finds them: music21's `isSequence`.
301 pub fn is_sequence(&self) -> bool {
302 let (_, spans) = self.spans();
303 Self::layering(&spans).iter().all(Vec::is_empty)
304 }
305
306 /// The offsets where something in this stream and something in
307 /// `other` both start, each stream's own elements: music21's
308 /// `simultaneousAttacks`.
309 pub fn simultaneous_attacks(&self, other: &Stream) -> Vec<FloatType> {
310 let mut offsets: Vec<FloatType> = Vec::new();
311 for event in &self.events {
312 if !offsets.contains(&event.offset()) {
313 offsets.push(event.offset());
314 }
315 }
316 let mut shared: Vec<FloatType> = offsets
317 .into_iter()
318 .filter(|offset| other.events.iter().any(|event| event.offset() == *offset))
319 .collect();
320 shared.sort_by(FloatType::total_cmp);
321 shared
322 }
323
324 /// The element of this stream sounding where `element` starts, at
325 /// `offset`: the one there, or of those there the first of `element`'s
326 /// class, or else the first; nothing where none is: music21's
327 /// `playingWhenAttacked`.
328 pub fn playing_when_attacked(
329 &self,
330 element: &StreamElement,
331 offset: FloatType,
332 ) -> Option<&StreamEvent> {
333 let mut span = OffsetSpan::at(offset);
334 span.must_begin_in_span = false;
335 let there: Vec<&StreamEvent> = self
336 .events
337 .iter()
338 .filter(|event| span.takes_at(event.offset(), event.element().quarter_length()))
339 .collect();
340 match there.as_slice() {
341 [] => None,
342 [only] => Some(*only),
343 many => {
344 let class = element.music21_classes()[0];
345 many.iter()
346 .find(|event| event.element().is_instance(class))
347 .or_else(|| many.first())
348 .copied()
349 }
350 }
351 }
352
353 /// Every element of this stream sounding while `element`, at `offset`,
354 /// sounds, each at its offset from `offset`: music21's
355 /// `allPlayingWhileSounding`.
356 pub fn all_playing_while_sounding(&self, element: &StreamElement, offset: FloatType) -> Stream {
357 let end = offset + element.quarter_length();
358 let span = if end != offset {
359 OffsetSpan {
360 must_begin_in_span: false,
361 include_end_boundary: false,
362 include_elements_that_end_at_start: false,
363 ..OffsetSpan::between(offset, end)
364 }
365 } else {
366 OffsetSpan {
367 must_begin_in_span: false,
368 ..OffsetSpan::at(offset)
369 }
370 };
371 let mut out = Stream::with_kind(self.kind());
372 out.events = self
373 .events
374 .iter()
375 .filter(|event| span.takes_at(event.offset(), event.element().quarter_length()))
376 .map(|event| {
377 StreamEvent::new(op_frac(event.offset() - offset), event.element().clone())
378 })
379 .collect();
380 out
381 }
382
383 /// Each element of this stream with where it starts and ends, those of
384 /// its voices flattened and labelled with the voice, barlines left out:
385 /// music21's `offsetMap`.
386 pub fn offset_map(&self) -> Vec<OffsetMapEntry> {
387 let entry = |event: &StreamEvent, voice: Option<usize>| OffsetMapEntry {
388 element: event.element().clone(),
389 offset: event.offset(),
390 end_time: op_frac(event.offset() + event.element().quarter_length()),
391 voice,
392 };
393 let keep = |event: &&StreamEvent| !matches!(event.element(), StreamElement::Barline(_));
394 if !self.has_voices() {
395 return self
396 .events
397 .iter()
398 .filter(keep)
399 .map(|event| entry(event, None))
400 .collect();
401 }
402 let mut out: Vec<OffsetMapEntry> = self
403 .events
404 .iter()
405 .filter(|event| !matches!(event.element(), StreamElement::Stream(inner) if inner.kind() == StreamKind::Voice))
406 .filter(keep)
407 .map(|event| entry(event, None))
408 .collect();
409 for (index, voice) in self.voices().into_iter().enumerate() {
410 let flat = voice.flatten();
411 out.extend(
412 flat.events
413 .iter()
414 .filter(keep)
415 .map(|event| entry(event, Some(index))),
416 );
417 }
418 out
419 }
420
421 /// The measures by offset, in order: a score's those of every part at
422 /// each offset, and another stream's its own: music21's
423 /// `measureOffsetMap`.
424 pub fn measure_offset_map(&self) -> Vec<(FloatType, Vec<&Stream>)> {
425 let mut map: Vec<(FloatType, Vec<&Stream>)> = Vec::new();
426 let parts = self.parts();
427 let holders: Vec<&Stream> = if self.kind() == StreamKind::Score && !parts.is_empty() {
428 parts
429 } else {
430 vec![self]
431 };
432 for holder in holders {
433 for event in &holder.events {
434 let StreamElement::Stream(measure) = event.element() else {
435 continue;
436 };
437 if measure.kind() != StreamKind::Measure {
438 continue;
439 }
440 match map.iter_mut().find(|(offset, _)| *offset == event.offset()) {
441 Some((_, measures)) => measures.push(measure),
442 None => map.push((event.offset(), vec![measure])),
443 }
444 }
445 }
446 map.sort_by(|left, right| left.0.total_cmp(&right.0));
447 map
448 }
449}