sim_lib_pitch_serial/
interval.rs1use sim_lib_pitch_core::PitchClass;
4
5use crate::{RowFamily, ToneRow};
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
12pub struct OrderedIntervalString {
13 intervals: [u8; 11],
14}
15
16impl OrderedIntervalString {
17 pub fn of_row(row: &ToneRow) -> Self {
19 Self {
20 intervals: ordered_intervals(row.classes()),
21 }
22 }
23
24 pub const fn intervals(&self) -> &[u8; 11] {
26 &self.intervals
27 }
28
29 pub const fn under_family(self, family: RowFamily) -> Self {
35 let mut intervals = self.intervals;
36 match family {
37 RowFamily::P => {}
38 RowFamily::I => {
39 let mut index = 0;
40 while index < intervals.len() {
41 intervals[index] = (12 - intervals[index]) % 12;
42 index += 1;
43 }
44 }
45 RowFamily::R => {
46 intervals.reverse();
47 let mut index = 0;
48 while index < intervals.len() {
49 intervals[index] = (12 - intervals[index]) % 12;
50 index += 1;
51 }
52 }
53 RowFamily::RI => intervals.reverse(),
54 }
55 Self { intervals }
56 }
57}
58
59pub(crate) fn ordered_intervals(classes: &[PitchClass]) -> [u8; 11] {
60 debug_assert_eq!(classes.len(), 12);
61 std::array::from_fn(|index| {
62 (12 + i16::from(classes[index + 1].value()) - i16::from(classes[index].value())) as u8 % 12
63 })
64}
65
66pub(crate) fn ordered_intervals_vec(classes: &[PitchClass]) -> Vec<u8> {
67 classes
68 .windows(2)
69 .map(|window| (12 + i16::from(window[1].value()) - i16::from(window[0].value())) as u8 % 12)
70 .collect()
71}