1use super::notation::Barline;
2use super::score::Score;
3
4pub fn measure_sequence(score: &Score) -> Vec<usize> {
17 let measures = match score
18 .parts
19 .first()
20 .and_then(|p| p.staves.first())
21 .map(|s| &s.measures)
22 {
23 Some(m) => m,
24 None => return vec![],
25 };
26
27 let n = measures.len();
28
29 let mut segno_idx: Option<usize> = None;
31 let mut coda_idx: Option<usize> = None;
32 for (j, m) in measures.iter().enumerate() {
33 match m.navigation.as_deref() {
34 Some("Segno") => segno_idx = Some(j),
35 Some("Coda") => coda_idx = Some(j),
36 _ => {}
37 }
38 }
39
40 let mut seq = Vec::with_capacity(n + 4);
41 let mut repeat_jumps = vec![0u8; n];
45 let mut jump_taken = vec![false; n];
46 let limit = n.saturating_mul(16).max(64);
48 let mut i = 0usize;
49 let mut repeat_start = 0usize;
50 let mut volta_pass: u8 = 1;
51 let mut in_nav_pass = false;
53 let mut nav_fine = false; let mut nav_coda = false; while i < n && seq.len() < limit {
57 let m = &measures[i];
58
59 if !in_nav_pass {
61 if let Some(volta) = &m.volta
63 && !volta.plays_on(volta_pass)
64 && (volta.kind == "begin" || volta.kind == "begin_end")
65 {
66 if volta.kind == "begin_end" {
67 i += 1;
68 continue;
69 } else {
70 i += 1;
71 while i < n {
72 if let Some(v) = &measures[i].volta
73 && v.kind == "end"
74 {
75 i += 1;
76 break;
77 }
78 i += 1;
79 }
80 continue;
81 }
82 }
83 }
84
85 seq.push(i);
86
87 if in_nav_pass {
89 if nav_fine && matches!(m.navigation.as_deref(), Some("Fine")) {
90 break;
91 }
92 if nav_coda
93 && matches!(m.navigation.as_deref(), Some("ToCoda"))
94 && let Some(ci) = coda_idx
95 {
96 i = ci;
97 in_nav_pass = false;
98 continue;
99 }
100 } else {
101 let jump: Option<(usize, bool, bool)> = match m.navigation.as_deref() {
103 Some("DaCapo") => Some((0, false, false)),
104 Some("DaCapoAlFine") => Some((0, true, false)),
105 Some("DaCapoAlCoda") => Some((0, false, true)),
106 Some("DalSegno") => segno_idx.map(|s| (s, false, false)),
107 Some("DalSegnoAlFine") => segno_idx.map(|s| (s, true, false)),
108 Some("DalSegnoAlCoda") => segno_idx.map(|s| (s, false, true)),
109 _ => None,
110 };
111 if let Some((target, fine, coda)) = jump
112 && !std::mem::replace(&mut jump_taken[i], true)
113 {
114 in_nav_pass = true;
115 nav_fine = fine;
116 nav_coda = coda;
117 i = target;
118 continue;
119 }
120
121 if matches!(m.barline_left, Barline::RepeatStart | Barline::RepeatBoth) {
123 if repeat_start != i {
127 volta_pass = 1;
128 }
129 repeat_start = i;
130 }
131
132 match m.barline_right {
133 Barline::RepeatEnd | Barline::RepeatBoth => {
134 let last_pass = if m.volta.is_some() {
137 let mut last = volta_pass;
138 let mut j = repeat_start;
139 while j < n && (j <= i || measures[j].volta.is_some()) {
140 if let Some(volta) = &measures[j].volta {
141 last = last.max(volta.passes().into_iter().max().unwrap_or(1));
142 }
143 j += 1;
144 }
145 last
146 } else {
147 2
148 };
149 let again = if m.volta.is_some() {
152 volta_pass < last_pass
153 && usize::from(repeat_jumps[i]) + 1 < usize::from(last_pass)
154 } else {
155 repeat_jumps[i] == 0
156 };
157 if again {
158 repeat_jumps[i] = repeat_jumps[i].saturating_add(1);
159 volta_pass = volta_pass.saturating_add(1).min(last_pass);
160 i = repeat_start;
161 } else {
162 volta_pass = 1;
163 if matches!(m.barline_right, Barline::RepeatBoth) {
164 repeat_start = i + 1;
165 }
166 i += 1;
167 }
168 continue;
169 }
170 _ => {}
171 }
172 }
173
174 i += 1;
175 }
176
177 seq
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::model::notation::Barline;
184 use crate::model::score::{Measure, Score, VoltaBracket};
185
186 fn score_with_measures(measures: Vec<Measure>) -> Score {
187 let mut score = Score::new("T", 120, 4, 4, 0, 0);
188 score.parts[0].staves[0].measures = measures;
189 score
190 }
191
192 fn plain(n: u32) -> Measure {
193 let mut m = Measure::empty(4, 4);
194 m.number = n;
195 m
196 }
197
198 fn with_nav(n: u32, nav: &str) -> Measure {
199 let mut m = plain(n);
200 m.navigation = Some(nav.to_string());
201 m
202 }
203
204 #[test]
205 fn an_ending_for_several_passes_repeats_the_section_that_many_times() {
206 let mut a = plain(1);
208 a.barline_left = Barline::RepeatStart;
209 let mut b = plain(2);
210 b.barline_right = Barline::RepeatEnd;
211 b.volta = Some(VoltaBracket {
212 number: 1,
213 kind: "begin_end".into(),
214 numbers: vec![1, 2],
215 });
216 let mut c = plain(3);
217 c.volta = Some(VoltaBracket {
218 number: 3,
219 kind: "begin_end".into(),
220 numbers: Vec::new(),
221 });
222 let score = score_with_measures(vec![a, b, c]);
223 assert_eq!(measure_sequence(&score), vec![0, 1, 0, 1, 0, 2]);
224 assert_eq!(VoltaBracket::parse_passes("1, 2"), vec![1, 2]);
225 assert_eq!(VoltaBracket::parse_passes("1-3"), vec![1, 2, 3]);
226 let three = VoltaBracket {
227 number: 1,
228 kind: "begin".into(),
229 numbers: vec![1, 2, 3],
230 };
231 assert_eq!(three.label(), "1-3");
232 }
233
234 #[test]
235 fn unpaired_repeat_marks_play_each_repeat_once_instead_of_looping() {
236 let volta = |number, kind: &str| {
240 Some(VoltaBracket {
241 number,
242 kind: kind.into(),
243 numbers: Vec::new(),
244 })
245 };
246 let mut m1 = plain(2);
247 m1.barline_right = Barline::RepeatEnd;
248 m1.volta = volta(1, "end");
249 let mut m2 = plain(3);
250 m2.volta = volta(2, "begin_end");
251 let mut m3 = plain(4);
252 m3.barline_right = Barline::RepeatEnd;
253 m3.volta = volta(2, "end");
254 let mut m4 = plain(5);
255 m4.volta = volta(2, "begin_end");
256 let score = score_with_measures(vec![plain(1), m1, m2, m3, m4]);
257 let sequence = measure_sequence(&score);
258 assert!(sequence.len() < 20, "{sequence:?}");
259 assert_eq!(sequence.iter().filter(|&&bar| bar == 3).count(), 2);
260 }
261
262 #[test]
263 fn a_coda_before_its_da_capo_does_not_loop() {
264 let score = score_with_measures(vec![
265 with_nav(1, "Coda"),
266 with_nav(2, "ToCoda"),
267 with_nav(3, "DaCapoAlCoda"),
268 ]);
269 let sequence = measure_sequence(&score);
270 assert!(sequence.len() < 20, "{sequence:?}");
271 }
272
273 #[test]
274 fn no_repeat_is_linear() {
275 let score = score_with_measures(vec![plain(1), plain(2), plain(3), plain(4)]);
276 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3]);
277 }
278
279 #[test]
280 fn simple_repeat_doubles_section() {
281 let mut m0 = plain(1);
282 m0.barline_left = Barline::RepeatStart;
283 let m1 = plain(2);
284 let mut m2 = plain(3);
285 m2.barline_right = Barline::RepeatEnd;
286 let m3 = plain(4);
287
288 let score = score_with_measures(vec![m0, m1, m2, m3]);
289 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2, 3]);
290 }
291
292 #[test]
293 fn volta_first_pass_plays_ending_1() {
294 let mut m0 = plain(1);
295 m0.barline_left = Barline::RepeatStart;
296 let m1 = plain(2);
297 let mut m2 = plain(3);
298 m2.volta = Some(VoltaBracket {
299 number: 1,
300 kind: "begin_end".into(),
301 numbers: Vec::new(),
302 });
303 m2.barline_right = Barline::RepeatEnd;
304 let mut m3 = plain(4);
305 m3.volta = Some(VoltaBracket {
306 number: 2,
307 kind: "begin_end".into(),
308 numbers: Vec::new(),
309 });
310
311 let score = score_with_measures(vec![m0, m1, m2, m3]);
312 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 3]);
313 }
314
315 #[test]
316 fn volta_second_pass_skips_ending_1() {
317 let mut m0 = plain(1);
318 m0.barline_left = Barline::RepeatStart;
319 let m1 = plain(2);
320 let mut m2 = plain(3);
321 m2.volta = Some(VoltaBracket {
322 number: 1,
323 kind: "begin_end".into(),
324 numbers: Vec::new(),
325 });
326 m2.barline_right = Barline::RepeatEnd;
327 let mut m3 = plain(4);
328 m3.volta = Some(VoltaBracket {
329 number: 2,
330 kind: "begin_end".into(),
331 numbers: Vec::new(),
332 });
333 let m4 = plain(5);
334
335 let score = score_with_measures(vec![m0, m1, m2, m3, m4]);
336 let seq = measure_sequence(&score);
337 assert_eq!(seq, vec![0, 1, 2, 0, 1, 3, 4]);
338 let second_pass_third = seq[5];
339 assert_eq!(second_pass_third, 3);
340 }
341
342 #[test]
343 fn independent_repeat_sections_restart_at_their_first_pass() {
344 let ending = |number| {
345 Some(VoltaBracket {
346 number,
347 kind: "begin_end".into(),
348 numbers: Vec::new(),
349 })
350 };
351 let mut first_start = plain(1);
352 first_start.barline_left = Barline::RepeatStart;
353 let mut first_ending = plain(2);
354 first_ending.barline_right = Barline::RepeatEnd;
355 first_ending.volta = ending(1);
356 let mut second_ending = plain(3);
357 second_ending.volta = ending(2);
358
359 let mut next_start = plain(4);
360 next_start.barline_left = Barline::RepeatStart;
361 let mut next_first_ending = plain(5);
362 next_first_ending.barline_right = Barline::RepeatEnd;
363 next_first_ending.volta = ending(1);
364 let mut next_second_ending = plain(6);
365 next_second_ending.volta = ending(2);
366
367 let score = score_with_measures(vec![
368 first_start,
369 first_ending,
370 second_ending,
371 next_start,
372 next_first_ending,
373 next_second_ending,
374 ]);
375 assert_eq!(measure_sequence(&score), vec![0, 1, 0, 2, 3, 4, 3, 5]);
376 }
377
378 #[test]
381 fn da_capo_jumps_to_start() {
382 let score = score_with_measures(vec![plain(1), plain(2), with_nav(3, "DaCapo")]);
385 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2]);
387 }
388
389 #[test]
390 fn da_capo_al_fine_stops_at_fine() {
391 let mut m0 = plain(1);
393 m0.navigation = Some("Fine".into());
394 let score = score_with_measures(vec![m0, plain(2), with_nav(3, "DaCapoAlFine")]);
395 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0]);
397 }
398
399 #[test]
400 fn dal_segno_al_coda_jumps_to_coda() {
401 let mut m1 = plain(2);
405 m1.navigation = Some("Segno".into());
406 let mut m3 = plain(4);
407 m3.navigation = Some("ToCoda".into());
408 let mut m5 = plain(6);
409 m5.navigation = Some("Coda".into());
410 let score = score_with_measures(vec![
411 plain(1),
412 m1,
413 plain(3),
414 m3,
415 with_nav(5, "DalSegnoAlCoda"),
416 m5,
417 plain(7),
418 ]);
419 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3, 4, 1, 2, 3, 5, 6]);
420 }
421}