klavier_core/
repeat.rs

1use std::{ops::Range, fmt::Display};
2use error_stack::{Report, IntoReport};
3use gcollections::ops::{Intersection, Union, Bounded};
4use interval::{IntervalSet, interval_set::ToIntervalSet};
5use klavier_helper::store::Store;
6use crate::{bar::{Bar, VarIndex, Repeat}, rhythm::Rhythm, have_start_tick::HaveBaseStartTick, global_repeat::{GlobalRepeat, RenderRegionWarning, GlobalRepeatBuilder}};
7
8// Accumulated tick after repeats are rendered.
9pub type AccumTick = u32;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Chunk {
13  start_tick: u32,
14  end_tick: u32,
15}
16
17impl Chunk {
18  pub fn new(start_tick: u32, end_tick: u32) -> Self {
19    Self {
20      start_tick, end_tick
21    }
22  }
23
24  pub fn start_tick(self) -> u32 {
25    self.start_tick
26  }
27
28  pub fn end_tick(self) -> u32 {
29    self.end_tick
30  }
31
32  pub fn optimize(chunks: &[Chunk]) -> Vec<Chunk> {
33    let mut ret: Vec<Chunk> = vec![];
34    let mut z = chunks.iter();
35    let mut cur = match z.next() {
36      None => return ret,
37      Some(c) => *c,
38    };
39
40    for next in z {
41      if cur.end_tick == next.start_tick {
42        cur.end_tick = next.end_tick;
43      } else {
44        ret.push(cur);
45        cur = *next;
46      }
47    }
48
49    ret.push(cur);
50    ret
51  }
52
53  pub fn contains(self, tick: u32) -> bool {
54    self.start_tick <= tick && tick < self.end_tick
55  }
56
57  pub fn len(self) -> u32 {
58    self.end_tick - self.start_tick()
59  }
60
61  pub fn is_empty(self) -> bool {
62    self.start_tick == self.end_tick
63  }
64
65  pub fn by_accum_tick(chunks: &[Chunk]) -> Store<AccumTick, Chunk, ()> {
66    let mut offset: u32 = 0;
67    let mut buf: Store<AccumTick, Chunk, ()> = Store::new(false);
68
69    for c in chunks {
70        buf.add(offset, *c, ());
71        if c.end_tick() != u32::MAX {
72            offset += c.len();
73        }
74    }
75
76    buf
77  }
78}
79
80pub trait Region: std::fmt::Debug {
81  fn to_chunks(&self) -> Vec<Chunk>;
82}
83
84#[derive(Debug, Clone, PartialEq)]
85enum RenderPhase {
86  NonDcDs,
87  DcDsIter0 { dc_ds_tick: u32 },
88  DcDsIter1 { global_repeat: GlobalRepeat },
89}
90
91// SimpleRegion can be stored in a compound region.
92trait SimpleRegion: Region {
93  fn render_chunks(&self, phase: &RenderPhase) -> Vec<Chunk>;
94  fn to_iter1_chunks(&self, global_repeat: &GlobalRepeat) -> Vec<Chunk>;
95}
96
97#[derive(Debug, PartialEq, Eq)]
98pub struct SequenceRegion {
99  tick_range: Range<u32>,
100}
101
102impl SequenceRegion {
103  #[inline]
104  #[allow(dead_code)]
105  fn tick_len(&self) -> u32 {
106    self.tick_range.len() as u32
107  }
108
109  #[inline]
110  fn start_tick(&self) -> u32 {
111    self.tick_range.start
112  }
113
114  // Exclusive
115  #[inline]
116  fn end_tick(&self) -> u32 {
117    self.tick_range.end
118  }
119
120  fn to_iter1_interval_set(&self) -> IntervalSet<u32> {
121    (self.tick_range.start, self.tick_range.end - 1).to_interval_set()
122  }
123}
124
125impl Region for SequenceRegion {
126  fn to_chunks(&self) -> Vec<Chunk> {
127    self.render_chunks(&RenderPhase::NonDcDs)
128  }
129}
130
131impl SimpleRegion for SequenceRegion {
132  fn render_chunks(&self, phase: &RenderPhase) -> Vec<Chunk> {
133    match phase {
134      RenderPhase::NonDcDs => vec![Chunk { start_tick: self.start_tick(), end_tick: self.end_tick() }],
135      RenderPhase::DcDsIter0 { dc_ds_tick } => {
136        if self.end_tick() <= *dc_ds_tick {
137          vec![Chunk::new(self.start_tick(), self.end_tick())]
138        } else if self.start_tick() < *dc_ds_tick && *dc_ds_tick < self.end_tick() {
139          vec![Chunk::new(self.start_tick(), *dc_ds_tick)]
140        } else {
141          vec![]
142        }
143      }
144      RenderPhase::DcDsIter1 { global_repeat } => {
145        self.to_iter1_chunks(global_repeat)
146      }
147    }
148  }
149  
150  fn to_iter1_chunks(&self, global_repeat: &GlobalRepeat) -> Vec<Chunk> {
151    let sections: IntervalSet<u32> = global_repeat.iter1_interval_set().clone().intersection(
152      &self.to_iter1_interval_set()
153    );
154
155    sections.into_iter().map(|sec| {
156      Chunk::new(sec.lower(), sec.upper() + 1)
157    }).collect()
158  }
159}
160
161#[derive(Debug, PartialEq, Eq)]
162pub struct RepeatRegion {
163  region: SequenceRegion,
164}
165
166impl RepeatRegion {
167  fn to_iter1_interval_set(&self) -> IntervalSet<u32> {
168    (self.region.start_tick(), self.region.end_tick() - 1).to_interval_set()
169  }
170}
171
172impl Region for RepeatRegion {
173  fn to_chunks(&self) -> Vec<Chunk> {
174    self.render_chunks(&RenderPhase::NonDcDs)
175  }
176}
177
178impl SimpleRegion for RepeatRegion {
179  fn render_chunks(&self, phase: &RenderPhase) -> Vec<Chunk> {
180    fn full(sr: &RepeatRegion) -> Vec<Chunk> {
181      let mut chunks = Vec::with_capacity(2);
182      chunks.extend(sr.region.to_chunks());
183      chunks.extend(sr.region.to_chunks());
184      chunks
185    }
186
187    match phase {
188        RenderPhase::NonDcDs => full(self),
189        RenderPhase::DcDsIter0 { dc_ds_tick } => {
190          if self.region.end_tick() <= *dc_ds_tick {
191            full(self)
192          } else if self.region.end_tick() < *dc_ds_tick && *dc_ds_tick < self.region.end_tick() {
193            // This condition should not occur.
194            panic!("Logic error.");
195          } else {
196            vec![]
197          }
198        },
199        RenderPhase::DcDsIter1 { global_repeat } => {
200          self.to_iter1_chunks(global_repeat)
201        }
202    }
203  }
204  
205  fn to_iter1_chunks(&self, global_repeat: &GlobalRepeat) -> Vec<Chunk> {
206    let sections: IntervalSet<u32> = global_repeat.iter1_interval_set().clone().intersection(
207      &self.to_iter1_interval_set()
208    );
209
210    sections.into_iter().map(|sec| {
211      Chunk::new(sec.lower(), sec.upper() + 1)
212    }).collect()
213  }
214}
215
216#[derive(Debug)]
217pub struct VariationRegion {
218  common: SequenceRegion,
219  variations: Vec<SequenceRegion>,
220}
221
222impl VariationRegion {
223  fn end_tick(&self) -> u32 {
224    self.variations.last().unwrap().end_tick()
225  }
226}
227
228impl VariationRegion {
229  fn last_variation(&self) -> &SequenceRegion {
230    &self.variations[self.variations.len() - 1]
231  }
232
233  fn to_iter1_interval_set(&self) -> IntervalSet<u32> {
234    self.common.to_iter1_interval_set().union(
235      &self.last_variation().to_iter1_interval_set()
236    )
237  }
238}
239
240impl Region for VariationRegion {
241  fn to_chunks(&self) -> Vec<Chunk> {
242    self.render_chunks(&RenderPhase::NonDcDs)
243  }
244}
245
246impl SimpleRegion for VariationRegion {
247  fn render_chunks(&self, phase: &RenderPhase) -> Vec<Chunk> {
248    fn full(vr: &VariationRegion) -> Vec<Chunk> {
249      let mut chunks = vec![];
250      let common = vr.common.to_chunks();
251      for v in vr.variations.iter() {
252        chunks.extend(common.clone());
253        chunks.extend(v.to_chunks());
254      }
255
256      chunks
257    }
258
259    match phase {
260        RenderPhase::NonDcDs => full(self),
261        RenderPhase::DcDsIter0 { dc_ds_tick } => {
262          if *dc_ds_tick <= self.common.start_tick() {
263            vec![]
264          } else if *dc_ds_tick < self.end_tick() {
265            // This condition should not occur.
266            panic!("Logic error");
267          } else {
268            full(self)
269          }
270        },
271        RenderPhase::DcDsIter1 { global_repeat } => {
272          self.to_iter1_chunks(global_repeat)
273        }
274    }
275  }
276  
277  fn to_iter1_chunks(&self, global_repeat: &GlobalRepeat) -> Vec<Chunk> {
278    let sections: IntervalSet<u32> = global_repeat.iter1_interval_set().clone().intersection(
279      &self.to_iter1_interval_set()
280    );
281
282    sections.into_iter().map(|sec| {
283      Chunk::new(sec.lower(), sec.upper() + 1)
284    }).collect()
285  }
286}
287
288#[derive(Debug)]
289pub struct CompoundRegion {
290  global_repeat: Option<GlobalRepeat>,
291  regions: Vec<Box<dyn SimpleRegion>>,
292}
293
294impl Region for CompoundRegion {
295  fn to_chunks(&self) -> Vec<Chunk> {
296    match self.global_repeat.as_ref() {
297      Some(gr) => {
298        let mut chunks = vec![];
299        for r in self.regions.iter() {
300          chunks.extend(r.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: gr.ds_dc().tick() }));
301        }
302        for r in self.regions.iter() {
303          chunks.extend(r.render_chunks(&RenderPhase::DcDsIter1 { global_repeat: gr.clone() } ));
304        }
305        
306        chunks
307      }
308      None => {
309        let mut chunks = vec![];
310        for r in self.regions.iter() {
311          chunks.extend(r.render_chunks(&RenderPhase::NonDcDs));
312        }
313        
314        chunks
315      }
316    }
317  }
318}
319
320#[derive(Debug)]
321enum RenderRegionState {
322  Idle,
323  Seq { start_tick: u32 },
324  RepeatStart { start_tick: u32 },
325  Variation {
326    start_tick: u32,
327    region_start_ticks: Vec<u32>,
328  },
329}
330
331#[derive(Debug, PartialEq, Eq, Clone)]
332pub enum RenderRegionError {
333  DuplicatedRepeatStart { tick: u32 },
334  DuplicatedSegno { tick: [u32; 2] },
335  DuplicatedDsDc { tick: [u32; 2] },
336  DuplicatedFine { tick: [u32; 2] },
337  OrphanRepeatEnd { tick: u32 },
338  FineWithoutDsDc { tick: u32 },
339  SegnoWithoutDs { tick: u32 },
340  CodaWithoutDsDc { tick: [u32; 2]},
341  NoRepeatEnd { tick: u32 },
342  InvalidRegionIndex { tick: u32, actual: VarIndex, expected: VarIndex },
343  RepeatInVariation { tick: u32 },
344  VariationNotClosed { tick: u32 },
345  RepeatOrVariationOnDc { tick: u32 },
346  RepeatOrVariationOnDs { tick: u32 },
347  FineNotAfterSegno { segno_tick: u32, fine_tick: u32 },
348  NoSegnoForDs { ds_tick: u32 },
349  MoreThanTwoCodas { tick: [u32; 3] },
350  OnlyOneCoda { tick: u32 },
351  DcDsWhileRepeat { tick: u32 },
352  DcDsWhileVariation { tick: u32 },
353  SegnoWhildVariation { tick: u32 },
354  CodaAfterFine { coda_from: u32, coda_to: u32, fine: u32 },
355}
356
357impl core::error::Error for RenderRegionError {}
358
359impl Display for RenderRegionError {
360    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
361        write!(f, "{:?}", self)
362    }
363}
364
365type RenderRegionResult = Result<(Box<dyn Region>, Vec<RenderRegionWarning>), Report<RenderRegionError>>;
366
367pub fn render_region<'a>(
368  tune_rhythm: Rhythm, bars: impl Iterator<Item = &'a Bar>
369) -> RenderRegionResult {
370  fn create_variation(start_tick: u32, region_start_ticks: Vec<u32>, end_tick: u32) -> Box<dyn SimpleRegion> {
371    let mut variations: Vec<SequenceRegion> = vec![];
372    let mut iter = region_start_ticks.iter();
373    let mut tick = *iter.next().unwrap();
374    for t in iter {
375      variations.push(SequenceRegion { tick_range: tick..*t });
376      tick = *t;
377    }
378
379    variations.push(SequenceRegion { tick_range: tick..end_tick });
380
381    Box::new(VariationRegion {
382      common: SequenceRegion { tick_range: start_tick..region_start_ticks[0] }, variations
383    })
384  }
385
386  let mut regions: Vec<Box<dyn SimpleRegion>> = vec![];
387  let mut state = RenderRegionState::Idle;
388  let mut is_auftakt: Option<bool> = None;
389  let mut global_repeat: GlobalRepeatBuilder = GlobalRepeatBuilder::new(tune_rhythm);
390
391  for bar in bars {
392    global_repeat = global_repeat.on_bar(bar)?;
393    if is_auftakt.is_none() && bar.base_start_tick() != 0 {
394      is_auftakt = Some(bar.base_start_tick() < tune_rhythm.tick_len());
395    }
396
397    state = match &state {
398      RenderRegionState::Idle => {
399        if bar.repeats.contains(Repeat::Start) && bar.repeats.contains(Repeat::End) {
400          regions.push(Box::new(RepeatRegion { region: SequenceRegion { tick_range: 0..bar.base_start_tick() }}));
401          RenderRegionState::RepeatStart { start_tick: bar.base_start_tick() }
402        } else if bar.repeats.contains(Repeat::End) {
403          regions.push(Box::new(RepeatRegion { region: SequenceRegion { tick_range: 0..bar.base_start_tick() }}));
404          RenderRegionState::Seq { start_tick: bar.base_start_tick() }
405        } else if bar.repeats.contains(Repeat::Start) {
406          regions.push(Box::new(SequenceRegion { tick_range: 0..bar.base_start_tick() }));
407          RenderRegionState::RepeatStart { start_tick: bar.base_start_tick() }
408        } else if let Some(idx) = bar.repeats.region_index() {
409          if idx != VarIndex::VI1 {
410            return Err(IntoReport::into_report(RenderRegionError::InvalidRegionIndex { tick: bar.base_start_tick(), actual: idx, expected: VarIndex::VI1 }));
411          }
412          RenderRegionState::Variation { start_tick: 0, region_start_ticks: vec![bar.base_start_tick()] }
413        } else {
414          state
415        }
416      },
417      RenderRegionState::Seq { start_tick } => {
418        if bar.repeats.contains(Repeat::End) {
419          return Err(IntoReport::into_report(RenderRegionError::OrphanRepeatEnd{ tick: bar.base_start_tick() }));
420        } else if bar.repeats.contains(Repeat::Start) {
421          regions.push(Box::new(SequenceRegion { tick_range: *start_tick..bar.base_start_tick() }));
422          RenderRegionState::RepeatStart { start_tick: bar.base_start_tick() }
423        } else {
424          state
425        }
426      },
427      RenderRegionState::RepeatStart { start_tick } => {
428        if bar.repeats.contains(Repeat::Start) && bar.repeats.contains(Repeat::End) {
429          regions.push(Box::new(RepeatRegion { region: SequenceRegion { tick_range: *start_tick..bar.base_start_tick() }}));
430          RenderRegionState::RepeatStart { start_tick: bar.base_start_tick() }
431        } else if bar.repeats.contains(Repeat::End) {
432          regions.push(Box::new(RepeatRegion { region: SequenceRegion { tick_range: *start_tick..bar.base_start_tick() }}));
433          RenderRegionState::Seq { start_tick: bar.base_start_tick() }
434        } else if bar.repeats.contains(Repeat::Start) {
435          return Err(IntoReport::into_report(RenderRegionError::DuplicatedRepeatStart { tick: bar.base_start_tick() }));
436        } else if bar.repeats.contains(Repeat::Dc) || bar.repeats.contains(Repeat::Ds) {
437          return Err(IntoReport::into_report(RenderRegionError::DcDsWhileRepeat { tick: bar.base_start_tick() }));
438        } else if let Some(idx) = bar.repeats.region_index() {
439          if idx != VarIndex::VI1 {
440            return Err(IntoReport::into_report(RenderRegionError::InvalidRegionIndex { tick: bar.base_start_tick(), actual: idx, expected: VarIndex::VI1 }));
441          }
442          RenderRegionState::Variation { start_tick: *start_tick, region_start_ticks: vec![bar.base_start_tick()] }
443        } else {
444          state
445        }
446      },
447      RenderRegionState::Variation { start_tick, region_start_ticks } => {
448        if bar.repeats.contains(Repeat::End) {
449          return Err(IntoReport::into_report(RenderRegionError::RepeatInVariation { tick: bar.base_start_tick() }))
450        } else if let Some(ri) = bar.repeats.region_index() {
451          if bar.repeats.contains(Repeat::Dc) || bar.repeats.contains(Repeat::Ds) {
452            return Err(IntoReport::into_report(RenderRegionError::DcDsWhileVariation { tick: bar.base_start_tick() }));
453          }
454          let current_idx = region_start_ticks.len() as u8;
455          let idx = ri.value();
456          if idx == current_idx {
457            state
458          } else if idx == current_idx + 1 {
459            let mut rst = region_start_ticks.clone();
460            rst.push(bar.base_start_tick());
461            RenderRegionState::Variation { start_tick: *start_tick, region_start_ticks: rst }
462          } else {
463            return Err(IntoReport::into_report(RenderRegionError::InvalidRegionIndex {
464              tick: bar.base_start_tick(), actual: ri, expected: VarIndex::from_value(current_idx + 1).unwrap()
465            }));
466          }
467        } else {
468          if let Some(segno) = global_repeat.segno {
469            if region_start_ticks[0] <= segno && segno < *region_start_ticks.last().unwrap() {
470              return Err(IntoReport::into_report(RenderRegionError::SegnoWhildVariation { tick: bar.base_start_tick() }));
471            }
472          }
473          regions.push(create_variation(*start_tick, region_start_ticks.clone(), bar.base_start_tick()));
474
475          if bar.repeats.contains(Repeat::Start) {
476            RenderRegionState::RepeatStart { start_tick: bar.base_start_tick() }
477          } else {
478            RenderRegionState::Seq { start_tick: bar.base_start_tick() }
479          }
480        }
481      }
482    }
483  }
484
485  match state {
486    RenderRegionState::Idle => {
487      regions.push(Box::new(SequenceRegion { tick_range: 0..u32::MAX }));
488      let (gr, w) = global_repeat.build()?;
489      Ok((Box::new(CompoundRegion { regions, global_repeat: gr }), w))
490    },
491    RenderRegionState::Seq { start_tick } => {
492      regions.push(Box::new(SequenceRegion { tick_range: start_tick..u32::MAX }));
493      let (gr, w) = global_repeat.build()?;
494      Ok((Box::new(CompoundRegion { regions, global_repeat: gr }), w))
495    }
496    RenderRegionState::RepeatStart { start_tick } => Err(IntoReport::into_report(RenderRegionError::NoRepeatEnd { tick: start_tick })),
497    RenderRegionState::Variation { start_tick: _, region_start_ticks } => {
498      Err(IntoReport::into_report(RenderRegionError::VariationNotClosed { tick: *region_start_ticks.last().unwrap() }))
499    }
500  }
501}
502
503#[cfg(test)]
504mod tests {
505  use error_stack::Report;
506
507use crate::{bar::{Bar, Repeat}, play_iter::PlayIter, play_start_tick::{PlayStartTick, ToAccumTickError}, repeat::{render_region, Chunk, GlobalRepeatBuilder, RenderRegionError, SimpleRegion}, rhythm::Rhythm};
508  use crate::repeat_set;
509  use super::{AccumTick, RenderPhase, SequenceRegion};
510  use crate::bar::RepeatSet;
511
512  fn to_accum_tick(tick: u32, iter: u8, chunks: &[(AccumTick, Chunk)]) -> std::result::Result<AccumTick, ToAccumTickError> {
513    PlayStartTick::new(tick, iter).to_accum_tick(chunks)
514  }
515
516  #[test]
517  fn empty() {
518    let bars: Vec<Bar> = vec![];
519    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
520    let chunks = region.to_chunks();
521    assert_eq!(chunks.len(), 1);
522    assert_eq!(chunks[0], Chunk::new(0, u32::MAX));
523
524    let by_accum_tick = Chunk::by_accum_tick(&chunks);
525    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
526    assert_eq!(to_accum_tick(100, 1, &by_accum_tick).unwrap(), 100);
527    assert_eq!(to_accum_tick(100, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
528  }
529
530  // 0    100
531  //   A  |
532  #[test]
533  fn single_bar() {
534    let bar = Bar::new(100, None, None, crate::repeat_set!());
535    let bars = [bar];
536    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
537    let chunks = region.to_chunks();
538    assert_eq!(chunks.len(), 1);
539    assert_eq!(chunks[0], Chunk::new(0, u32::MAX));
540
541    let by_accum_tick = Chunk::by_accum_tick(&chunks);
542    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
543    assert_eq!(to_accum_tick(100, 1, &by_accum_tick).unwrap(), 100);
544    assert_eq!(to_accum_tick(100, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
545  }
546
547  // 0    100
548  //   A  :|  B
549  //
550  // 0    100   200
551  //   A  |  A  |  B
552  #[test]
553  fn default_start_repeat() {
554    let bars = [
555      Bar::new(100, None, None, repeat_set!(Repeat::End))
556    ];
557    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
558    let chunks = region.to_chunks();
559    assert_eq!(chunks.len(), 3);
560    assert_eq!(chunks[0], Chunk::new(0, 100));
561    assert_eq!(chunks[1], Chunk::new(0, 100));
562    assert_eq!(chunks[2], Chunk::new(100, u32::MAX));
563
564    let chunks = Chunk::optimize(&chunks);
565    assert_eq!(chunks.len(), 2);
566    assert_eq!(chunks[0], Chunk::new(0, 100));
567    assert_eq!(chunks[1], Chunk::new(0, u32::MAX));
568
569    let by_accum_tick = Chunk::by_accum_tick(&chunks);
570    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
571    assert_eq!(to_accum_tick(50, 1, &by_accum_tick).unwrap(), 50);
572    assert_eq!(to_accum_tick(0, 2, &by_accum_tick).unwrap(), 100);
573    assert_eq!(to_accum_tick(50, 2, &by_accum_tick).unwrap(), 150);
574    assert_eq!(to_accum_tick(100, 1, &by_accum_tick).unwrap(), 200);
575    assert_eq!(to_accum_tick(150, 1, &by_accum_tick).unwrap(), 250);
576    assert_eq!(to_accum_tick(100, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
577  }
578
579  // 0    100   200
580  //   A  :|  B  :|
581  //
582  // Repeat end at 200 is invalid.
583  #[test]
584  fn invalid_repeat_end() {
585    let bars = [
586      Bar::new(100, None, None, repeat_set!(Repeat::End)),
587      Bar::new(200, None, None, repeat_set!(Repeat::End)),
588    ];
589
590    let e =  render_region(Rhythm::new(4, 4), bars.iter()).unwrap_err();
591    let err: &RenderRegionError = e.current_context();
592    assert_eq!(*err, RenderRegionError::OrphanRepeatEnd { tick: 200 });
593  }
594
595  // 0    100     200
596  //   A  |:  B  :|  C
597  //
598  // 0    100   200   300
599  //   A  |  B  |  B  |  C
600  #[test]
601  fn single_repeat() {
602    let bars = [
603      Bar::new(100, None, None, repeat_set!(Repeat::Start)),
604      Bar::new(200, None, None, repeat_set!(Repeat::End)),
605    ];
606
607    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
608    let chunks = region.to_chunks();
609    assert_eq!(chunks.len(), 4);
610    assert_eq!(chunks[0], Chunk::new(0, 100));
611    assert_eq!(chunks[1], Chunk::new(100, 200));
612    assert_eq!(chunks[2], Chunk::new(100, 200));
613    assert_eq!(chunks[3], Chunk::new(200, u32::MAX));
614
615    let chunks = Chunk::optimize(&chunks);
616    assert_eq!(chunks.len(), 2);
617    assert_eq!(chunks[0], Chunk::new(0, 200));
618    assert_eq!(chunks[1], Chunk::new(100, u32::MAX));
619
620    let by_accum_tick = Chunk::by_accum_tick(&chunks);
621    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
622    assert_eq!(to_accum_tick(0, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
623    assert_eq!(to_accum_tick(50, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
624    assert_eq!(to_accum_tick(100, 1, &by_accum_tick).unwrap(), 100);
625    assert_eq!(to_accum_tick(150, 1, &by_accum_tick).unwrap(), 150);
626    assert_eq!(to_accum_tick(100, 2, &by_accum_tick).unwrap(), 200);
627    assert_eq!(to_accum_tick(150, 2, &by_accum_tick).unwrap(), 250);
628    assert_eq!(to_accum_tick(200, 1, &by_accum_tick).unwrap(), 300);
629    assert_eq!(to_accum_tick(250, 1, &by_accum_tick).unwrap(), 350);
630    assert_eq!(to_accum_tick(200, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
631    assert_eq!(to_accum_tick(250, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
632  }
633
634  // 0    50          200
635  //   A  |:    B    :|  C
636  //
637  // 0    50          200         350
638  //   A  |     B     |     B     |  C
639  #[test]
640  fn single_repeat2() {
641    let bars = [
642      Bar::new(50, None, None, repeat_set!(Repeat::Start)),
643      Bar::new(200, None, None, repeat_set!(Repeat::End)),
644    ];
645
646    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
647    let chunks = region.to_chunks();
648    assert_eq!(chunks.len(), 4);
649    assert_eq!(chunks[0], Chunk::new(0, 50));
650    assert_eq!(chunks[1], Chunk::new(50, 200));
651    assert_eq!(chunks[2], Chunk::new(50, 200));
652    assert_eq!(chunks[3], Chunk::new(200, u32::MAX));
653
654    let chunks = Chunk::optimize(&chunks);
655    assert_eq!(chunks.len(), 2);
656    assert_eq!(chunks[0], Chunk::new(0, 200));
657    assert_eq!(chunks[1], Chunk::new(50, u32::MAX));
658
659    let by_accum_tick = Chunk::by_accum_tick(&chunks);
660    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
661    assert_eq!(to_accum_tick(50, 1, &by_accum_tick).unwrap(), 50);
662    assert_eq!(to_accum_tick(50, 2, &by_accum_tick).unwrap(), 200);
663    assert_eq!(to_accum_tick(199, 2, &by_accum_tick).unwrap(), 349);
664    assert_eq!(to_accum_tick(200, 1, &by_accum_tick).unwrap(), 350);
665    assert_eq!(to_accum_tick(200, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
666  }
667
668  // 0     50       100       150
669  //   A   |[1]  B   |[2]  C   |    D
670  //
671  // 0     50       100      150    200
672  //   A   |     B   |   A    |   C  |  D
673  #[test]
674  fn simple_variation() {
675    let bars = [
676      Bar::new(50, None, None, repeat_set!(Repeat::Var1)),
677      Bar::new(100, None, None, repeat_set!(Repeat::Var2)),
678      Bar::new(150, None, None, repeat_set!()),
679    ];
680
681    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
682    let chunks = region.to_chunks();
683    assert_eq!(chunks.len(), 5);
684    assert_eq!(chunks[0], Chunk::new(0, 50));
685    assert_eq!(chunks[1], Chunk::new(50, 100));
686    assert_eq!(chunks[2], Chunk::new(0, 50));
687    assert_eq!(chunks[3], Chunk::new(100, 150));
688    assert_eq!(chunks[4], Chunk::new(150, u32::MAX));
689
690    let chunks = Chunk::optimize(&chunks);
691    assert_eq!(chunks.len(), 3);
692    assert_eq!(chunks[0], Chunk::new(0, 100));
693    assert_eq!(chunks[1], Chunk::new(0, 50));
694    assert_eq!(chunks[2], Chunk::new(100, u32::MAX));
695
696    let by_accum_tick = Chunk::by_accum_tick(&chunks);
697    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
698    assert_eq!(to_accum_tick(0, 2, &by_accum_tick).unwrap(), 100);
699    assert_eq!(to_accum_tick(20, 2, &by_accum_tick).unwrap(), 120);
700    assert_eq!(to_accum_tick(100, 1, &by_accum_tick).unwrap(), 150);
701    assert_eq!(to_accum_tick(100, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
702  }
703
704  // 0    100        200        350       500        650
705  //   A   |[1]  B   |[1]   C   |[2]  D   |[2]   E   |    F
706  //
707  // 0    100        200        350    450      600     750
708  //   A   |     B   |      C   |   A  |    D   |   E   |   F
709  #[test]
710  fn simple_variation2() {
711    let bars = [
712      Bar::new(100, None, None, repeat_set!(Repeat::Var1)),
713      Bar::new(200, None, None, repeat_set!(Repeat::Var1)),
714      Bar::new(350, None, None, repeat_set!(Repeat::Var2)),
715      Bar::new(500, None, None, repeat_set!(Repeat::Var2)),
716      Bar::new(650, None, None, repeat_set!()),
717    ];
718
719    let (region, _warnings) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
720    let chunks = region.to_chunks();
721    assert_eq!(chunks.len(), 5);
722    assert_eq!(chunks[0], Chunk::new(0, 100));
723    assert_eq!(chunks[1], Chunk::new(100, 350));
724    assert_eq!(chunks[2], Chunk::new(0, 100));
725    assert_eq!(chunks[3], Chunk::new(350, 650));
726    assert_eq!(chunks[4], Chunk::new(650, u32::MAX));
727
728    let chunks = Chunk::optimize(&chunks);
729    assert_eq!(chunks.len(), 3);
730    assert_eq!(chunks[0], Chunk::new(0, 350));
731    assert_eq!(chunks[1], Chunk::new(0, 100));
732    assert_eq!(chunks[2], Chunk::new(350, u32::MAX));
733
734    let by_accum_tick = Chunk::by_accum_tick(&chunks);
735    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
736    assert_eq!(to_accum_tick(200, 1, &by_accum_tick).unwrap(), 200);
737    assert_eq!(to_accum_tick(0, 2, &by_accum_tick).unwrap(), 350);
738    assert_eq!(to_accum_tick(350, 1, &by_accum_tick).unwrap(), 450);
739    assert_eq!(to_accum_tick(650, 1, &by_accum_tick).unwrap(), 750);
740    assert_eq!(to_accum_tick(650, 2, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(2), max_iter: 1 }));
741    assert_eq!(to_accum_tick(0, 3, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(3), max_iter: 2 }));
742  }
743
744  // Non auftakt.
745  // 0    480         960        1440
746  //   A   |Fine  B   |     C    |DC
747  //
748  // 0    480         960        1440   1920
749  //   A   |     B    |      C   |   A  |
750  #[test]
751  fn simple_dc() {
752    let bars = [
753      Bar::new(480, None, None, repeat_set!(Repeat::Fine)),
754      Bar::new(960, None, None, repeat_set!()),
755      Bar::new(1440, None, None, repeat_set!(Repeat::Dc)),
756    ];
757
758    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
759    let chunks = region.to_chunks();
760    assert_eq!(chunks.len(), 2);
761    assert_eq!(chunks[0], Chunk::new(0, 1440));
762    assert_eq!(chunks[1], Chunk::new(0, 480));
763
764    let chunks = Chunk::optimize(&chunks);
765    assert_eq!(chunks.len(), 2);
766    assert_eq!(chunks[0], Chunk::new(0, 1440));
767    assert_eq!(chunks[1], Chunk::new(0, 480));
768
769    let by_accum_tick = Chunk::by_accum_tick(&chunks);
770    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
771    assert_eq!(to_accum_tick(0, 2, &by_accum_tick).unwrap(), 1440);
772    assert_eq!(to_accum_tick(0, 3, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(3), max_iter: 2 }));
773  }
774
775  // Auftakt.
776  // 0    480         580       730        880       1030      1180    1280
777  //   A   |[1]  B   |[1]   C   |[2]   D   |[2]   E   |Fine F   |   G   |DC
778  //
779  //   A   |     B    |     C   |   A  |   D   |   E   |   F   |   G   |   D   |   E   |
780  #[test]
781  fn simple_var_dc() {
782    let bars = [
783      Bar::new(480, None, None, repeat_set!(Repeat::Var1)),
784      Bar::new(580, None, None, repeat_set!(Repeat::Var1)),
785      Bar::new(730, None, None, repeat_set!(Repeat::Var2)),
786      Bar::new(880, None, None, repeat_set!(Repeat::Var2)),
787      Bar::new(1030, None, None, repeat_set!(Repeat::Fine)),
788      Bar::new(1180, None, None, repeat_set!()),
789      Bar::new(1280, None, None, repeat_set!(Repeat::Dc)),
790    ];
791
792    let (region, _) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
793    let chunks = region.to_chunks();
794    assert_eq!(chunks.len(), 6);
795    assert_eq!(chunks[0], Chunk::new(0, 480));
796    assert_eq!(chunks[1], Chunk::new(480, 730));
797    assert_eq!(chunks[2], Chunk::new(0, 480));
798    assert_eq!(chunks[3], Chunk::new(730, 1030));
799    assert_eq!(chunks[4], Chunk::new(1030, 1280));
800    assert_eq!(chunks[5], Chunk::new(730, 1030));
801
802    let chunks = Chunk::optimize(&chunks);
803    assert_eq!(chunks.len(), 4);
804    assert_eq!(chunks[0], Chunk::new(0, 730));
805    assert_eq!(chunks[1], Chunk::new(0, 480));
806    assert_eq!(chunks[2], Chunk::new(730, 1280));
807    assert_eq!(chunks[3], Chunk::new(730, 1030));
808
809    let by_accum_tick = Chunk::by_accum_tick(&chunks);
810    assert_eq!(to_accum_tick(0, 1, &by_accum_tick).unwrap(), 0);
811    assert_eq!(to_accum_tick(480, 1, &by_accum_tick).unwrap(), 480);
812    assert_eq!(to_accum_tick(400, 2, &by_accum_tick).unwrap(), 730 + 400);
813    assert_eq!(to_accum_tick(800, 1, &by_accum_tick).unwrap(), 730 + 480 + (800 - 730));
814    assert_eq!(to_accum_tick(1180, 1, &by_accum_tick).unwrap(), 730 + 480 + (1180 - 730));
815    assert_eq!(to_accum_tick(730, 2, &by_accum_tick).unwrap(), 730 + 480 + (1280 - 730));
816    assert_eq!(to_accum_tick(730, 3, &by_accum_tick), Err(ToAccumTickError::CannotFind { specified_iter: PlayIter::new(3), max_iter: 2 }));
817  }
818
819  // 0 480    530        600   1080 
820  // A |: B :|:[Fine] C :|: D :|[D.C.]
821  //
822  // A B B C C D D A B
823  #[test]
824  fn dc_and_repeat_end() {
825    let bars = [
826      Bar::new(480, None, None, repeat_set!(Repeat::Start)),
827      Bar::new(530, None, None, repeat_set!(Repeat::Start, Repeat::End, Repeat::Fine)),
828      Bar::new(600, None, None, repeat_set!(Repeat::Start, Repeat::End)),
829      Bar::new(1080, None, None, repeat_set!(Repeat::Dc, Repeat::End)),
830    ];
831
832    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
833    let chunks = region.to_chunks();
834
835    assert_eq!(chunks.len(), 9);
836    assert_eq!(chunks[0], Chunk::new(0, 480));
837    assert_eq!(chunks[1], Chunk::new(480, 530));
838    assert_eq!(chunks[2], Chunk::new(480, 530));
839    assert_eq!(chunks[3], Chunk::new(530, 600));
840    assert_eq!(chunks[4], Chunk::new(530, 600));
841    assert_eq!(chunks[5], Chunk::new(600, 1080));
842    assert_eq!(chunks[6], Chunk::new(600, 1080));
843    assert_eq!(chunks[7], Chunk::new(0, 480));
844    assert_eq!(chunks[8], Chunk::new(480, 530));
845
846    let chunks = Chunk::optimize(&chunks);
847    assert_eq!(chunks.len(), 5);
848    assert_eq!(chunks[0], Chunk::new(0, 530));
849    assert_eq!(chunks[1], Chunk::new(480, 600));
850    assert_eq!(chunks[2], Chunk::new(530, 1080));
851    assert_eq!(chunks[3], Chunk::new(600, 1080));
852    assert_eq!(chunks[4], Chunk::new(0, 530));
853  }
854
855  // 0 50   100 150  200  250  300 350  400 450
856  // A |: B | C |1 D |2 E |: F | G |1 H |2 I| J
857  //
858  // 0 50  100 150 200 250 300 350 400 450 500 550 600 650
859  // A | B | C | D | B | C | E | F | G | H | F | G | I | J
860  #[test]
861  fn two_vars() {
862    let bars = [
863      Bar::new(50, None, None, repeat_set!(Repeat::Start)),
864      Bar::new(100, None, None, repeat_set!()),
865      Bar::new(150, None, None, repeat_set!(Repeat::Var1)),
866      Bar::new(200, None, None, repeat_set!(Repeat::Var2)),
867      Bar::new(250, None, None, repeat_set!(Repeat::Start)),
868      Bar::new(300, None, None, repeat_set!()),
869      Bar::new(350, None, None, repeat_set!(Repeat::Var1)),
870      Bar::new(400, None, None, repeat_set!(Repeat::Var2)),
871      Bar::new(450, None, None, repeat_set!()),
872    ];
873
874    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
875    let chunks = region.to_chunks();
876
877    assert_eq!(chunks.len(), 10);
878    assert_eq!(chunks[0], Chunk::new(0, 50));
879    assert_eq!(chunks[1], Chunk::new(50, 150));
880    assert_eq!(chunks[2], Chunk::new(150, 200));
881    assert_eq!(chunks[3], Chunk::new(50, 150));
882    assert_eq!(chunks[4], Chunk::new(200, 250));
883    assert_eq!(chunks[5], Chunk::new(250, 350));
884    assert_eq!(chunks[6], Chunk::new(350, 400));
885    assert_eq!(chunks[7], Chunk::new(250, 350));
886    assert_eq!(chunks[8], Chunk::new(400, 450));
887    assert_eq!(chunks[9], Chunk::new(450, u32::MAX));
888
889    let chunks = Chunk::optimize(&chunks);
890    assert_eq!(chunks.len(), 5);
891    assert_eq!(chunks[0], Chunk::new(0, 200));
892    assert_eq!(chunks[1], Chunk::new(50, 150));
893    assert_eq!(chunks[2], Chunk::new(200, 400));
894    assert_eq!(chunks[3], Chunk::new(250, 350));
895    assert_eq!(chunks[4], Chunk::new(400, u32::MAX));
896  }
897
898  // 0 50   100 150  200  250  300  350  400 450 500 550 600
899  // A |: B | C |1 D |2 E |  F |: G | H  |1 I|1 J |2 K| L |
900  //
901  // 0 50  100 150 200 250 300 350 400 450 500 550 600 650 700 750
902  // A | B | C | D | B | C | E | F | G | H | I | J | G | H | K | L
903  #[test]
904  fn two_vars_with_end_bar() {
905    let bars = [
906      Bar::new(50, None, None, repeat_set!(Repeat::Start)),
907      Bar::new(100, None, None, repeat_set!()),
908      Bar::new(150, None, None, repeat_set!(Repeat::Var1)),
909      Bar::new(200, None, None, repeat_set!(Repeat::Var2)),
910      Bar::new(250, None, None, repeat_set!()),
911      Bar::new(300, None, None, repeat_set!(Repeat::Start)),
912      Bar::new(350, None, None, repeat_set!()),
913      Bar::new(400, None, None, repeat_set!(Repeat::Var1)),
914      Bar::new(450, None, None, repeat_set!(Repeat::Var1)),
915      Bar::new(500, None, None, repeat_set!(Repeat::Var2)),
916      Bar::new(550, None, None, repeat_set!()),
917      Bar::new(600, None, None, repeat_set!()),
918    ];
919
920    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
921    let chunks = region.to_chunks();
922
923    assert_eq!(chunks.len(), 11);
924    assert_eq!(chunks[0], Chunk::new(0, 50));
925    assert_eq!(chunks[1], Chunk::new(50, 150));
926    assert_eq!(chunks[2], Chunk::new(150, 200));
927    assert_eq!(chunks[3], Chunk::new(50, 150));
928    assert_eq!(chunks[4], Chunk::new(200, 250));
929    assert_eq!(chunks[5], Chunk::new(250, 300));
930    assert_eq!(chunks[6], Chunk::new(300, 400));
931    assert_eq!(chunks[7], Chunk::new(400, 500));
932    assert_eq!(chunks[8], Chunk::new(300, 400));
933    assert_eq!(chunks[9], Chunk::new(500, 550));
934    assert_eq!(chunks[10], Chunk::new(550, u32::MAX));
935
936    let chunks = Chunk::optimize(&chunks);
937    assert_eq!(chunks.len(), 5);
938    assert_eq!(chunks[0], Chunk::new(0, 200));
939    assert_eq!(chunks[1], Chunk::new(50, 150));
940    assert_eq!(chunks[2], Chunk::new(200, 500));
941    assert_eq!(chunks[3], Chunk::new(300, 400));
942    assert_eq!(chunks[4], Chunk::new(500, u32::MAX));
943
944  }
945
946  // 0 240  320 370  420  470  520  570  620 670     720 770 820  870 920 970
947  // A |: B | C |1 D |2 E |  F |: G | H  |1 I|2 J Fine| K |: L| M | N :| O |DC
948  //
949  // A | B | C | D | B | C | E | F | G | H | I | G | H | J | K | L | M | N | L | M 
950  // |  N | O  | B  | C  | E  | F  | G  | H  | J  |
951  #[test]
952  fn repeat_and_dc() {
953    let bars = [
954      Bar::new(240, None, None, repeat_set!(Repeat::Start)),
955      Bar::new(320, None, None, repeat_set!()),
956      Bar::new(370, None, None, repeat_set!(Repeat::Var1)),
957      Bar::new(420, None, None, repeat_set!(Repeat::Var2)),
958      Bar::new(470, None, None, repeat_set!()),
959      Bar::new(520, None, None, repeat_set!(Repeat::Start)),
960      Bar::new(570, None, None, repeat_set!()),
961      Bar::new(620, None, None, repeat_set!(Repeat::Var1)),
962      Bar::new(670, None, None, repeat_set!(Repeat::Var2)),
963      Bar::new(720, None, None, repeat_set!(Repeat::Fine)),
964      Bar::new(770, None, None, repeat_set!(Repeat::Start)),
965      Bar::new(820, None, None, repeat_set!()),
966      Bar::new(870, None, None, repeat_set!()),
967      Bar::new(920, None, None, repeat_set!(Repeat::End)),
968      Bar::new(970, None, None, repeat_set!(Repeat::Dc)),
969    ];
970
971    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
972    let chunks = region.to_chunks();
973
974    assert_eq!(chunks.len(), 19);
975    let mut z = chunks.iter();
976    assert_eq!(*z.next().unwrap(), Chunk::new(0, 240));
977    assert_eq!(*z.next().unwrap(), Chunk::new(240, 370));
978    assert_eq!(*z.next().unwrap(), Chunk::new(370, 420));
979    assert_eq!(*z.next().unwrap(), Chunk::new(240, 370));
980    assert_eq!(*z.next().unwrap(), Chunk::new(420, 470));
981
982    assert_eq!(*z.next().unwrap(), Chunk::new(470, 520));
983    assert_eq!(*z.next().unwrap(), Chunk::new(520, 620));
984    assert_eq!(*z.next().unwrap(), Chunk::new(620, 670));
985    assert_eq!(*z.next().unwrap(), Chunk::new(520, 620));
986    assert_eq!(*z.next().unwrap(), Chunk::new(670, 720));
987
988    assert_eq!(*z.next().unwrap(), Chunk::new(720, 770));
989    assert_eq!(*z.next().unwrap(), Chunk::new(770, 920));
990    assert_eq!(*z.next().unwrap(), Chunk::new(770, 920));
991    assert_eq!(*z.next().unwrap(), Chunk::new(920, 970));
992
993    assert_eq!(*z.next().unwrap(), Chunk::new(240, 370));
994    assert_eq!(*z.next().unwrap(), Chunk::new(420, 470));
995    assert_eq!(*z.next().unwrap(), Chunk::new(470, 520));
996    assert_eq!(*z.next().unwrap(), Chunk::new(520, 620));
997    assert_eq!(*z.next().unwrap(), Chunk::new(670, 720));
998    assert_eq!(z.next(), None);
999
1000    let chunks = Chunk::optimize(&chunks);
1001    assert_eq!(chunks.len(), 9);
1002    let mut z = chunks.iter();
1003    assert_eq!(*z.next().unwrap(), Chunk::new(0, 420));
1004    assert_eq!(*z.next().unwrap(), Chunk::new(240, 370));
1005    assert_eq!(*z.next().unwrap(), Chunk::new(420, 670));
1006    assert_eq!(*z.next().unwrap(), Chunk::new(520, 620));
1007    assert_eq!(*z.next().unwrap(), Chunk::new(670, 920));
1008    assert_eq!(*z.next().unwrap(), Chunk::new(770, 970));
1009    assert_eq!(*z.next().unwrap(), Chunk::new(240, 370));
1010    assert_eq!(*z.next().unwrap(), Chunk::new(420, 620));
1011    assert_eq!(*z.next().unwrap(), Chunk::new(670, 720));
1012    assert_eq!(z.next(), None);
1013  }
1014
1015  // 0    50          200      300
1016  //   A  |     B    :|:  C    :|
1017  //
1018  // 0    50          200  250         400    500   600
1019  //   A  |     B     |  A  |     B     |  C   |  C  |
1020  #[test]
1021  fn consecutive_repeat() {
1022    let bars = [
1023      Bar::new(50, None, None, repeat_set!()),
1024      Bar::new(200, None, None, repeat_set!(Repeat::Start, Repeat::End)),
1025      Bar::new(300, None, None, repeat_set!(Repeat::End)),
1026    ];
1027
1028    let (region, _warnings) = render_region(Rhythm::new(2, 4), bars.iter()).unwrap();
1029    let chunks = region.to_chunks();
1030    assert_eq!(chunks.len(), 5);
1031
1032    let mut z = chunks.iter();
1033    assert_eq!(*z.next().unwrap(), Chunk::new(0, 200));
1034    assert_eq!(*z.next().unwrap(), Chunk::new(0, 200));
1035    assert_eq!(*z.next().unwrap(), Chunk::new(200, 300));
1036    assert_eq!(*z.next().unwrap(), Chunk::new(200, 300));
1037    assert_eq!(*z.next().unwrap(), Chunk::new(300, u32::MAX));
1038    assert_eq!(z.next(), None);
1039
1040    let chunks = Chunk::optimize(&chunks);
1041    let mut z = chunks.iter();
1042    assert_eq!(*z.next().unwrap(), Chunk::new(0, 200));
1043    assert_eq!(*z.next().unwrap(), Chunk::new(0, 300));
1044    assert_eq!(*z.next().unwrap(), Chunk::new(200, u32::MAX));
1045    assert_eq!(z.next(), None);
1046  }
1047
1048  // 0   120          270          370
1049  //   A  |     B    :|:Fine  C    :| D.C
1050  // Assumed auftakt.
1051  //   A  |     B     |  A  |     B     |  C   |  C  |   B  |
1052  #[test]
1053  fn fine_and_repeat() {
1054    let bars = [
1055      Bar::new(120, None, None, repeat_set!()),
1056      Bar::new(270, None, None, repeat_set!(Repeat::Start, Repeat::End, Repeat::Fine)),
1057      Bar::new(370, None, None, repeat_set!(Repeat::Dc, Repeat::End)),
1058    ];
1059
1060    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1061    let chunks = region.to_chunks();
1062    assert_eq!(chunks.len(), 5);
1063
1064    let mut z = chunks.iter();
1065    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1066    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1067    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1068    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1069    assert_eq!(*z.next().unwrap(), Chunk::new(120, 270));
1070    assert_eq!(z.next(), None);
1071
1072    let chunks = Chunk::optimize(&chunks);
1073    let mut z = chunks.iter();
1074    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1075    assert_eq!(*z.next().unwrap(), Chunk::new(0, 370));
1076    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1077    assert_eq!(*z.next().unwrap(), Chunk::new(120, 270));
1078    assert_eq!(z.next(), None);
1079  }
1080
1081  // 0 120   170       270   370
1082  // A |: B :|:Fine C :|: D :|D.C.
1083  // 
1084  // Assumed auftakt.
1085  // A  B  B   C   C   D   D   B 
1086  #[test]
1087  fn dc_and_repeat() {
1088    let bars = [
1089      Bar::new(120, None, None, repeat_set!(Repeat::Start)),
1090      Bar::new(170, None, None, repeat_set!(Repeat::Start, Repeat::End, Repeat::Fine)),
1091      Bar::new(270, None, None, repeat_set!(Repeat::Start, Repeat::End)),
1092      Bar::new(370, None, None, repeat_set!(Repeat::Dc, Repeat::End)),
1093    ];
1094
1095    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1096    let chunks = region.to_chunks();
1097    assert_eq!(chunks.len(), 8);
1098
1099    let mut z = chunks.iter();
1100    assert_eq!(*z.next().unwrap(), Chunk::new(0, 120));
1101    assert_eq!(*z.next().unwrap(), Chunk::new(120, 170));
1102    assert_eq!(*z.next().unwrap(), Chunk::new(120, 170));
1103    assert_eq!(*z.next().unwrap(), Chunk::new(170, 270));
1104    assert_eq!(*z.next().unwrap(), Chunk::new(170, 270));
1105    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1106    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1107    assert_eq!(*z.next().unwrap(), Chunk::new(120, 170));
1108    assert_eq!(z.next(), None);
1109
1110    let chunks = Chunk::optimize(&chunks);
1111    let mut z = chunks.iter();
1112    assert_eq!(*z.next().unwrap(), Chunk::new(0, 170));
1113    assert_eq!(*z.next().unwrap(), Chunk::new(120, 270));
1114    assert_eq!(*z.next().unwrap(), Chunk::new(170, 370));
1115    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1116    assert_eq!(*z.next().unwrap(), Chunk::new(120, 170));
1117    assert_eq!(z.next(), None);
1118  }
1119
1120  // 0 120 170  270  370    470
1121  // A | B |: C | D :|D.C. E |
1122  // Assumed auftakt.
1123  // A B C D C D B C D E
1124  #[test]
1125  fn dc_without_fine() {
1126    let bars = [
1127      Bar::new(120, None, None, repeat_set!()),
1128      Bar::new(170, None, None, repeat_set!(Repeat::Start)),
1129      Bar::new(270, None, None, repeat_set!()),
1130      Bar::new(370, None, None, repeat_set!(Repeat::Dc, Repeat::End)),
1131      Bar::new(470, None, None, repeat_set!()),
1132    ];
1133
1134    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1135    let chunks = region.to_chunks();
1136    assert_eq!(chunks.len(), 6);
1137
1138    let mut z = chunks.iter();
1139    assert_eq!(*z.next().unwrap(), Chunk::new(0, 170));
1140    assert_eq!(*z.next().unwrap(), Chunk::new(170, 370));
1141    assert_eq!(*z.next().unwrap(), Chunk::new(170, 370));
1142    assert_eq!(*z.next().unwrap(), Chunk::new(120, 170));
1143    assert_eq!(*z.next().unwrap(), Chunk::new(170, 370));
1144    assert_eq!(*z.next().unwrap(), Chunk::new(370, u32::MAX));
1145    assert_eq!(z.next(), None);
1146
1147    let chunks = Chunk::optimize(&chunks);
1148    let mut z = chunks.iter();
1149    assert_eq!(*z.next().unwrap(), Chunk::new(0, 370));
1150    assert_eq!(*z.next().unwrap(), Chunk::new(170, 370));
1151    assert_eq!(*z.next().unwrap(), Chunk::new(120, u32::MAX));
1152    assert_eq!(z.next(), None);
1153  }
1154
1155  // 0   120   200         270          370
1156  //   A  |  B  |Segno C   :|:Fine  D    :| D.S
1157  //
1158  //   A  |     B     |  C  |     A     |  B   |  C  |   D  |  D  | A | B |
1159  #[test]
1160  fn simple_ds() {
1161    let bars = [
1162      Bar::new(120, None, None, repeat_set!()),
1163      Bar::new(200, None, None, repeat_set!(Repeat::Segno)),
1164      Bar::new(270, None, None, repeat_set!(Repeat::Start, Repeat::End, Repeat::Fine)),
1165      Bar::new(370, None, None, repeat_set!(Repeat::Ds, Repeat::End)),
1166    ];
1167
1168    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1169    let chunks = region.to_chunks();
1170    assert_eq!(chunks.len(), 5);
1171
1172    let mut z = chunks.iter();
1173    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1174    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1175    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1176    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1177    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1178    assert_eq!(z.next(), None);
1179
1180    let chunks = Chunk::optimize(&chunks);
1181    let mut z = chunks.iter();
1182    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1183    assert_eq!(*z.next().unwrap(), Chunk::new(0, 370));
1184    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1185    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1186    assert_eq!(z.next(), None);
1187  }
1188
1189  // 0   120   200         270          370    470     570
1190  //   A  |  B  |Segno C   :|:Fine  D    |[1] E |[2] F  |D.S
1191  //
1192  //   A  |  B  |  C  |  A  |  B  |  C  |   D  |  E  | D | F | C
1193  #[test]
1194  fn var_and_ds() {
1195    let bars = [
1196      Bar::new(120, None, None, repeat_set!()),
1197      Bar::new(200, None, None, repeat_set!(Repeat::Segno)),
1198      Bar::new(270, None, None, repeat_set!(Repeat::Start, Repeat::End, Repeat::Fine)),
1199      Bar::new(370, None, None, repeat_set!(Repeat::Var1)),
1200      Bar::new(470, None, None, repeat_set!(Repeat::Var2)),
1201      Bar::new(570, None, None, repeat_set!(Repeat::Ds)),
1202    ];
1203
1204    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1205    let chunks = region.to_chunks();
1206    assert_eq!(chunks.len(), 7);
1207
1208    let mut z = chunks.iter();
1209    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1210    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1211    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1212    assert_eq!(*z.next().unwrap(), Chunk::new(370, 470));
1213    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1214    assert_eq!(*z.next().unwrap(), Chunk::new(470, 570));
1215    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1216    assert_eq!(z.next(), None);
1217
1218    let chunks = Chunk::optimize(&chunks);
1219    let mut z = chunks.iter();
1220    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1221    assert_eq!(*z.next().unwrap(), Chunk::new(0, 470));
1222    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1223    assert_eq!(*z.next().unwrap(), Chunk::new(470, 570));
1224    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1225    assert_eq!(z.next(), None);
1226  }    
1227
1228  // 0   120   200         270  370     470  570     670
1229  //   A  |  B  |Segno C   :| D |Coda E | F |Coda G  | D.S
1230  //
1231  //   A  |  B  |  C  |  A  |  B  |  C  |  D | E | F | G | C | D | G
1232  #[test]
1233  fn ds_and_coda() {
1234    let bars = [
1235      Bar::new(120, None, None, repeat_set!()),
1236      Bar::new(200, None, None, repeat_set!(Repeat::Segno)),
1237      Bar::new(270, None, None, repeat_set!(Repeat::End)),
1238      Bar::new(370, None, None, repeat_set!(Repeat::Coda)),
1239      Bar::new(470, None, None, repeat_set!()),
1240      Bar::new(570, None, None, repeat_set!(Repeat::Coda)),
1241      Bar::new(670, None, None, repeat_set!(Repeat::Ds)),
1242    ];
1243
1244    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1245    let chunks = region.to_chunks();
1246    assert_eq!(chunks.len(), 6);
1247
1248    let mut z = chunks.iter();
1249    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1250    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1251    assert_eq!(*z.next().unwrap(), Chunk::new(270, 670));
1252    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1253    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1254    assert_eq!(*z.next().unwrap(), Chunk::new(570, u32::MAX));
1255    assert_eq!(z.next(), None);
1256
1257    let chunks = Chunk::optimize(&chunks);
1258    let mut z = chunks.iter();
1259    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1260    assert_eq!(*z.next().unwrap(), Chunk::new(0, 670));
1261    assert_eq!(*z.next().unwrap(), Chunk::new(200, 370));
1262    assert_eq!(*z.next().unwrap(), Chunk::new(570, u32::MAX));
1263    assert_eq!(z.next(), None);
1264  }    
1265
1266  // 0   120   200         270  370     470  570     670   770
1267  //   A  |  B  |Segno C   :| D |Coda E | F |Coda G  |Fine |D.S
1268  //
1269  //   A  |  B  |  C  |  A  |  B  |  C  |  D | E | G 
1270  #[test]
1271  fn ds_and_coda_fine() {
1272    let bars = [
1273      Bar::new(120, None, None, repeat_set!()),
1274      Bar::new(200, None, None, repeat_set!(Repeat::Segno)),
1275      Bar::new(270, None, None, repeat_set!(Repeat::End)),
1276      Bar::new(370, None, None, repeat_set!(Repeat::Coda)),
1277      Bar::new(470, None, None, repeat_set!()),
1278      Bar::new(570, None, None, repeat_set!(Repeat::Coda)),
1279      Bar::new(670, None, None, repeat_set!(Repeat::Fine)),
1280      Bar::new(770, None, None, repeat_set!(Repeat::Ds)),
1281    ];
1282
1283    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1284    let chunks = region.to_chunks();
1285    assert_eq!(chunks.len(), 6);
1286
1287    let mut z = chunks.iter();
1288    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1289    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1290    assert_eq!(*z.next().unwrap(), Chunk::new(270, 770));
1291    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1292    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1293    assert_eq!(*z.next().unwrap(), Chunk::new(570, 670));
1294    assert_eq!(z.next(), None);
1295
1296    let chunks = Chunk::optimize(&chunks);
1297    let mut z = chunks.iter();
1298    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1299    assert_eq!(*z.next().unwrap(), Chunk::new(0, 770));
1300    assert_eq!(*z.next().unwrap(), Chunk::new(200, 370));
1301    assert_eq!(*z.next().unwrap(), Chunk::new(570, 670));
1302    assert_eq!(z.next(), None);
1303  }    
1304
1305  // 0   120   200         270  370     470 570  670
1306  //   A  |  B  |Segno C   :| D |Coda E | F |D.S |Coda H
1307  //
1308  //   A  |  B  |  C  |  A  |  B  |  C  |  D | E | F | C | D | H
1309  #[test]
1310  fn ds_and_coda_skip_ds() {
1311    let bars = [
1312      Bar::new(120, None, None, repeat_set!()),
1313      Bar::new(200, None, None, repeat_set!(Repeat::Segno)),
1314      Bar::new(270, None, None, repeat_set!(Repeat::End)),
1315      Bar::new(370, None, None, repeat_set!(Repeat::Coda)),
1316      Bar::new(470, None, None, repeat_set!()),
1317      Bar::new(570, None, None, repeat_set!(Repeat::Ds)),
1318      Bar::new(670, None, None, repeat_set!(Repeat::Coda)),
1319    ];
1320
1321    let (region, _warnings) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1322    let chunks = region.to_chunks();
1323    assert_eq!(chunks.len(), 6);
1324
1325    let mut z = chunks.iter();
1326    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1327    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1328    assert_eq!(*z.next().unwrap(), Chunk::new(270, 570));
1329    assert_eq!(*z.next().unwrap(), Chunk::new(200, 270));
1330    assert_eq!(*z.next().unwrap(), Chunk::new(270, 370));
1331    assert_eq!(*z.next().unwrap(), Chunk::new(670, u32::MAX));
1332    assert_eq!(z.next(), None);
1333
1334    let chunks = Chunk::optimize(&chunks);
1335    let mut z = chunks.iter();
1336    assert_eq!(*z.next().unwrap(), Chunk::new(0, 270));
1337    assert_eq!(*z.next().unwrap(), Chunk::new(0, 570));
1338    assert_eq!(*z.next().unwrap(), Chunk::new(200, 370));
1339    assert_eq!(*z.next().unwrap(), Chunk::new(670, u32::MAX));
1340    assert_eq!(z.next(), None);
1341  }    
1342
1343  #[test]  
1344  fn render_sequence_region_when_non_dcds() {
1345    let seq_region = SequenceRegion {
1346      tick_range: 100..200
1347    };
1348    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::NonDcDs);
1349    assert_eq!(chunks.len(), 1);
1350    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 200 });
1351  }
1352
1353  #[test]  
1354  fn render_sequence_region_when_dcds_iter0() {
1355    let seq_region = SequenceRegion {
1356      tick_range: 100..200
1357    };
1358    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 99 });
1359    assert_eq!(chunks.len(), 0);
1360
1361    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 100 });
1362    assert_eq!(chunks.len(), 0);
1363
1364    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 101 });
1365    assert_eq!(chunks.len(), 1);
1366    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 101 });
1367
1368    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 199 });
1369    assert_eq!(chunks.len(), 1);
1370    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 199 });
1371
1372    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 200 });
1373    assert_eq!(chunks.len(), 1);
1374    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 200 });
1375
1376    let chunks: Vec<Chunk> = seq_region.render_chunks(&RenderPhase::DcDsIter0 { dc_ds_tick: 201 });
1377    assert_eq!(chunks.len(), 1);
1378    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 200 });
1379  }
1380
1381  #[test]  
1382  fn render_sequence_region_when_dcds_iter1() -> Result<(), Report<RenderRegionError>> {
1383    let seq_region = SequenceRegion {
1384      tick_range: 100..200
1385    };
1386    let (global_repeat, _warn) = GlobalRepeatBuilder::new(Rhythm::new(4, 4))
1387      .adding_segno(99)?
1388      .adding_dc(400, 100)?
1389      .adding_first_bar_len(30)?
1390      .build()?;
1391      
1392    let gr: crate::global_repeat::GlobalRepeat = global_repeat.unwrap();
1393    let rp = RenderPhase::DcDsIter1 { global_repeat: gr };
1394    let chunks = seq_region.render_chunks(&rp);
1395
1396    assert_eq!(chunks.len(), 1);
1397    assert_eq!(chunks[0], Chunk { start_tick: 100, end_tick: 200 });
1398    Ok(())
1399  }
1400
1401  //   200      400
1402  // A | Fine B | D.C.
1403  // This is assumed auftakt.
1404  // A B
1405  #[test]
1406  fn dc_goes_to_fine() {
1407    let bars = [
1408      Bar::new(200, None, None, repeat_set!(Repeat::Fine)),
1409      Bar::new(400, None, None, repeat_set!(Repeat::Dc)),
1410    ];
1411
1412    let (region, _) = render_region(Rhythm::new(1, 4), bars.iter()).unwrap();
1413    let chunks = region.to_chunks();
1414    assert_eq!(chunks.len(), 1);
1415  }
1416
1417  // 0 240   1200      1920
1418  // A |  B  | Fine C  |D.C.
1419  // 
1420  // A  B  C  A  B
1421  #[test]
1422  fn dc_and_auftakt() {
1423    let bars = [
1424      Bar::new(240, None, None, repeat_set!()),
1425      Bar::new(1200, None, None, repeat_set!(Repeat::Fine)),
1426      Bar::new(1920, None, None, repeat_set!(Repeat::Dc)),
1427    ];
1428
1429    let (region, _) = render_region(Rhythm::new(4, 4), bars.iter()).unwrap();
1430    let chunks = region.to_chunks();
1431    assert_eq!(chunks.len(), 2);
1432
1433    let mut z = chunks.iter();
1434    assert_eq!(*z.next().unwrap(), Chunk::new(0, 1920));
1435    assert_eq!(*z.next().unwrap(), Chunk::new(0, 1200));
1436  }
1437}