sim_lib_pitch_serial/
row.rs1use sim_lib_pitch_core::PitchClass;
4use sim_lib_serial_core::{AggregateRule, Series};
5
6use crate::{PitchClassAlphabet, RowError, RowLabel, RowLabelConvention, RowOperation};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct ToneRow {
11 classes: [PitchClass; 12],
12}
13
14impl ToneRow {
15 pub fn try_from_classes(classes: [PitchClass; 12]) -> Result<Self, RowError> {
21 let alphabet = PitchClassAlphabet::try_new()?;
22 Series::try_new(
23 alphabet,
24 AggregateRule::exhaustive_exactly_once(),
25 classes.to_vec(),
26 )?;
27 Ok(Self::from_valid_classes(classes))
28 }
29
30 pub const fn classes(&self) -> &[PitchClass; 12] {
32 &self.classes
33 }
34
35 pub fn apply(&self, operation: RowOperation) -> RowForm {
37 let operation = operation.normalized();
38 let mut classes = std::array::from_fn(|position| {
39 let class = self.classes[position];
40 let class = if operation.family.is_inverted() {
41 class.invert(PitchClass::C)
42 } else {
43 class
44 };
45 class.transpose(i32::from(operation.addend))
46 });
47 if operation.family.is_retrograde() {
48 classes.reverse();
49 }
50 RowForm {
51 row: Self::from_valid_classes(classes),
52 operation,
53 }
54 }
55
56 pub(crate) const fn from_valid_classes(classes: [PitchClass; 12]) -> Self {
57 Self { classes }
58 }
59}
60
61#[derive(Clone, Debug, PartialEq, Eq)]
66pub struct RowForm {
67 row: ToneRow,
68 operation: RowOperation,
69}
70
71impl RowForm {
72 pub const fn operation(&self) -> RowOperation {
74 self.operation
75 }
76
77 pub const fn row(&self) -> &ToneRow {
79 &self.row
80 }
81
82 pub const fn classes(&self) -> &[PitchClass; 12] {
84 self.row.classes()
85 }
86
87 pub fn label(&self, convention: RowLabelConvention) -> RowLabel {
89 convention.label(self)
90 }
91
92 pub fn into_row(self) -> ToneRow {
94 self.row
95 }
96}