Skip to main content

music21_rs/stream/
splitting.rs

1//! Cutting a stream in two at a point: music21's
2//! `Stream.splitAtQuarterLength`.
3
4use super::{Stream, StreamElement, StreamEvent, StreamKind};
5use crate::clef::Clef;
6use crate::defaults::FloatType;
7use crate::error::Result;
8use crate::key::KeySignature;
9use crate::makenotation::{op_frac, split_element};
10use crate::meter::TimeSignature;
11
12/// The clef, key and time signature in force before a measure, which
13/// music21 finds by searching the measure's context and
14/// [`Stream::split_at_quarter_length`] is given: a crate stream knows
15/// nothing outside itself. [`Stream::in_force_before`] reads them off a
16/// part.
17#[derive(Clone, Debug, Default)]
18pub struct InForce {
19    /// The clef in force before the measure.
20    pub clef: Option<Clef>,
21    /// The key signature in force before the measure.
22    pub key: Option<KeySignature>,
23    /// The time signature in force before the measure.
24    pub meter: Option<TimeSignature>,
25}
26
27impl Stream {
28    /// The clef, key and time signature in force before `offset`: the last
29    /// of each this stream holds, however deep, standing before it.
30    pub fn in_force_before(&self, offset: FloatType) -> InForce {
31        let mut found = InForce::default();
32        for event in self.flatten().events() {
33            if event.offset() >= offset {
34                break;
35            }
36            match event.element() {
37                StreamElement::Clef(clef) => found.clef = Some(clef.clone()),
38                StreamElement::KeySignature(key) => found.key = Some(key.clone()),
39                StreamElement::Key(key) => found.key = Some(key.key_signature()),
40                StreamElement::TimeSignature(meter) => found.meter = Some(meter.clone()),
41                _ => {}
42            }
43        }
44        found
45    }
46
47    /// The stream cut in two `quarter_length` into it: music21's
48    /// `splitAtQuarterLength`. What starts before the point and sounds
49    /// past it is cut there, tied, its second piece starting the second
50    /// half; what starts at or after the point moves to the second half,
51    /// as far from its start. A voice is cut as a stream is.
52    ///
53    /// The second half of a measure is a measure of its own holding the
54    /// time signature of the first (or `in_force`'s where it has none),
55    /// and the key and clef in force at the point: the first half's own
56    /// last before it, or `in_force`'s. Spanners stay with the first half,
57    /// naming nothing for what moved.
58    ///
59    /// ```
60    /// use music21_rs::stream::InForce;
61    /// use music21_rs::tinynotation::from_tiny_notation;
62    ///
63    /// let line = from_tiny_notation("4/4 c2 d2")?;
64    /// let measure = line.measures()[0].clone();
65    /// let (first, second) = measure.split_at_quarter_length(1.0, &InForce::default())?;
66    /// assert_eq!(first.notes().len(), 1);
67    /// assert_eq!(second.notes().len(), 2);
68    /// # Ok::<(), music21_rs::Error>(())
69    /// ```
70    ///
71    /// # Errors
72    ///
73    /// An element that cannot be cut at the point.
74    pub fn split_at_quarter_length(
75        &self,
76        quarter_length: FloatType,
77        in_force: &InForce,
78    ) -> Result<(Stream, Stream)> {
79        let quarter_length = op_frac(quarter_length);
80        let mut right = Stream::with_kind(self.kind());
81        let mut settings: Vec<StreamEvent> = Vec::new();
82        if self.kind() == StreamKind::Measure {
83            let own = |find: &dyn Fn(&StreamElement) -> bool| -> Option<StreamElement> {
84                self.events()
85                    .iter()
86                    .filter(|event| event.offset() < quarter_length && find(event.element()))
87                    .map(|event| event.element().clone())
88                    .last()
89            };
90            let meter = self
91                .flatten()
92                .events()
93                .iter()
94                .find_map(|event| match event.element() {
95                    StreamElement::TimeSignature(meter) => Some(meter.clone()),
96                    _ => None,
97                })
98                .or_else(|| in_force.meter.clone());
99            if let Some(meter) = meter {
100                settings.push(StreamEvent::new(0.0, meter));
101            }
102            let key = own(&|element| {
103                matches!(
104                    element,
105                    StreamElement::KeySignature(_) | StreamElement::Key(_)
106                )
107            })
108            .or_else(|| in_force.key.clone().map(StreamElement::KeySignature));
109            if let Some(key) = key {
110                settings.push(StreamEvent::new(0.0, key));
111            }
112            let clef = own(&|element| matches!(element, StreamElement::Clef(_)))
113                .or_else(|| in_force.clef.clone().map(StreamElement::Clef));
114            if let Some(clef) = clef {
115                settings.push(StreamEvent::new(0.0, clef));
116            }
117        }
118        right.insert_sorted(settings);
119
120        let mut left = self.clone();
121        let highest = op_frac(self.end_offset());
122        if quarter_length > highest {
123            return Ok((left, right));
124        }
125        let span = super::span::OffsetSpan {
126            include_end_boundary: true,
127            must_finish_in_span: false,
128            include_elements_that_end_at_start: false,
129            must_begin_in_span: false,
130            ..super::span::OffsetSpan::between(quarter_length, highest)
131        };
132        let mut kept: Vec<(StreamEvent, Option<usize>)> = Vec::new();
133        let mut moved: Vec<StreamEvent> = Vec::new();
134        for (index, event) in self.events().iter().enumerate() {
135            let length = event.element().quarter_length();
136            if !span.takes_at(event.offset(), length) {
137                kept.push((event.clone(), Some(index)));
138                continue;
139            }
140            if event.offset() < quarter_length {
141                let cut = op_frac(quarter_length - event.offset());
142                let (first, second) = match event.element() {
143                    StreamElement::Stream(inner) => {
144                        let (first, second) =
145                            inner.split_at_quarter_length(cut, &InForce::default())?;
146                        (first.into(), second.into())
147                    }
148                    element => split_element(element, cut)?,
149                };
150                kept.push((StreamEvent::new(event.offset(), first), Some(index)));
151                moved.push(StreamEvent::new(0.0, second));
152            } else {
153                moved.push(StreamEvent::new(
154                    op_frac(event.offset() - quarter_length),
155                    event.element().clone(),
156                ));
157            }
158        }
159        left.replace_events(kept);
160        if left.right_barline().is_some() && span.takes_at(highest, 0.0) {
161            right.set_right_barline(left.right_barline().cloned());
162            left.set_right_barline(None);
163        }
164        right.insert_sorted(moved);
165        Ok((left, right))
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172    use crate::bar::{Barline, BarlineType};
173    use crate::duration::Duration;
174    use crate::note::Note;
175
176    #[test]
177    fn the_second_half_gets_the_settings_and_the_right_barline() -> Result<()> {
178        let mut measure = Stream::with_kind(StreamKind::Measure);
179        measure.insert(0.0, Note::from_name("C4")?.with_duration(Duration::whole()));
180        measure.set_right_barline(Some(Barline::new(BarlineType::Final)));
181        let in_force = InForce {
182            clef: Some(Clef::best_for(&[], false)),
183            key: Some(KeySignature::new(2)),
184            meter: Some(TimeSignature::new(4, 4)?),
185        };
186        let (left, right) = measure.split_at_quarter_length(1.0, &in_force)?;
187        assert!(left.right_barline().is_none());
188        assert_eq!(
189            right.right_barline().map(Barline::bar_type),
190            Some(BarlineType::Final)
191        );
192        assert!(right.left_barline().is_none());
193        let kinds: Vec<&str> = right
194            .events()
195            .iter()
196            .map(|event| match event.element() {
197                StreamElement::Clef(_) => "clef",
198                StreamElement::KeySignature(_) => "key",
199                StreamElement::TimeSignature(_) => "meter",
200                StreamElement::Note(_) => "note",
201                _ => "other",
202            })
203            .collect();
204        assert_eq!(kinds, ["clef", "key", "meter", "note"]);
205        assert_eq!(left.end_offset(), 1.0);
206        assert_eq!(right.end_offset(), 3.0);
207
208        // Past the end there is nothing to cut.
209        let (whole, empty) = measure.split_at_quarter_length(5.0, &InForce::default())?;
210        assert_eq!(whole.end_offset(), 4.0);
211        assert!(empty.is_empty());
212        Ok(())
213    }
214}