Skip to main content

music21/stream/
placed.rs

1//! An element together with where it stands: music21's sites, answered
2//! as a composite rather than stored on the element.
3//!
4//! music21 keeps on every object a back-reference to each stream holding
5//! it, so that `getContextByClass` can walk up to the key or metre in
6//! force; that is why its objects are deep-copied so often. Its author
7//! would do it differently: "store objects and sites separately and return
8//! them as a separate composite object" ("Music21's Mistakes", point 2).
9//! [`Stream::placed`] is that composite. The element stays a plain value in
10//! the tree; where it sits, and what is in force there, is worked out from
11//! the tree when asked.
12//!
13//! ```text
14//!   Score ─┬─ Part 1 ─┬─ Measure 1: KeySignature(-1), C4 …
15//!          │          └─ Measure 2: D4 …   ─► Placed { D4, offset 4.0,
16//!          │                                     measure offset 0.0,
17//!          │                                     key: one flat }
18//!          └─ Part 2 ─── Measure 1: E4 …   ─► Placed { E4, key: none }
19//! ```
20
21use super::{Stream, StreamElement, StreamKind};
22use crate::{
23    Duration, Result,
24    defaults::{FloatType, IntegerType},
25    key::KeySignature,
26    meter::TimeSignature,
27    tempo::MetronomeMark,
28};
29
30/// Which marks a leaf reads: those of its own part, and those held by the
31/// stream asked, which stand over every part.
32#[derive(Clone, Copy, PartialEq)]
33enum Scope {
34    Shared,
35    Part(usize),
36}
37
38impl Scope {
39    fn reaches(self, leaf: Scope) -> bool {
40        self == Scope::Shared || self == leaf
41    }
42}
43
44/// One element of a stream with its place in it: its offset, its offset in
45/// the measure holding it and that measure's number, and the key signature,
46/// metre and tempo in force where it stands.
47#[derive(Clone, Debug)]
48pub struct Placed<'a> {
49    element: &'a StreamElement,
50    offset: FloatType,
51    measure_offset: Option<FloatType>,
52    measure_number: Option<IntegerType>,
53    /// Where the element stands in the bar before its meter is applied:
54    /// music21's `_getMeasureOffset`, the offset in its measure plus the
55    /// measure's padding, or its offset in the stream holding it.
56    bar_position: FloatType,
57    key_signature: Option<&'a KeySignature>,
58    time_signature: Option<&'a TimeSignature>,
59    /// The meter's own place in its bar, its padding left out, as music21's
60    /// `_getMeasureOffset(includeMeasurePadding=False)` reads it.
61    time_signature_position: FloatType,
62    metronome_mark: Option<&'a MetronomeMark>,
63}
64
65impl<'a> Placed<'a> {
66    /// The element itself.
67    pub fn element(&self) -> &'a StreamElement {
68        self.element
69    }
70
71    /// The offset from the start of the stream asked.
72    pub fn offset(&self) -> FloatType {
73        self.offset
74    }
75
76    /// The offset from the start of the measure holding the element, or
77    /// `None` outside any measure.
78    pub fn measure_offset(&self) -> Option<FloatType> {
79        self.measure_offset
80    }
81
82    /// The number of the innermost measure holding the element, or `None`
83    /// outside any measure: music21's `measureNumber`.
84    pub fn measure_number(&self) -> Option<IntegerType> {
85        self.measure_number
86    }
87
88    /// The key signature in force where the element stands.
89    pub fn key_signature(&self) -> Option<&'a KeySignature> {
90        self.key_signature
91    }
92
93    /// The metre in force where the element stands.
94    pub fn time_signature(&self) -> Option<&'a TimeSignature> {
95        self.time_signature
96    }
97
98    /// The tempo in force where the element stands.
99    pub fn metronome_mark(&self) -> Option<&'a MetronomeMark> {
100        self.metronome_mark
101    }
102
103    /// Where the element falls in the bar of the meter in force: music21's
104    /// `getMeasureOffsetOrMeterModulusOffset`. Inside a measure that is its
105    /// place in it, padding included; outside one, the meter's bars are
106    /// counted on from where the meter stands. `None` with no meter.
107    ///
108    /// ```text
109    ///   3/4 at 0, no measures:  note at 4.0  ->  bar offset 1.0
110    ///   4/4 pickup, padding 3:  note at 0.0  ->  bar offset 3.0
111    /// ```
112    pub fn bar_offset(&self) -> Option<FloatType> {
113        let meter = self.time_signature?;
114        Some(meter.offset_in_bar(self.bar_position, self.time_signature_position))
115    }
116
117    /// The beat the element falls on, counted from 1 with the progress
118    /// through it as a fraction: music21's `beat`. `None` with no meter,
119    /// where music21 answers `nan`.
120    ///
121    /// # Errors
122    ///
123    /// An offset the meter cannot place, where music21 raises.
124    pub fn beat(&self) -> Result<Option<FloatType>> {
125        self.read_bar(TimeSignature::beat_proportion)
126    }
127
128    /// [`Placed::beat`] written as music21's `beatStr` writes it: `2 1/2`.
129    ///
130    /// # Errors
131    ///
132    /// As [`Placed::beat`].
133    pub fn beat_string(&self) -> Result<Option<String>> {
134        self.read_bar(TimeSignature::beat_proportion_string)
135    }
136
137    /// How long the beat holding the element is: music21's `beatDuration`.
138    /// `None` with no meter, where music21 answers a duration of nothing.
139    ///
140    /// # Errors
141    ///
142    /// As [`Placed::beat`].
143    pub fn beat_duration(&self) -> Result<Option<Duration>> {
144        self.read_bar(TimeSignature::beat_duration_at)
145    }
146
147    /// The metrical accent of the element's place: music21's
148    /// `beatStrength`, which weighs a place that starts no partition at
149    /// half the smallest weight. `None` with no meter.
150    ///
151    /// # Errors
152    ///
153    /// As [`Placed::beat`].
154    pub fn beat_strength(&self) -> Result<Option<FloatType>> {
155        self.read_bar(|meter, offset| meter.accent_weight_with(offset, true, false))
156    }
157
158    /// One reading of the meter in force at the element's bar offset.
159    fn read_bar<T>(
160        &self,
161        read: impl Fn(&TimeSignature, FloatType) -> Result<T>,
162    ) -> Result<Option<T>> {
163        let (Some(meter), Some(offset)) = (self.time_signature, self.bar_offset()) else {
164            return Ok(None);
165        };
166        read(meter, offset).map(Some)
167    }
168}
169
170/// A leaf as the walk finds it, before its context is looked up.
171struct Leaf<'a> {
172    element: &'a StreamElement,
173    offset: FloatType,
174    measure_start: Option<FloatType>,
175    measure_number: Option<IntegerType>,
176    /// The offset in the stream directly holding it.
177    site_offset: FloatType,
178    /// The padding of the measure holding it, nothing outside one.
179    padding: FloatType,
180    scope: Scope,
181}
182
183impl Leaf<'_> {
184    /// music21's `_getMeasureOffset`: the place in the measure, with or
185    /// without the measure's padding, or the place in the stream holding
186    /// it outside a measure.
187    fn bar_position(&self, padded: bool) -> FloatType {
188        let Some(start) = self.measure_start else {
189            return self.site_offset;
190        };
191        let padding = if padded { self.padding } else { 0.0 };
192        crate::makenotation::op_frac(self.offset - start + padding)
193    }
194}
195
196impl Stream {
197    /// Every element that is not itself a stream, in [`Stream::leaves`]
198    /// order, each with where it stands and what is in force there.
199    ///
200    /// A mark is in force from its offset on, the last one at or before an
201    /// element winning. In a stream holding parts, each part reads its own
202    /// marks and those the stream holds directly, never another part's,
203    /// which is music21's `getContextByClass` for music written once.
204    ///
205    /// ```
206    /// use music21::{KeySignature, Note, Stream, StreamElement, stream::StreamKind};
207    ///
208    /// let mut part = Stream::with_kind(StreamKind::Part);
209    /// part.insert(0.0, KeySignature::new(-1));
210    /// part.insert(0.0, Note::from_name("B-4")?);
211    /// let placed = part.placed();
212    /// let note = placed
213    ///     .iter()
214    ///     .find(|placed| matches!(placed.element(), StreamElement::Note(_)))
215    ///     .unwrap();
216    /// assert_eq!(note.key_signature().map(KeySignature::sharps), Some(-1));
217    /// # Ok::<(), music21::Error>(())
218    /// ```
219    pub fn placed(&self) -> Vec<Placed<'_>> {
220        let parts = self.has_part_like_streams();
221        let mut leaves = Vec::new();
222        for (index, event) in self.events.iter().enumerate() {
223            let StreamElement::Stream(stream) = &event.element else {
224                leaves.push(Leaf {
225                    element: &event.element,
226                    offset: event.offset,
227                    measure_start: self.measure_start(0.0),
228                    measure_number: self.measure_number(None),
229                    site_offset: event.offset,
230                    padding: self.measure_padding(),
231                    scope: Scope::Shared,
232                });
233                continue;
234            };
235
236            let scope = if parts {
237                Scope::Part(index)
238            } else {
239                Scope::Shared
240            };
241            let measure_start = self.measure_start(0.0);
242            stream.gather(
243                event.offset,
244                measure_start,
245                self.measure_number(None),
246                self.measure_padding(),
247                scope,
248                &mut leaves,
249            );
250        }
251
252        leaves
253            .iter()
254            .map(|leaf| {
255                let meter = in_force(&leaves, leaf, |element| match element {
256                    StreamElement::TimeSignature(meter) => Some(meter),
257                    _ => None,
258                });
259                Placed {
260                    element: leaf.element,
261                    offset: leaf.offset,
262                    measure_offset: leaf.measure_start.map(|start| leaf.offset - start),
263                    measure_number: leaf.measure_number,
264                    bar_position: leaf.bar_position(true),
265                    key_signature: in_force(&leaves, leaf, |element| match element {
266                        StreamElement::KeySignature(key) => Some(key),
267                        _ => None,
268                    })
269                    .map(|(_, key)| key),
270                    time_signature: meter.map(|(_, meter)| meter),
271                    time_signature_position: meter
272                        .map_or(0.0, |(mark, _)| mark.bar_position(false)),
273                    metronome_mark: in_force(&leaves, leaf, |element| match element {
274                        StreamElement::MetronomeMark(mark) => Some(mark),
275                        _ => None,
276                    })
277                    .map(|(_, mark)| mark),
278                }
279            })
280            .collect()
281    }
282
283    /// Where a measure starts, when this stream is one starting at `base`.
284    fn measure_start(&self, base: FloatType) -> Option<FloatType> {
285        (self.kind == StreamKind::Measure).then_some(base)
286    }
287
288    /// A measure's number, or `outer`'s for any other stream.
289    fn measure_number(&self, outer: Option<IntegerType>) -> Option<IntegerType> {
290        match self.kind {
291            StreamKind::Measure => Some(self.number()),
292            _ => outer,
293        }
294    }
295
296    /// A measure's padding, nothing for any other stream.
297    fn measure_padding(&self) -> FloatType {
298        match self.kind {
299            StreamKind::Measure => self.padding_left(),
300            _ => 0.0,
301        }
302    }
303
304    fn gather<'a>(
305        &'a self,
306        base: FloatType,
307        measure_start: Option<FloatType>,
308        measure_number: Option<IntegerType>,
309        padding: FloatType,
310        scope: Scope,
311        out: &mut Vec<Leaf<'a>>,
312    ) {
313        // The innermost measure is the one whose place counts.
314        let (measure_start, padding) = match self.measure_start(base) {
315            Some(start) => (Some(start), self.measure_padding()),
316            None => (measure_start, padding),
317        };
318        let measure_number = self.measure_number(measure_number);
319        for event in &self.events {
320            let offset = base + event.offset;
321            if let StreamElement::Stream(stream) = &event.element {
322                stream.gather(offset, measure_start, measure_number, padding, scope, out);
323                continue;
324            }
325
326            out.push(Leaf {
327                element: &event.element,
328                offset,
329                measure_start,
330                measure_number,
331                site_offset: event.offset,
332                padding,
333                scope,
334            });
335        }
336    }
337}
338
339/// The last mark of one sort at or before a leaf that the leaf's scope
340/// reaches; of two at one offset, the later-listed. A mark of the sort is
341/// in force where it stands itself, as music21's `getContextByClass`
342/// answers. The mark's own leaf comes with it, for where it stands.
343fn in_force<'l, 'a, T>(
344    leaves: &'l [Leaf<'a>],
345    leaf: &'l Leaf<'a>,
346    read: impl Fn(&'a StreamElement) -> Option<&'a T>,
347) -> Option<(&'l Leaf<'a>, &'a T)> {
348    if let Some(value) = read(leaf.element) {
349        return Some((leaf, value));
350    }
351
352    let mut found: Option<(&'l Leaf<'a>, &'a T)> = None;
353    for mark in leaves {
354        if mark.offset > leaf.offset || !mark.scope.reaches(leaf.scope) {
355            continue;
356        }
357        let Some(value) = read(mark.element) else {
358            continue;
359        };
360        if found.is_none_or(|(held, _)| mark.offset >= held.offset) {
361            found = Some((mark, value));
362        }
363    }
364    found
365}
366
367#[cfg(test)]
368mod tests {
369    use super::Placed;
370    use crate::{
371        Duration, KeySignature, Note, Stream, StreamElement, meter::TimeSignature,
372        stream::StreamKind,
373    };
374
375    fn measure(notes: &[&str]) -> Stream {
376        let mut measure = Stream::with_kind(StreamKind::Measure);
377        for name in notes {
378            measure.push(Note::from_name(name).unwrap());
379        }
380        measure
381    }
382
383    /// A part's key reaches its later measures but not the other part.
384    #[test]
385    fn each_part_reads_its_own_marks() {
386        let mut first = measure(&["C4", "D4", "E4", "F4"]);
387        first.insert(0.0, KeySignature::new(-1));
388        let mut flute = Stream::with_kind(StreamKind::Part);
389        flute.insert(0.0, first);
390        flute.insert(4.0, measure(&["G4"]));
391        let mut oboe = Stream::with_kind(StreamKind::Part);
392        oboe.insert(0.0, measure(&["A4"]));
393        let mut score = Stream::with_kind(StreamKind::Score);
394        score.insert(0.0, TimeSignature::new(4, 4).unwrap());
395        score.insert(0.0, flute);
396        score.insert(0.0, oboe);
397
398        let notes: Vec<_> = score
399            .placed()
400            .into_iter()
401            .filter(|placed| matches!(placed.element(), StreamElement::Note(_)))
402            .collect();
403        let sharps = |index: usize| notes[index].key_signature().map(KeySignature::sharps);
404
405        assert_eq!(notes.len(), 6);
406        assert_eq!(sharps(4), Some(-1));
407        assert_eq!(notes[4].offset(), 4.0);
408        assert_eq!(notes[4].measure_offset(), Some(0.0));
409        assert_eq!(notes[3].measure_offset(), Some(3.0));
410        assert_eq!(sharps(5), None);
411        assert!(notes.iter().all(|placed| placed.time_signature().is_some()));
412    }
413
414    /// An element names the innermost measure holding it, through a voice;
415    /// one outside every measure names none.
416    #[test]
417    fn each_element_names_its_measure() {
418        let mut voice = Stream::with_kind(StreamKind::Voice);
419        voice.push(Note::from_name("C4").unwrap());
420        let mut first = Stream::with_kind(StreamKind::Measure);
421        first.set_number(1);
422        first.insert(0.0, voice);
423        let mut second = measure(&["D4"]);
424        second.set_number(2);
425        let mut part = Stream::with_kind(StreamKind::Part);
426        part.insert(0.0, KeySignature::new(0));
427        part.insert(0.0, first);
428        part.insert(1.0, second);
429
430        let numbers: Vec<_> = part.placed().iter().map(Placed::measure_number).collect();
431        // A measure sorts before a key at one offset, as in music21.
432        assert_eq!(numbers, [Some(1), None, Some(2)]);
433    }
434
435    /// The composite lists what `leaves` lists, in the same order.
436    #[test]
437    fn placed_follows_leaves() {
438        let mut part = Stream::with_kind(StreamKind::Part);
439        part.insert(0.0, measure(&["C4", "D4"]));
440        part.insert(2.0, measure(&["E4"]));
441        let offsets: Vec<_> = part.placed().iter().map(|placed| placed.offset()).collect();
442        let leaves: Vec<_> = part.leaves().iter().map(|(offset, _)| *offset).collect();
443        assert_eq!(offsets, leaves);
444    }
445
446    /// `count` notes of one length, in a stream of `kind` under `meter`.
447    fn repeated(kind: StreamKind, meter: &str, length: f64, count: usize) -> Stream {
448        let mut stream = Stream::with_kind(kind);
449        stream.insert(0.0, TimeSignature::from_ratio_string(meter).unwrap());
450        for _ in 0..count {
451            let mut note = Note::from_name("C4").unwrap();
452            note.set_duration(Duration::new(length).unwrap());
453            stream.push(note);
454        }
455        stream
456    }
457
458    fn notes_of(stream: &Stream) -> Vec<Placed<'_>> {
459        stream
460            .placed()
461            .into_iter()
462            .filter(|placed| matches!(placed.element(), StreamElement::Note(_)))
463            .collect()
464    }
465
466    /// music21's `beat` and `beatStrength` examples, read off a measure.
467    #[test]
468    fn a_measure_counts_its_beats() {
469        let three = repeated(StreamKind::Measure, "3/4", 0.5, 6);
470        let beats: Vec<_> = notes_of(&three)
471            .iter()
472            .map(|placed| placed.beat().unwrap().unwrap())
473            .collect();
474        assert_eq!(beats, [1.0, 1.5, 2.0, 2.5, 3.0, 3.5]);
475        let strengths: Vec<_> = notes_of(&three)
476            .iter()
477            .map(|placed| placed.beat_strength().unwrap().unwrap())
478            .collect();
479        assert_eq!(strengths, [1.0, 0.25, 0.5, 0.25, 0.5, 0.25]);
480
481        let six = repeated(StreamKind::Measure, "6/8", 0.5, 6);
482        let written: Vec<_> = notes_of(&six)
483            .iter()
484            .map(|placed| placed.beat_string().unwrap().unwrap())
485            .collect();
486        assert_eq!(written, ["1", "1 1/3", "1 2/3", "2", "2 1/3", "2 2/3"]);
487        let strengths: Vec<_> = notes_of(&six)
488            .iter()
489            .map(|placed| placed.beat_strength().unwrap().unwrap())
490            .collect();
491        assert_eq!(strengths, [1.0, 0.25, 0.25, 0.5, 0.25, 0.25]);
492    }
493
494    /// Outside a measure the meter wraps, as if its bars went on.
495    #[test]
496    fn a_stream_without_measures_wraps_at_the_bar() {
497        let three = repeated(StreamKind::Stream, "3/4", 1.0, 8);
498        let beats: Vec<_> = notes_of(&three)
499            .iter()
500            .map(|placed| placed.beat().unwrap().unwrap())
501            .collect();
502        assert_eq!(beats, [1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0]);
503
504        let additive = repeated(StreamKind::Stream, "2/4+3/4", 1.0, 8);
505        let lengths: Vec<_> = notes_of(&additive)
506            .iter()
507            .map(|placed| placed.beat_duration().unwrap().unwrap().quarter_length())
508            .collect();
509        assert_eq!(lengths, [2.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 3.0]);
510
511        // A second meter counts from where it stands.
512        let mut changing = repeated(StreamKind::Stream, "2/2", 1.0, 12);
513        changing.insert(4.0, TimeSignature::from_ratio_string("3/4").unwrap());
514        let strengths: Vec<_> = notes_of(&changing)
515            .iter()
516            .map(|placed| placed.beat_strength().unwrap().unwrap())
517            .collect();
518        assert_eq!(
519            strengths,
520            [1.0, 0.25, 0.5, 0.25, 1.0, 0.5, 0.5, 1.0, 0.5, 0.5, 1.0, 0.5]
521        );
522    }
523
524    /// A pickup's padding counts toward where its notes fall in the bar.
525    #[test]
526    fn a_pickup_counts_from_its_padding() {
527        let mut pickup = repeated(StreamKind::Measure, "4/4", 1.0, 1);
528        pickup.set_padding_left(3.0);
529        let notes = notes_of(&pickup);
530        assert_eq!(notes[0].bar_offset(), Some(3.0));
531        assert_eq!(notes[0].beat().unwrap(), Some(4.0));
532    }
533
534    /// A meter is in force where it stands itself, even beside another at
535    /// the same offset: music21's `getContextByClass` answers an element
536    /// of the class asked with itself.
537    #[test]
538    fn a_meter_reads_itself() {
539        let mut empty = Stream::with_kind(StreamKind::Measure);
540        empty.set_number(1);
541        empty.insert(0.0, TimeSignature::from_ratio_string("7/8").unwrap());
542        let mut next = repeated(StreamKind::Measure, "5/4", 1.0, 1);
543        next.set_number(2);
544        let mut part = Stream::with_kind(StreamKind::Part);
545        part.insert(0.0, empty);
546        part.insert(0.0, next);
547
548        let lengths: Vec<_> = part
549            .placed()
550            .iter()
551            .map(|placed| placed.beat_duration().unwrap().unwrap().quarter_length())
552            .collect();
553        assert_eq!(lengths, [0.5, 1.0, 1.0]);
554    }
555
556    /// A meter standing at a third of a beat still counts whole bars from
557    /// there: 26/3 is two bars of 2/2 after 2/3.
558    #[test]
559    fn thirds_count_whole_bars() {
560        let mut part = Stream::with_kind(StreamKind::Part);
561        part.insert(2.0 / 3.0, TimeSignature::from_ratio_string("2/2").unwrap());
562        part.insert(26.0 / 3.0, Note::from_name("C4").unwrap());
563
564        let notes = notes_of(&part);
565        assert_eq!(notes[0].beat().unwrap(), Some(1.0));
566        assert_eq!(notes[0].beat_string().unwrap().as_deref(), Some("1"));
567    }
568
569    /// With no meter in force there is no beat to tell.
570    #[test]
571    fn no_meter_no_beat() {
572        let mut bare = Stream::new();
573        bare.push(Note::from_name("E4").unwrap());
574        let notes = notes_of(&bare);
575        assert_eq!(notes[0].bar_offset(), None);
576        assert_eq!(notes[0].beat().unwrap(), None);
577        assert_eq!(notes[0].beat_strength().unwrap(), None);
578    }
579}