1use super::{Stream, StreamElement, StreamKind};
22use crate::{defaults::FloatType, key::KeySignature, meter::TimeSignature, tempo::MetronomeMark};
23
24#[derive(Clone, Copy, PartialEq)]
27enum Scope {
28 Shared,
29 Part(usize),
30}
31
32impl Scope {
33 fn reaches(self, leaf: Scope) -> bool {
34 self == Scope::Shared || self == leaf
35 }
36}
37
38#[derive(Clone, Debug)]
42pub struct Placed<'a> {
43 element: &'a StreamElement,
44 offset: FloatType,
45 measure_offset: Option<FloatType>,
46 key_signature: Option<&'a KeySignature>,
47 time_signature: Option<&'a TimeSignature>,
48 metronome_mark: Option<&'a MetronomeMark>,
49}
50
51impl<'a> Placed<'a> {
52 pub fn element(&self) -> &'a StreamElement {
54 self.element
55 }
56
57 pub fn offset(&self) -> FloatType {
59 self.offset
60 }
61
62 pub fn measure_offset(&self) -> Option<FloatType> {
65 self.measure_offset
66 }
67
68 pub fn key_signature(&self) -> Option<&'a KeySignature> {
70 self.key_signature
71 }
72
73 pub fn time_signature(&self) -> Option<&'a TimeSignature> {
75 self.time_signature
76 }
77
78 pub fn metronome_mark(&self) -> Option<&'a MetronomeMark> {
80 self.metronome_mark
81 }
82}
83
84struct Leaf<'a> {
86 element: &'a StreamElement,
87 offset: FloatType,
88 measure_start: Option<FloatType>,
89 scope: Scope,
90}
91
92impl Stream {
93 pub fn placed(&self) -> Vec<Placed<'_>> {
116 let parts = self.has_part_like_streams();
117 let mut leaves = Vec::new();
118 for (index, event) in self.events.iter().enumerate() {
119 let StreamElement::Stream(stream) = &event.element else {
120 leaves.push(Leaf {
121 element: &event.element,
122 offset: event.offset,
123 measure_start: self.measure_start(0.0),
124 scope: Scope::Shared,
125 });
126 continue;
127 };
128
129 let scope = if parts {
130 Scope::Part(index)
131 } else {
132 Scope::Shared
133 };
134 let measure_start = self.measure_start(0.0);
135 stream.gather(event.offset, measure_start, scope, &mut leaves);
136 }
137
138 leaves
139 .iter()
140 .map(|leaf| Placed {
141 element: leaf.element,
142 offset: leaf.offset,
143 measure_offset: leaf.measure_start.map(|start| leaf.offset - start),
144 key_signature: in_force(&leaves, leaf, |element| match element {
145 StreamElement::KeySignature(key) => Some(key),
146 _ => None,
147 }),
148 time_signature: in_force(&leaves, leaf, |element| match element {
149 StreamElement::TimeSignature(meter) => Some(meter),
150 _ => None,
151 }),
152 metronome_mark: in_force(&leaves, leaf, |element| match element {
153 StreamElement::MetronomeMark(mark) => Some(mark),
154 _ => None,
155 }),
156 })
157 .collect()
158 }
159
160 fn measure_start(&self, base: FloatType) -> Option<FloatType> {
162 (self.kind == StreamKind::Measure).then_some(base)
163 }
164
165 fn gather<'a>(
166 &'a self,
167 base: FloatType,
168 measure_start: Option<FloatType>,
169 scope: Scope,
170 out: &mut Vec<Leaf<'a>>,
171 ) {
172 let measure_start = self.measure_start(base).or(measure_start);
173 for event in &self.events {
174 let offset = base + event.offset;
175 if let StreamElement::Stream(stream) = &event.element {
176 stream.gather(offset, measure_start, scope, out);
177 continue;
178 }
179
180 out.push(Leaf {
181 element: &event.element,
182 offset,
183 measure_start,
184 scope,
185 });
186 }
187 }
188}
189
190fn in_force<'a, T>(
193 leaves: &[Leaf<'a>],
194 leaf: &Leaf<'a>,
195 read: impl Fn(&'a StreamElement) -> Option<&'a T>,
196) -> Option<&'a T> {
197 let mut found: Option<(FloatType, &'a T)> = None;
198 for mark in leaves {
199 if mark.offset > leaf.offset || !mark.scope.reaches(leaf.scope) {
200 continue;
201 }
202 let Some(value) = read(mark.element) else {
203 continue;
204 };
205 if found.is_none_or(|(offset, _)| mark.offset >= offset) {
206 found = Some((mark.offset, value));
207 }
208 }
209 found.map(|(_, value)| value)
210}
211
212#[cfg(test)]
213mod tests {
214 use crate::{
215 KeySignature, Note, Stream, StreamElement, meter::TimeSignature, stream::StreamKind,
216 };
217
218 fn measure(notes: &[&str]) -> Stream {
219 let mut measure = Stream::with_kind(StreamKind::Measure);
220 for name in notes {
221 measure.push(Note::from_name(name).unwrap());
222 }
223 measure
224 }
225
226 #[test]
228 fn each_part_reads_its_own_marks() {
229 let mut first = measure(&["C4", "D4", "E4", "F4"]);
230 first.insert(0.0, KeySignature::new(-1));
231 let mut flute = Stream::with_kind(StreamKind::Part);
232 flute.insert(0.0, first);
233 flute.insert(4.0, measure(&["G4"]));
234 let mut oboe = Stream::with_kind(StreamKind::Part);
235 oboe.insert(0.0, measure(&["A4"]));
236 let mut score = Stream::with_kind(StreamKind::Score);
237 score.insert(0.0, TimeSignature::new(4, 4).unwrap());
238 score.insert(0.0, flute);
239 score.insert(0.0, oboe);
240
241 let notes: Vec<_> = score
242 .placed()
243 .into_iter()
244 .filter(|placed| matches!(placed.element(), StreamElement::Note(_)))
245 .collect();
246 let sharps = |index: usize| notes[index].key_signature().and_then(KeySignature::sharps);
247
248 assert_eq!(notes.len(), 6);
249 assert_eq!(sharps(4), Some(-1));
250 assert_eq!(notes[4].offset(), 4.0);
251 assert_eq!(notes[4].measure_offset(), Some(0.0));
252 assert_eq!(notes[3].measure_offset(), Some(3.0));
253 assert_eq!(sharps(5), None);
254 assert!(notes.iter().all(|placed| placed.time_signature().is_some()));
255 }
256
257 #[test]
259 fn placed_follows_leaves() {
260 let mut part = Stream::with_kind(StreamKind::Part);
261 part.insert(0.0, measure(&["C4", "D4"]));
262 part.insert(2.0, measure(&["E4"]));
263 let offsets: Vec<_> = part.placed().iter().map(|placed| placed.offset()).collect();
264 let leaves: Vec<_> = part.leaves().iter().map(|(offset, _)| *offset).collect();
265 assert_eq!(offsets, leaves);
266 }
267}