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 i = 0usize;
42 let mut repeat_start = 0usize;
43 let mut volta_pass: u8 = 1;
44 let mut in_nav_pass = false;
46 let mut nav_fine = false; let mut nav_coda = false; while i < n {
50 let m = &measures[i];
51
52 if !in_nav_pass {
54 if let Some(volta) = &m.volta
56 && volta.number != volta_pass
57 && (volta.kind == "begin" || volta.kind == "begin_end")
58 {
59 if volta.kind == "begin_end" {
60 i += 1;
61 continue;
62 } else {
63 i += 1;
64 while i < n {
65 if let Some(v) = &measures[i].volta
66 && v.kind == "end"
67 {
68 i += 1;
69 break;
70 }
71 i += 1;
72 }
73 continue;
74 }
75 }
76 }
77
78 seq.push(i);
79
80 if in_nav_pass {
82 if nav_fine && matches!(m.navigation.as_deref(), Some("Fine")) {
83 break;
84 }
85 if nav_coda
86 && matches!(m.navigation.as_deref(), Some("ToCoda"))
87 && let Some(ci) = coda_idx
88 {
89 i = ci;
90 in_nav_pass = false;
91 continue;
92 }
93 } else {
94 let jump: Option<(usize, bool, bool)> = match m.navigation.as_deref() {
96 Some("DaCapo") => Some((0, false, false)),
97 Some("DaCapoAlFine") => Some((0, true, false)),
98 Some("DaCapoAlCoda") => Some((0, false, true)),
99 Some("DalSegno") => segno_idx.map(|s| (s, false, false)),
100 Some("DalSegnoAlFine") => segno_idx.map(|s| (s, true, false)),
101 Some("DalSegnoAlCoda") => segno_idx.map(|s| (s, false, true)),
102 _ => None,
103 };
104 if let Some((target, fine, coda)) = jump {
105 in_nav_pass = true;
106 nav_fine = fine;
107 nav_coda = coda;
108 i = target;
109 continue;
110 }
111
112 if matches!(m.barline_left, Barline::RepeatStart | Barline::RepeatBoth) {
114 repeat_start = i;
115 }
116
117 match m.barline_right {
118 Barline::RepeatEnd | Barline::RepeatBoth => {
119 if volta_pass == 1 {
120 volta_pass = 2;
121 i = repeat_start;
122 } else {
123 volta_pass = 1;
124 if matches!(m.barline_right, Barline::RepeatBoth) {
125 repeat_start = i + 1;
126 }
127 i += 1;
128 }
129 continue;
130 }
131 _ => {}
132 }
133 }
134
135 i += 1;
136 }
137
138 seq
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::model::notation::Barline;
145 use crate::model::score::{Measure, Score, VoltaBracket};
146
147 fn score_with_measures(measures: Vec<Measure>) -> Score {
148 let mut score = Score::new("T", 120, 4, 4, 0, 0);
149 score.parts[0].staves[0].measures = measures;
150 score
151 }
152
153 fn plain(n: u32) -> Measure {
154 let mut m = Measure::empty(4, 4);
155 m.number = n;
156 m
157 }
158
159 fn with_nav(n: u32, nav: &str) -> Measure {
160 let mut m = plain(n);
161 m.navigation = Some(nav.to_string());
162 m
163 }
164
165 #[test]
166 fn no_repeat_is_linear() {
167 let score = score_with_measures(vec![plain(1), plain(2), plain(3), plain(4)]);
168 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3]);
169 }
170
171 #[test]
172 fn simple_repeat_doubles_section() {
173 let mut m0 = plain(1);
174 m0.barline_left = Barline::RepeatStart;
175 let m1 = plain(2);
176 let mut m2 = plain(3);
177 m2.barline_right = Barline::RepeatEnd;
178 let m3 = plain(4);
179
180 let score = score_with_measures(vec![m0, m1, m2, m3]);
181 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2, 3]);
182 }
183
184 #[test]
185 fn volta_first_pass_plays_ending_1() {
186 let mut m0 = plain(1);
187 m0.barline_left = Barline::RepeatStart;
188 let m1 = plain(2);
189 let mut m2 = plain(3);
190 m2.volta = Some(VoltaBracket {
191 number: 1,
192 kind: "begin_end".into(),
193 });
194 m2.barline_right = Barline::RepeatEnd;
195 let mut m3 = plain(4);
196 m3.volta = Some(VoltaBracket {
197 number: 2,
198 kind: "begin_end".into(),
199 });
200
201 let score = score_with_measures(vec![m0, m1, m2, m3]);
202 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 3]);
203 }
204
205 #[test]
206 fn volta_second_pass_skips_ending_1() {
207 let mut m0 = plain(1);
208 m0.barline_left = Barline::RepeatStart;
209 let m1 = plain(2);
210 let mut m2 = plain(3);
211 m2.volta = Some(VoltaBracket {
212 number: 1,
213 kind: "begin_end".into(),
214 });
215 m2.barline_right = Barline::RepeatEnd;
216 let mut m3 = plain(4);
217 m3.volta = Some(VoltaBracket {
218 number: 2,
219 kind: "begin_end".into(),
220 });
221 let m4 = plain(5);
222
223 let score = score_with_measures(vec![m0, m1, m2, m3, m4]);
224 let seq = measure_sequence(&score);
225 assert_eq!(seq, vec![0, 1, 2, 0, 1, 3, 4]);
226 let second_pass_third = seq[5];
227 assert_eq!(second_pass_third, 3);
228 }
229
230 #[test]
233 fn da_capo_jumps_to_start() {
234 let score = score_with_measures(vec![plain(1), plain(2), with_nav(3, "DaCapo")]);
237 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0, 1, 2]);
239 }
240
241 #[test]
242 fn da_capo_al_fine_stops_at_fine() {
243 let mut m0 = plain(1);
245 m0.navigation = Some("Fine".into());
246 let score = score_with_measures(vec![m0, plain(2), with_nav(3, "DaCapoAlFine")]);
247 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 0]);
249 }
250
251 #[test]
252 fn dal_segno_al_coda_jumps_to_coda() {
253 let mut m1 = plain(2);
257 m1.navigation = Some("Segno".into());
258 let mut m3 = plain(4);
259 m3.navigation = Some("ToCoda".into());
260 let mut m5 = plain(6);
261 m5.navigation = Some("Coda".into());
262 let score = score_with_measures(vec![
263 plain(1),
264 m1,
265 plain(3),
266 m3,
267 with_nav(5, "DalSegnoAlCoda"),
268 m5,
269 plain(7),
270 ]);
271 assert_eq!(measure_sequence(&score), vec![0, 1, 2, 3, 4, 1, 2, 3, 5, 6]);
272 }
273}