sim_lib_music_serial/
cycle.rs1#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5pub enum ParameterTrackKind {
6 Pitch,
8 Rhythm,
10 Dynamics,
12 Timbre,
14 Orchestration,
16 Harmonic,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct CyclicOrder<T> {
23 pub track: ParameterTrackKind,
25 pub values: Vec<T>,
27}
28
29#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct CyclicProjectionSpec {
32 pub order: Vec<usize>,
34 pub rotation: usize,
36}
37
38#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct CyclicProjection<T> {
41 pub track: ParameterTrackKind,
43 pub order: Vec<usize>,
45 pub rotation: usize,
47 pub values: Vec<T>,
49}
50
51pub fn project_cyclic_order<T: Clone>(
53 cycle: &CyclicOrder<T>,
54 spec: &CyclicProjectionSpec,
55) -> Result<CyclicProjection<T>, String> {
56 if cycle.values.is_empty() {
57 return Err("cyclic source cannot be empty".to_owned());
58 }
59 if spec.order.is_empty() {
60 return Err("cyclic order cannot be empty".to_owned());
61 }
62 let mut values = Vec::with_capacity(spec.order.len());
63 for &index in &spec.order {
64 let Some(value) = cycle.values.get(index).cloned() else {
65 return Err(format!(
66 "cyclic order index {index} is outside source length {}",
67 cycle.values.len()
68 ));
69 };
70 values.push(value);
71 }
72 let rotation = spec.rotation % values.len();
73 values.rotate_left(rotation);
74 Ok(CyclicProjection {
75 track: cycle.track,
76 order: spec.order.clone(),
77 rotation,
78 values,
79 })
80}