1#[doc(inline)]
6pub use self::{class::*, factors::*};
7
8pub(crate) mod class;
9pub(crate) mod factors;
10
11use crate::error::MusicError;
12use crate::traits::{IntoNote, IntoOctave, PitchMod};
13use crate::transform::{LPR, TriadNavigator};
14use crate::types::{Note, Octave};
15
16use num_traits::{Float, FromPrimitive};
17
18#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
24#[cfg_attr(
25 feature = "serde",
26 derive(serde_derive::Deserialize, serde_derive::Serialize)
27)]
28pub struct Triad {
29 pub(crate) class: Triads,
31 pub(crate) notes: [usize; 3],
33 pub(crate) octave: Octave,
35}
36
37impl Triad {
38 pub fn new(notes: [usize; 3], class: Triads) -> Self {
39 if !class.validate(¬es) {
40 panic!("Invalid triad pitches for class {notes:?}");
41 }
42 Self {
43 class,
44 notes,
45 octave: Octave(4),
46 }
47 }
48 pub fn from_root<N>(root: N, class: Triads) -> Self
50 where
51 N: IntoNote,
52 {
53 let note = root.into_note();
55 let root = note.class();
56 let [a, .., c] = class.intervals();
57 let third = (root + a).pmod();
58 let fifth = (root + c).pmod();
59 Self {
60 class,
61 notes: [root, third, fifth],
62 octave: note.octave(),
63 }
64 }
65 pub fn augmented<N>(root: N) -> Self
67 where
68 N: IntoNote,
69 {
70 Self::from_root(root, Triads::Augmented)
71 }
72 pub fn diminished<N>(root: N) -> Self
74 where
75 N: IntoNote,
76 {
77 Self::from_root(root, Triads::Diminished)
78 }
79 pub fn major<N>(root: N) -> Self
81 where
82 N: IntoNote,
83 {
84 Self::from_root(root, Triads::Major)
85 }
86 pub fn minor<N>(root: N) -> Self
88 where
89 N: IntoNote,
90 {
91 Self::from_root(root, Triads::Minor)
92 }
93 pub const fn class(&self) -> Triads {
95 self.class
96 }
97 pub fn common_tones(&self, other: &Self) -> Vec<usize> {
99 self.notes()
100 .iter()
101 .filter(|&&n| other.contains(&n))
102 .copied()
103 .collect::<Vec<_>>()
104 }
105 pub const fn notes(&self) -> [usize; 3] {
107 self.notes
108 }
109 pub fn notes_mut(&mut self) -> &mut [usize; 3] {
111 &mut self.notes
112 }
113 pub const fn octave(&self) -> Octave {
115 self.octave
116 }
117 pub fn octave_mut(&mut self) -> &mut Octave {
119 &mut self.octave
120 }
121 pub fn root(&self) -> Note {
123 Note {
124 class: self[Factors::Root],
125 octave: self.octave(),
126 }
127 }
128 pub fn third(&self) -> Note {
130 Note {
131 class: self[Factors::Third],
132 octave: self.octave(),
133 }
134 }
135 pub fn fifth(&self) -> Note {
137 Note {
138 class: self[Factors::Fifth],
139 octave: self.octave(),
140 }
141 }
142 pub fn contains<Q>(&self, pitch: &Q) -> bool
144 where
145 Q: core::borrow::Borrow<usize>,
146 {
147 self.notes().contains(pitch.borrow())
148 }
149 pub fn is_augmented(&self) -> bool {
151 self.class().is_augmented()
152 }
153 pub fn is_diminished(&self) -> bool {
155 self.class().is_diminished()
156 }
157 pub fn is_major(&self) -> bool {
159 self.class().is_major()
160 }
161 pub fn is_minor(&self) -> bool {
163 self.class().is_minor()
164 }
165 pub fn is_valid(&self) -> bool {
167 self.class().validate(&self.notes())
168 }
169 pub fn leading(&self) -> Self {
171 self.transform(LPR::Leading)
172 }
173 pub fn parallel(&self) -> Self {
175 self.transform(LPR::Parallel)
176 }
177 pub fn relative(&self) -> Self {
179 self.transform(LPR::Relative)
180 }
181 pub fn centroid<T>(&self) -> Option<[T; 2]>
183 where
184 T: Float + FromPrimitive,
185 {
186 let y = T::from_isize(*self.octave)?;
187 let x = T::from_usize(self.notes().iter().sum())? / T::from_usize(self.notes().len())?;
188 Some([x, y])
189 }
190 pub fn barycentric<T>(&self, p: impl IntoNote) -> [T; 3]
192 where
193 T: Float + FromPrimitive,
194 {
195 let note = p.into_note();
196 let px = T::from_usize(note.class().pmod()).unwrap();
197 let py = T::from_isize(*note.octave()).unwrap();
198 let y = T::from_isize(*self.octave).unwrap();
199 let [v0, v1, v2] = self.notes.map(|n| T::from_usize(n).unwrap());
200
201 let d00 = v0 * v0 + y * y;
202 let d01 = v0 * v1 + y * y;
203 let d11 = v1 * v1 + y * y;
204 let d20 = v2 * px + y * py;
205 let d21 = v2 * v1 + y * y;
206
207 let denom = d00 * d11 - d01 * d01;
208 let a = (d11 * d20 - d01 * d21) / denom;
209 let b = (d00 * d21 - d01 * d20) / denom;
210 let c = T::one() - a - b;
211 [a, b, c]
212 }
213 pub fn path_finder(&self) -> TriadNavigator<'_> {
215 TriadNavigator::new(self)
216 }
217 pub fn transform(&self, transform: LPR) -> Self {
219 transform.apply(self)
220 }
221 pub fn transform_inplace(&mut self, transform: LPR) {
223 *self = self.transform(transform);
224 }
225 pub fn walk<I>(&self, path: I) -> Self
227 where
228 I: IntoIterator<Item = LPR>,
229 {
230 path.into_iter()
231 .fold(*self, |triad, transform| transform.apply(&triad))
232 }
233 pub fn walk_inplace<I>(&mut self, path: I)
235 where
236 I: IntoIterator<Item = LPR>,
237 {
238 *self = self.walk(path);
239 }
240 pub fn try_transform(&self, transform: LPR) -> Result<Self, MusicError> {
242 transform.try_apply(self)
243 }
244 pub fn set_octave<O>(&mut self, octave: O)
246 where
247 O: IntoOctave,
248 {
249 self.octave = octave.into_octave();
250 }
251 pub fn with_octave<O>(self, octave: O) -> Self
253 where
254 O: IntoOctave,
255 {
256 Self {
257 octave: octave.into_octave(),
258 ..self
259 }
260 }
261}
262
263impl Default for Triad {
264 fn default() -> Self {
265 Triad::major(Note::from_pitch(0))
266 }
267}
268
269impl core::fmt::Display for Triad {
270 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
271 write!(f, "{}({:?})", self.class, self.notes)
272 }
273}
274
275impl core::convert::AsRef<[usize; 3]> for Triad {
276 fn as_ref(&self) -> &[usize; 3] {
277 &self.notes
278 }
279}
280
281impl core::convert::AsMut<[usize; 3]> for Triad {
282 fn as_mut(&mut self) -> &mut [usize; 3] {
283 &mut self.notes
284 }
285}
286
287impl core::ops::Index<usize> for Triad {
288 type Output = usize;
289 fn index(&self, index: usize) -> &Self::Output {
290 &self.notes[index % 3]
291 }
292}
293
294impl core::ops::IndexMut<usize> for Triad {
295 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
296 &mut self.notes[index % 3]
297 }
298}
299
300impl core::ops::Index<Factors> for Triad {
301 type Output = usize;
302 fn index(&self, index: Factors) -> &Self::Output {
303 &self.notes[index as usize]
304 }
305}
306
307impl core::ops::IndexMut<Factors> for Triad {
308 fn index_mut(&mut self, index: Factors) -> &mut Self::Output {
309 &mut self.notes[index as usize]
310 }
311}
312
313impl core::ops::Mul<LPR> for Triad {
314 type Output = Self;
315
316 fn mul(self, rhs: LPR) -> Self::Output {
317 rhs.apply(&self)
318 }
319}
320
321impl core::ops::MulAssign<LPR> for Triad {
322 fn mul_assign(&mut self, rhs: LPR) {
323 *self = rhs.apply(self);
324 }
325}
326
327impl core::iter::IntoIterator for Triad {
328 type Item = usize;
329
330 type IntoIter = core::array::IntoIter<Self::Item, 3>;
331
332 fn into_iter(self) -> Self::IntoIter {
333 self.notes.into_iter()
334 }
335}
336
337impl<'a> core::iter::IntoIterator for &'a Triad {
338 type Item = &'a usize;
339
340 type IntoIter = core::slice::Iter<'a, usize>;
341
342 fn into_iter(self) -> Self::IntoIter {
343 self.notes.iter()
344 }
345}
346
347impl<'a> core::iter::IntoIterator for &'a mut Triad {
348 type Item = &'a mut usize;
349
350 type IntoIter = core::slice::IterMut<'a, usize>;
351
352 fn into_iter(self) -> Self::IntoIter {
353 self.notes.iter_mut()
354 }
355}