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 measure_of(event: &StreamEvent) -> Option<(FloatType, &Stream)> {
25 match event.element() {
26 StreamElement::Stream(inner) => Some((event.offset(), &**inner)),
27 _ => None,
28 }
29}
30
31impl Stream {
32 pub fn element_at_or_before(
51 &self,
52 offset: FloatType,
53 classes: &[&str],
54 ) -> Option<&StreamEvent> {
55 self.nearest_before(offset, classes, false)
56 }
57
58 pub fn element_before_offset(
62 &self,
63 offset: FloatType,
64 classes: &[&str],
65 ) -> Option<&StreamEvent> {
66 self.nearest_before(offset, classes, true)
67 }
68
69 fn nearest_before(
70 &self,
71 offset: FloatType,
72 classes: &[&str],
73 before_not_at: bool,
74 ) -> Option<&StreamEvent> {
75 let offset = op_frac(offset);
76 let mut best: Option<(FloatType, &StreamEvent)> = None;
77 for event in &self.events {
78 if !of_classes(event.element(), classes) {
79 continue;
80 }
81 let span = op_frac(offset - event.offset());
82 if span < 0.0 || (span == 0.0 && before_not_at) {
83 continue;
84 }
85 let better = match best {
88 None => span <= offset,
89 Some((nearest, held)) => {
90 span < nearest
91 || (span == nearest && event_order(event, held) != std::cmp::Ordering::Less)
92 }
93 };
94 if better {
95 best = Some((span, event));
96 }
97 }
98 best.map(|(_, event)| event)
99 }
100
101 pub fn element_after(&self, index: usize, classes: &[&str]) -> Result<Option<&StreamEvent>> {
109 if index >= self.events.len() {
110 return Err(stream_error("cannot find object in this Stream"));
111 }
112 Ok(self.events[index + 1..]
113 .iter()
114 .find(|event| of_classes(event.element(), classes)))
115 }
116
117 pub fn beat_and_measure_from_offset(
143 &self,
144 offset: FloatType,
145 fix_zeros: bool,
146 ) -> Result<(FloatType, &Stream)> {
147 let mut holder = self;
148 if !self.has_measures() {
149 if !self.has_part_like_streams() {
150 return Err(stream_error(
151 "beatAndMeasureFromOffset: could not find any measures!",
152 ));
153 }
154 holder = self
155 .events
156 .iter()
157 .filter_map(|event| event.element().as_stream())
158 .find(|inner| inner.has_measures())
159 .ok_or_else(|| {
160 stream_error("beatAndMeasureFromOffset: could not find any parts!")
161 })?;
162 }
163 let (measure_offset, measure) = holder
164 .element_at_or_before(offset, &["Measure"])
165 .and_then(measure_of)
166 .ok_or_else(|| stream_error("beatAndMeasureFromOffset: no measure at that offset."))?;
167 let meter = holder.time_signature_at(measure_offset).ok_or_else(|| {
168 stream_error(
169 "beatAndMeasureFromOffset: could not find a time signature for that place.",
170 )
171 })?;
172 let beat = meter
173 .beat_proportion(op_frac(offset - measure_offset))
174 .map_err(|_| {
175 stream_error("beatAndMeasureFromOffset: offset is beyond the end of the piece")
176 })?;
177
178 let suffixed = measure
179 .number_suffix()
180 .is_some_and(|suffix| !suffix.is_empty());
181 if !suffixed && !(fix_zeros && measure.number() == 0) {
182 return Ok((beat, measure));
183 }
184 let previous = holder
187 .element_before_offset(measure_offset, &["Measure"])
188 .and_then(measure_of)
189 .filter(|(_, previous)| {
190 !previous.events.is_empty() || previous.right_barline().is_some()
191 });
192 match previous {
193 Some((previous_offset, previous)) => {
194 let earlier = holder.time_signature_at(previous_offset).ok_or_else(|| {
195 stream_error(
196 "beatAndMeasureFromOffset: partial measure found, but could not find a time signature for the preceding measure",
197 )
198 })?;
199 let filled = op_frac(previous.end_offset());
200 let pad = if filled == earlier.bar_quarter_length() {
201 Exact::integer(i64::from(earlier.beat_count()))
202 } else {
203 Exact::held(earlier.beat_proportion(filled)?).plus(Exact::integer(-1))
204 };
205 Ok((Exact::held(beat).plus(pad).to_float(), previous))
206 }
207 None => {
208 let pad =
209 Exact::held(meter.beat_proportion(
210 meter.bar_quarter_length() - op_frac(measure.end_offset()),
211 )?)
212 .plus(Exact::integer(-1));
213 Ok((Exact::held(beat).plus(pad).to_float(), measure))
214 }
215 }
216 }
217
218 pub fn time_signatures(&self, return_default: bool) -> Result<Vec<(FloatType, TimeSignature)>> {
229 let mut found: Vec<(FloatType, TimeSignature)> = self
230 .flatten()
231 .events
232 .into_iter()
233 .filter_map(|event| match event.element {
234 StreamElement::TimeSignature(meter) => Some((event.offset, meter)),
235 _ => None,
236 })
237 .collect();
238 if return_default && found.first().is_none_or(|(offset, _)| *offset > 0.0) {
239 found.insert(0, (0.0, TimeSignature::new(4, 4)?));
240 }
241 Ok(found)
242 }
243
244 pub fn instruments(&self, recurse: bool, return_default: bool) -> Vec<Instrument> {
251 let held = if recurse {
252 self.flatten()
253 } else {
254 self.clone()
255 };
256 let mut found: Vec<Instrument> = held
257 .events
258 .into_iter()
259 .filter_map(|event| match event.element {
260 StreamElement::Instrument(instrument) => Some(*instrument),
261 _ => None,
262 })
263 .collect();
264 if return_default && found.is_empty() {
265 let mut instrument = Instrument::new();
266 instrument.set_part_name(Some(String::new()));
267 found.push(instrument);
268 }
269 found
270 }
271
272 pub fn instrument(&self, recurse: bool, return_default: bool) -> Option<Instrument> {
276 self.instruments(recurse, return_default).into_iter().next()
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use crate::duration::Duration;
284 use crate::note::Note;
285 use crate::rest::Rest;
286 use crate::stream::StreamKind;
287
288 #[test]
289 fn the_nearest_before_is_the_last_of_its_offset() -> Result<()> {
290 let mut stream = Stream::new();
291 stream.insert(0.0, Note::from_name("C4")?);
292 stream.insert(1.0, Rest::new(Duration::quarter()));
293 stream.insert(1.0, Note::from_name("D4")?);
294 let at = stream.element_at_or_before(1.0, &[]).unwrap();
295 assert_eq!(at.offset(), 1.0);
296 assert!(matches!(at.element(), StreamElement::Note(_)));
297 assert!(matches!(
298 stream
299 .element_at_or_before(1.0, &["Rest"])
300 .unwrap()
301 .element(),
302 StreamElement::Rest(_)
303 ));
304 assert_eq!(
305 stream.element_before_offset(1.0, &[]).unwrap().offset(),
306 0.0
307 );
308 assert!(stream.element_before_offset(0.0, &[]).is_none());
309 assert!(stream.element_at_or_before(-1.0, &[]).is_none());
310 assert!(matches!(
311 stream.element_after(0, &["Note"])?.unwrap().element(),
312 StreamElement::Note(_)
313 ));
314 assert!(stream.element_after(2, &[])?.is_none());
315 assert!(stream.element_after(3, &[]).is_err());
316 Ok(())
317 }
318
319 #[test]
320 fn a_pickup_counts_its_beats_from_the_end_of_a_bar() -> Result<()> {
321 let mut part = Stream::with_kind(StreamKind::Part);
322 let mut pickup = Stream::with_kind(StreamKind::Measure);
323 pickup.insert(0.0, TimeSignature::new(4, 4)?);
324 pickup.insert(0.0, Note::from_name("G4")?);
325 let mut first = Stream::with_kind(StreamKind::Measure);
326 first.set_number(1);
327 first.insert(0.0, Note::from_name("C5")?.with_duration(Duration::whole()));
328 part.insert(0.0, pickup);
329 part.insert(1.0, first);
330 let (beat, measure) = part.beat_and_measure_from_offset(0.0, true)?;
331 assert_eq!((beat, measure.number()), (4.0, 0));
332 let (beat, measure) = part.beat_and_measure_from_offset(3.0, true)?;
333 assert_eq!((beat, measure.number()), (3.0, 1));
334 Ok(())
335 }
336
337 #[test]
338 fn a_default_meter_and_instrument_stand_in_for_none() -> Result<()> {
339 let stream = Stream::new();
340 let meters = stream.time_signatures(true)?;
341 assert_eq!(meters.len(), 1);
342 assert_eq!(meters[0].1.ratio_string(), "4/4");
343 assert!(stream.time_signatures(false)?.is_empty());
344 assert_eq!(stream.instrument(true, true).unwrap().part_name(), Some(""));
345 assert!(stream.instrument(true, false).is_none());
346 Ok(())
347 }
348}