1use super::notation::Barline;
2use super::score::Score;
3
4pub fn measure_sequence(score: &Score) -> Vec<usize> {
17 let measures = match score.parts.first()
18 .and_then(|p| p.staves.first())
19 .map(|s| &s.measures)
20 {
21 Some(m) => m,
22 None => return vec![],
23 };
24
25 let n = measures.len();
26
27 let mut segno_idx: Option<usize> = None;
29 let mut coda_idx: Option<usize> = None;
30 for (j, m) in measures.iter().enumerate() {
31 match m.navigation.as_deref() {
32 Some("Segno") => segno_idx = Some(j),
33 Some("Coda") => coda_idx = Some(j),
34 _ => {}
35 }
36 }
37
38 let mut seq = Vec::with_capacity(n + 4);
39 let mut i = 0usize;
40 let mut repeat_start = 0usize;
41 let mut volta_pass: u8 = 1;
42 let mut in_nav_pass = false;
44 let mut nav_fine = false; let mut nav_coda = false; while i < n {
48 let m = &measures[i];
49
50 if !in_nav_pass {
52 if let Some(volta) = &m.volta
54 && volta.number != volta_pass
55 && (volta.kind == "begin" || volta.kind == "begin_end")
56 {
57 if volta.kind == "begin_end" {
58 i += 1;
59 continue;
60 } else {
61 i += 1;
62 while i < n {
63 if let Some(v) = &measures[i].volta
64 && v.kind == "end"
65 {
66 i += 1;
67 break;
68 }
69 i += 1;
70 }
71 continue;
72 }
73 }
74 }
75
76 seq.push(i);
77
78 if in_nav_pass {
80 if nav_fine && matches!(m.navigation.as_deref(), Some("Fine")) {
81 break;
82 }
83 if nav_coda
84 && matches!(m.navigation.as_deref(), Some("ToCoda"))
85 && let Some(ci) = coda_idx
86 {
87 i = ci;
88 in_nav_pass = false;
89 continue;
90 }
91 } else {
92 let jump: Option<(usize, bool, bool)> = match m.navigation.as_deref() {
94 Some("DaCapo") => Some((0, false, false)),
95 Some("DaCapoAlFine") => Some((0, true, false)),
96 Some("DaCapoAlCoda") => Some((0, false, true)),
97 Some("DalSegno") => segno_idx.map(|s| (s, false, false)),
98 Some("DalSegnoAlFine") => segno_idx.map(|s| (s, true, false)),
99 Some("DalSegnoAlCoda") => segno_idx.map(|s| (s, false, true)),
100 _ => None,
101 };
102 if let Some((target, fine, coda)) = jump {
103 in_nav_pass = true;
104 nav_fine = fine;
105 nav_coda = coda;
106 i = target;
107 continue;
108 }
109
110 if matches!(m.barline_left, Barline::RepeatStart | Barline::RepeatBoth) {
112 repeat_start = i;
113 }
114
115 match m.barline_right {
116 Barline::RepeatEnd | Barline::RepeatBoth => {
117 if volta_pass == 1 {
118 volta_pass = 2;
119 i = repeat_start;
120 } else {
121 volta_pass = 1;
122 if matches!(m.barline_right, Barline::RepeatBoth) {
123 repeat_start = i + 1;
124 }
125 i += 1;
126 }
127 continue;
128 }
129 _ => {}
130 }
131 }
132
133 i += 1;
134 }
135
136 seq
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::model::score::{Measure, Score, VoltaBracket};
143 use crate::model::notation::Barline;
144
145 fn score_with_measures(measures: Vec<Measure>) -> Score {
146 let mut score = Score::new("T", 120, 4, 4, 0, 0);
147 score.parts[0].staves[0].measures = measures;
148 score
149 }
150
151 fn plain(n: u32) -> Measure {
152 let mut m = Measure::empty(4, 4);
153 m.number = n;
154 m
155 }
156
157 fn with_nav(n: u32, nav: &str) -> Measure {
158 let mut m = plain(n);
159 m.navigation = Some(nav.to_string());
160 m
161 }
162
163 #[test]
164 fn no_repeat_is_linear() {
165 let score = score_with_measures(vec![plain(1), plain(2), plain(3), plain(4)]);
166 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3]);
167 }
168
169 #[test]
170 fn simple_repeat_doubles_section() {
171 let mut m0 = plain(1);
172 m0.barline_left = Barline::RepeatStart;
173 let m1 = plain(2);
174 let mut m2 = plain(3);
175 m2.barline_right = Barline::RepeatEnd;
176 let m3 = plain(4);
177
178 let score = score_with_measures(vec![m0, m1, m2, m3]);
179 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2, 3]);
180 }
181
182 #[test]
183 fn volta_first_pass_plays_ending_1() {
184 let mut m0 = plain(1);
185 m0.barline_left = Barline::RepeatStart;
186 let m1 = plain(2);
187 let mut m2 = plain(3);
188 m2.volta = Some(VoltaBracket { number: 1, kind: "begin_end".into() });
189 m2.barline_right = Barline::RepeatEnd;
190 let mut m3 = plain(4);
191 m3.volta = Some(VoltaBracket { number: 2, kind: "begin_end".into() });
192
193 let score = score_with_measures(vec![m0, m1, m2, m3]);
194 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 3]);
195 }
196
197 #[test]
198 fn volta_second_pass_skips_ending_1() {
199 let mut m0 = plain(1);
200 m0.barline_left = Barline::RepeatStart;
201 let m1 = plain(2);
202 let mut m2 = plain(3);
203 m2.volta = Some(VoltaBracket { number: 1, kind: "begin_end".into() });
204 m2.barline_right = Barline::RepeatEnd;
205 let mut m3 = plain(4);
206 m3.volta = Some(VoltaBracket { number: 2, kind: "begin_end".into() });
207 let m4 = plain(5);
208
209 let score = score_with_measures(vec![m0, m1, m2, m3, m4]);
210 let seq = measure_sequence(&score);
211 assert_eq!(seq, vec![0, 1, 2, 0, 1, 3, 4]);
212 let second_pass_third = seq[5];
213 assert_eq!(second_pass_third, 3);
214 }
215
216 #[test]
219 fn da_capo_jumps_to_start() {
220 let score = score_with_measures(vec![
223 plain(1), plain(2), with_nav(3, "DaCapo"),
224 ]);
225 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2]);
227 }
228
229 #[test]
230 fn da_capo_al_fine_stops_at_fine() {
231 let mut m0 = plain(1);
233 m0.navigation = Some("Fine".into());
234 let score = score_with_measures(vec![
235 m0, plain(2), with_nav(3, "DaCapoAlFine"),
236 ]);
237 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0]);
239 }
240
241 #[test]
242 fn dal_segno_al_coda_jumps_to_coda() {
243 let mut m1 = plain(2);
247 m1.navigation = Some("Segno".into());
248 let mut m3 = plain(4);
249 m3.navigation = Some("ToCoda".into());
250 let mut m5 = plain(6);
251 m5.navigation = Some("Coda".into());
252 let score = score_with_measures(vec![
253 plain(1), m1, plain(3), m3, with_nav(5, "DalSegnoAlCoda"), m5, plain(7),
254 ]);
255 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3, 4, 1, 2, 3, 5, 6]);
256 }
257}