1use super::exact::Exact;
6use super::{Stream, StreamElement, StreamEvent};
7use crate::defaults::FloatType;
8use crate::error::{Error, Result};
9use crate::instrument::Instrument;
10use crate::makenotation::{event_order, op_frac};
11use crate::meter::TimeSignature;
12
13fn stream_error(message: impl Into<String>) -> Error {
14 Error::Stream(message.into())
15}
16
17fn of_classes(element: &StreamElement, classes: &[&str]) -> bool {
20 classes.is_empty() || classes.iter().any(|class| element.is_instance(class))
21}
22
23fn time_signatures_in(stream: &Stream) -> impl Iterator<Item = (FloatType, TimeSignature)> + '_ {
25 stream
26 .events
27 .iter()
28 .filter_map(|event| match event.element() {
29 StreamElement::TimeSignature(meter) => Some((event.offset(), meter.clone())),
30 _ => None,
31 })
32}
33
34fn measure_of(event: &StreamEvent) -> Option<(FloatType, &Stream)> {
36 match event.element() {
37 StreamElement::Stream(inner) => Some((event.offset(), &**inner)),
38 _ => None,
39 }
40}
41
42impl Stream {
43 pub fn element_at_or_before(
62 &self,
63 offset: FloatType,
64 classes: &[&str],
65 ) -> Option<&StreamEvent> {
66 self.nearest_before(offset, classes, false)
67 }
68
69 pub fn element_before_offset(
73 &self,
74 offset: FloatType,
75 classes: &[&str],
76 ) -> Option<&StreamEvent> {
77 self.nearest_before(offset, classes, true)
78 }
79
80 fn nearest_before(
81 &self,
82 offset: FloatType,
83 classes: &[&str],
84 before_not_at: bool,
85 ) -> Option<&StreamEvent> {
86 let offset = op_frac(offset);
87 let mut best: Option<(FloatType, &StreamEvent)> = None;
88 for event in &self.events {
89 if !of_classes(event.element(), classes) {
90 continue;
91 }
92 let span = op_frac(offset - event.offset());
93 if span < 0.0 || (span == 0.0 && before_not_at) {
94 continue;
95 }
96 let better = match best {
99 None => span <= offset,
100 Some((nearest, held)) => {
101 span < nearest
102 || (span == nearest && event_order(event, held) != std::cmp::Ordering::Less)
103 }
104 };
105 if better {
106 best = Some((span, event));
107 }
108 }
109 best.map(|(_, event)| event)
110 }
111
112 pub fn element_after(&self, index: usize, classes: &[&str]) -> Result<Option<&StreamEvent>> {
120 if index >= self.events.len() {
121 return Err(stream_error("cannot find object in this Stream"));
122 }
123 Ok(self.events[index + 1..]
124 .iter()
125 .find(|event| of_classes(event.element(), classes)))
126 }
127
128 pub fn beat_and_measure_from_offset(
154 &self,
155 offset: FloatType,
156 fix_zeros: bool,
157 ) -> Result<(FloatType, &Stream)> {
158 let mut holder = self;
159 if !self.has_measures() {
160 if !self.has_part_like_streams() {
161 return Err(stream_error(
162 "beatAndMeasureFromOffset: could not find any measures!",
163 ));
164 }
165 holder = self
166 .events
167 .iter()
168 .filter_map(|event| event.element().as_stream())
169 .find(|inner| inner.has_measures())
170 .ok_or_else(|| {
171 stream_error("beatAndMeasureFromOffset: could not find any parts!")
172 })?;
173 }
174 let (measure_offset, measure) = holder
175 .element_at_or_before(offset, &["Measure"])
176 .and_then(measure_of)
177 .ok_or_else(|| stream_error("beatAndMeasureFromOffset: no measure at that offset."))?;
178 let meter = holder.time_signature_at(measure_offset).ok_or_else(|| {
179 stream_error(
180 "beatAndMeasureFromOffset: could not find a time signature for that place.",
181 )
182 })?;
183 let beat = meter
184 .beat_proportion(op_frac(offset - measure_offset))
185 .map_err(|_| {
186 stream_error("beatAndMeasureFromOffset: offset is beyond the end of the piece")
187 })?;
188
189 let suffixed = measure
190 .number_suffix()
191 .is_some_and(|suffix| !suffix.is_empty());
192 if !suffixed && !(fix_zeros && measure.number() == 0) {
193 return Ok((beat, measure));
194 }
195 let previous = holder
198 .element_before_offset(measure_offset, &["Measure"])
199 .and_then(measure_of)
200 .filter(|(_, previous)| {
201 !previous.events.is_empty() || previous.right_barline().is_some()
202 });
203 match previous {
204 Some((previous_offset, previous)) => {
205 let opening = holder.time_signature_at(previous_offset).ok_or_else(|| {
206 stream_error(
207 "beatAndMeasureFromOffset: partial measure found, but could not find a time signature for the preceding measure",
208 )
209 })?;
210 let mut segments = vec![(opening, 0.0)];
213 for (start, meter) in time_signatures_in(previous) {
214 if segments.last().is_some_and(|(_, last)| *last == start) {
215 segments.pop();
216 }
217 segments.push((meter, start));
218 }
219 let filled = op_frac(previous.end_offset());
220 let mut pad = Exact::integer(0);
221 for (index, (meter, start)) in segments.iter().enumerate() {
222 let end = segments.get(index + 1).map_or(filled, |(_, next)| *next);
223 let length = op_frac(end - start);
224 pad = pad.plus(if length == meter.bar_quarter_length() {
225 Exact::integer(i64::from(meter.beat_count()))
226 } else {
227 Exact::held(meter.beat_proportion(length)?).plus(Exact::integer(-1))
228 });
229 }
230 let beat = match segments.last() {
231 Some((closing, _))
232 if !time_signatures_in(measure).any(|(start, _)| start == 0.0) =>
233 {
234 closing.beat_proportion(op_frac(offset - measure_offset))?
235 }
236 _ => beat,
237 };
238 Ok((Exact::held(beat).plus(pad).to_float(), previous))
239 }
240 None => {
241 let pad =
242 Exact::held(meter.beat_proportion(
243 meter.bar_quarter_length() - op_frac(measure.end_offset()),
244 )?)
245 .plus(Exact::integer(-1));
246 Ok((Exact::held(beat).plus(pad).to_float(), measure))
247 }
248 }
249 }
250
251 pub fn time_signatures(&self, return_default: bool) -> Result<Vec<(FloatType, TimeSignature)>> {
262 let mut found: Vec<(FloatType, TimeSignature)> = self
263 .flatten()
264 .events
265 .into_iter()
266 .filter_map(|event| match event.element {
267 StreamElement::TimeSignature(meter) => Some((event.offset, meter)),
268 _ => None,
269 })
270 .collect();
271 if return_default && found.first().is_none_or(|(offset, _)| *offset > 0.0) {
272 found.insert(0, (0.0, TimeSignature::new(4, 4)?));
273 }
274 Ok(found)
275 }
276
277 pub fn instruments(&self, recurse: bool, return_default: bool) -> Vec<Instrument> {
284 let held = if recurse {
285 self.flatten()
286 } else {
287 self.clone()
288 };
289 let mut found: Vec<Instrument> = held
290 .events
291 .into_iter()
292 .filter_map(|event| match event.element {
293 StreamElement::Instrument(instrument) => Some(*instrument),
294 _ => None,
295 })
296 .collect();
297 if return_default && found.is_empty() {
298 let mut instrument = Instrument::new();
299 instrument.set_part_name(Some(String::new()));
300 found.push(instrument);
301 }
302 found
303 }
304
305 pub fn instrument(&self, recurse: bool, return_default: bool) -> Option<Instrument> {
309 self.instruments(recurse, return_default).into_iter().next()
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::duration::Duration;
317 use crate::note::Note;
318 use crate::rest::Rest;
319 use crate::stream::StreamKind;
320
321 #[test]
322 fn the_nearest_before_is_the_last_of_its_offset() -> Result<()> {
323 let mut stream = Stream::new();
324 stream.insert(0.0, Note::from_name("C4")?);
325 stream.insert(1.0, Rest::new(Duration::quarter()));
326 stream.insert(1.0, Note::from_name("D4")?);
327 let at = stream.element_at_or_before(1.0, &[]).unwrap();
328 assert_eq!(at.offset(), 1.0);
329 assert!(matches!(at.element(), StreamElement::Note(_)));
330 assert!(matches!(
331 stream
332 .element_at_or_before(1.0, &["Rest"])
333 .unwrap()
334 .element(),
335 StreamElement::Rest(_)
336 ));
337 assert_eq!(
338 stream.element_before_offset(1.0, &[]).unwrap().offset(),
339 0.0
340 );
341 assert!(stream.element_before_offset(0.0, &[]).is_none());
342 assert!(stream.element_at_or_before(-1.0, &[]).is_none());
343 assert!(matches!(
344 stream.element_after(0, &["Note"])?.unwrap().element(),
345 StreamElement::Note(_)
346 ));
347 assert!(stream.element_after(2, &[])?.is_none());
348 assert!(stream.element_after(3, &[]).is_err());
349 Ok(())
350 }
351
352 #[test]
353 fn a_pickup_counts_its_beats_from_the_end_of_a_bar() -> Result<()> {
354 let mut part = Stream::with_kind(StreamKind::Part);
355 let mut pickup = Stream::with_kind(StreamKind::Measure);
356 pickup.insert(0.0, TimeSignature::new(4, 4)?);
357 pickup.insert(0.0, Note::from_name("G4")?);
358 let mut first = Stream::with_kind(StreamKind::Measure);
359 first.set_number(1);
360 first.insert(0.0, Note::from_name("C5")?.with_duration(Duration::whole()));
361 part.insert(0.0, pickup);
362 part.insert(1.0, first);
363 let (beat, measure) = part.beat_and_measure_from_offset(0.0, true)?;
364 assert_eq!((beat, measure.number()), (4.0, 0));
365 let (beat, measure) = part.beat_and_measure_from_offset(3.0, true)?;
366 assert_eq!((beat, measure.number()), (3.0, 1));
367 Ok(())
368 }
369
370 #[test]
371 fn a_meter_changing_at_a_split_counts_each_half_in_its_own() -> Result<()> {
372 let mut part = Stream::with_kind(StreamKind::Part);
373 let mut whole = Stream::with_kind(StreamKind::Measure);
374 whole.set_number(1);
375 whole.insert(0.0, TimeSignature::new(4, 4)?);
376 whole.insert(0.0, Note::from_name("C4")?.with_duration(Duration::whole()));
377 let mut first_half = Stream::with_kind(StreamKind::Measure);
378 first_half.set_number(2);
379 first_half.insert(0.0, Note::from_name("C4")?.with_duration(Duration::half()));
380 first_half.insert(2.0, TimeSignature::new(12, 16)?);
381 let mut second_half = Stream::with_kind(StreamKind::Measure);
382 second_half.set_number(2);
383 second_half.set_number_suffix(Some("X1".to_string()));
384 second_half.insert(
385 0.0,
386 Note::from_name("C4")?.with_duration(Duration::new(0.75)?),
387 );
388 second_half.insert(
389 0.75,
390 Note::from_name("C4")?.with_duration(Duration::new(0.75)?),
391 );
392 part.insert(0.0, whole);
393 part.insert(4.0, first_half);
394 part.insert(6.0, second_half);
395 let beats = [5.0, 6.0, 6.75]
396 .into_iter()
397 .map(|offset| Ok(part.beat_and_measure_from_offset(offset, true)?.0))
398 .collect::<Result<Vec<_>>>()?;
399 assert_eq!(beats, [2.0, 3.0, 4.0]);
400 Ok(())
401 }
402
403 #[test]
404 fn a_default_meter_and_instrument_stand_in_for_none() -> Result<()> {
405 let stream = Stream::new();
406 let meters = stream.time_signatures(true)?;
407 assert_eq!(meters.len(), 1);
408 assert_eq!(meters[0].1.ratio_string(), "4/4");
409 assert!(stream.time_signatures(false)?.is_empty());
410 assert_eq!(stream.instrument(true, true).unwrap().part_name(), Some(""));
411 assert!(stream.instrument(true, false).is_none());
412 Ok(())
413 }
414}