From cd15235043b1a4c6f13cf01aa79a684e5a8cb16f Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 31 Jul 2024 10:54:49 -0500 Subject: [PATCH 1/2] update Signed-off-by: Joe McCain III --- core/src/chords/dyad.rs | 16 ++++---- core/src/error/err.rs | 53 +------------------------ core/src/error/kinds/music.rs | 37 +++++++++++++++++ core/src/error/mod.rs | 28 +++++++++++-- core/src/intervals/interval.rs | 57 --------------------------- core/src/intervals/kinds.rs | 51 ++++++++++++------------ core/src/intervals/mod.rs | 23 +++++------ core/src/macros/errors.rs | 40 +++++++++++++++++++ core/src/macros/intervals.rs | 2 +- core/src/notes/impls/impl_note_ops.rs | 40 ++++++++++--------- core/src/pitch/mod.rs | 29 ++------------ core/src/pitch/pitch.rs | 7 ++-- core/src/pitch/signs.rs | 30 ++++++++++++++ neo/src/transform/mod.rs | 2 +- neo/src/utils.rs | 6 +-- 15 files changed, 210 insertions(+), 211 deletions(-) create mode 100644 core/src/error/kinds/music.rs delete mode 100644 core/src/intervals/interval.rs create mode 100644 core/src/pitch/signs.rs diff --git a/core/src/chords/dyad.rs b/core/src/chords/dyad.rs index 795e081..d7a0af3 100644 --- a/core/src/chords/dyad.rs +++ b/core/src/chords/dyad.rs @@ -3,11 +3,11 @@ Contrib: FL03 */ use crate::notes::Note; -use crate::{Intervals, Pair}; +use crate::{Interval, Pair}; -fn _interval(lhs: A, rhs: B) -> Intervals +fn _interval(lhs: A, rhs: B) -> Interval where - A: core::ops::Sub, + A: core::ops::Sub, { lhs - rhs } @@ -16,19 +16,19 @@ where #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Dyad { chord: Pair, - interval: Intervals, + interval: Interval, } impl Dyad { pub fn new(src: Note, tgt: Note) -> Self { let chord = Pair::new(src, tgt); - let interval = Intervals::new(src, tgt); + let interval = Interval::new(src, tgt); Self { chord, interval } } pub fn from_tuple((lhs, rhs): (Note, Note)) -> Self { let chord = Pair::new(lhs, rhs); - let interval = Intervals::new(lhs, rhs); + let interval = Interval::new(lhs, rhs); Self { chord, interval } } @@ -40,11 +40,11 @@ impl Dyad { &mut self.chord } - pub const fn interval(&self) -> &Intervals { + pub const fn interval(&self) -> &Interval { &self.interval } - pub fn interval_mut(&mut self) -> &mut Intervals { + pub fn interval_mut(&mut self) -> &mut Interval { &mut self.interval } } diff --git a/core/src/error/err.rs b/core/src/error/err.rs index 0bd39af..916325c 100644 --- a/core/src/error/err.rs +++ b/core/src/error/err.rs @@ -2,48 +2,12 @@ Appellation: err Contrib: FL03 */ - -pub trait FluoError: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static {} - -impl FluoError for T where T: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static {} +use super::MusicalError; pub trait ErrorKind: core::fmt::Debug + core::fmt::Display {} impl ErrorKind for T where T: core::fmt::Debug + core::fmt::Display {} -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumIs, - strum::EnumString, - strum::VariantNames, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "PascalCase") -)] -#[strum(serialize_all = "PascalCase")] -pub enum MusicalError { - InvalidInterval, - InvalidPitch, -} - -#[cfg(feature = "std")] -impl std::error::Error for MusicalError {} - -unsafe impl Send for MusicalError {} - -unsafe impl Sync for MusicalError {} - #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[repr(transparent)] @@ -148,18 +112,3 @@ unsafe impl Sync for Error where K: ErrorKind {} #[cfg(feature = "std")] impl std::error::Error for Error where K: ErrorKind {} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_error() { - let err = Error::new( - MusicalError::InvalidInterval, - "Invalid interval".to_string(), - ); - assert_eq!(err.kind(), &MusicalError::InvalidInterval); - assert_eq!(err.msg(), "Invalid interval"); - } -} diff --git a/core/src/error/kinds/music.rs b/core/src/error/kinds/music.rs new file mode 100644 index 0000000..b0171ab --- /dev/null +++ b/core/src/error/kinds/music.rs @@ -0,0 +1,37 @@ +/* + Appellation: music + Contrib: FL03 +*/ + +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::AsRefStr, + strum::Display, + strum::EnumIs, + strum::EnumString, + strum::VariantNames, +)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "PascalCase") +)] +#[strum(serialize_all = "PascalCase")] +pub enum MusicalError { + InvalidInterval, + InvalidPitch, +} + +#[cfg(feature = "std")] +impl std::error::Error for MusicalError {} + +unsafe impl Send for MusicalError {} + +unsafe impl Sync for MusicalError {} diff --git a/core/src/error/mod.rs b/core/src/error/mod.rs index ff6dfa3..441f87b 100644 --- a/core/src/error/mod.rs +++ b/core/src/error/mod.rs @@ -2,14 +2,36 @@ Appellation: errors Contrib: FL03 */ -pub use self::err::*; +pub use self::{err::*, kinds::*}; pub(crate) mod err; -/// A type alias for `Result`. -pub type Result = core::result::Result; +pub mod kinds { + pub use self::music::*; + + pub(crate) mod music; +} pub(crate) mod prelude { pub use super::err::*; + pub use super::kinds::*; pub use super::Result; } + +/// A type alias for `Result`. +pub type Result = core::result::Result; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_error() { + let err = Error::new( + MusicalError::InvalidInterval, + "Invalid interval".to_string(), + ); + assert_eq!(err.kind(), &MusicalError::InvalidInterval); + assert_eq!(err.msg(), "Invalid interval"); + } +} diff --git a/core/src/intervals/interval.rs b/core/src/intervals/interval.rs deleted file mode 100644 index 3b83431..0000000 --- a/core/src/intervals/interval.rs +++ /dev/null @@ -1,57 +0,0 @@ -/* - Appellation: interval - Contrib: FL03 -*/ -use super::IntervalTy; -use crate::Step; - -/// The number of an interval. -#[derive( - Clone, - Copy, - Debug, - Default, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::AsRefStr, - strum::Display, - strum::EnumCount, - strum::EnumIs, - strum::EnumIter, - strum::VariantArray, - strum::VariantNames, -)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(rename_all = "lowercase") -)] -#[repr(i8)] -#[strum(serialize_all = "lowercase")] -pub enum IntervalLevel { - #[default] - Unison = 1, - Second = 2, - Third, - Fourth = 5, - Fifth, - Sixth, - Seventh, - Octave = 12, -} - -#[allow(dead_code)] -#[doc(hidden)] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Interval { - pub(crate) distance: IntervalTy, - pub(crate) level: IntervalLevel, - pub(crate) source: T, - pub(crate) step: Step, -} - -impl Interval {} diff --git a/core/src/intervals/kinds.rs b/core/src/intervals/kinds.rs index 11ca7c3..d427786 100644 --- a/core/src/intervals/kinds.rs +++ b/core/src/intervals/kinds.rs @@ -28,7 +28,7 @@ use crate::{IntoPitch, Pitch}; )] #[repr(u8)] #[strum(serialize_all = "lowercase")] -pub enum Intervals { +pub enum Interval { #[default] Semitone = 1, Tone = 2, @@ -39,19 +39,19 @@ pub enum Intervals { Octave = 12, } -impl Intervals { +impl Interval { pub fn new(lhs: A, rhs: B) -> Self where A: core::ops::Sub, - C: Into, + C: Into, { (lhs - rhs).into() } /// Use the difference between two pitches to determine the interval. pub fn from_value(value: impl IntoPitch) -> Self { - use Intervals::*; + use Interval::*; let pitch = value.into_pitch(); - match *pitch { + match *pitch.abs() { 1 => Semitone, 2 => Tone, 3 => Thirds(Third::Minor), @@ -69,31 +69,32 @@ impl Intervals { } /// A convenience method for constructing a new instance of the [Octave](Intervals::Octave) variant. pub fn octave() -> Self { - Intervals::Octave + Interval::Octave } /// A convenience method for constructing a new instance of the [Semitone](Intervals::Semitone) variant. pub fn semitone() -> Self { - Intervals::Semitone + Interval::Semitone } /// A convenience method for constructing a new instance of the [Tone](Intervals::Tone) variant. pub fn tone() -> Self { - Intervals::Tone + Interval::Tone } /// A convenience method for constructing a new variant, [`Thirds`](Intervals::Thirds). pub fn third(third: Third) -> Self { - Intervals::Thirds(third) + Interval::Thirds(third) } + /// A convenience method for constructing a new variant, [`Fourths`](Intervals::Fourths). pub fn fourth(fourth: Fourth) -> Self { - Intervals::Fourths(fourth) + Interval::Fourths(fourth) } /// A convenience method for constructing a new variant, [`Fifths`](Intervals::Fifths). pub fn fifth(fifth: Fifth) -> Self { - Intervals::Fifths(fifth) + Interval::Fifths(fifth) } /// A convenience method for constructing a new variant, [`Sevenths`](Intervals::Sevenths). pub fn seventh(seventh: Seventh) -> Self { - Intervals::Sevenths(seventh) + Interval::Sevenths(seventh) } /// Interpret the current interval as a pitch. pub fn as_pitch(&self) -> Pitch { @@ -106,13 +107,13 @@ impl Intervals { /// Returns the value of the selected interval. pub fn value(&self) -> i8 { match *self { - Intervals::Semitone => 1, - Intervals::Tone => 2, - Intervals::Thirds(third) => third as i8, - Intervals::Fourths(fourth) => fourth as i8, - Intervals::Fifths(fifth) => fifth as i8, - Intervals::Sevenths(seventh) => seventh as i8, - Intervals::Octave => 12, + Interval::Semitone => 1, + Interval::Tone => 2, + Interval::Thirds(third) => third as i8, + Interval::Fourths(fourth) => fourth as i8, + Interval::Fifths(fifth) => fifth as i8, + Interval::Sevenths(seventh) => seventh as i8, + Interval::Octave => 12, } } } @@ -132,20 +133,20 @@ macro_rules! impl_from_value { }; } -impl

From

for Intervals +impl

From

for Interval where P: IntoPitch, { fn from(value: P) -> Self { - Intervals::from_value(value) + Interval::from_value(value) } } impl_from_value! { - Intervals::Thirds(Third), - Intervals::Fourths(Fourth), - Intervals::Fifths(Fifth), - Intervals::Sevenths(Seventh), + Interval::Thirds(Third), + Interval::Fourths(Fourth), + Interval::Fifths(Fifth), + Interval::Sevenths(Seventh), } interval! { diff --git a/core/src/intervals/mod.rs b/core/src/intervals/mod.rs index 1bfcce4..4e81c17 100644 --- a/core/src/intervals/mod.rs +++ b/core/src/intervals/mod.rs @@ -3,20 +3,15 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{ - kinds::*, - qualities::{IntervalQuality, Quality}, -}; +pub use self::kinds::*; pub(crate) mod kinds; -pub mod interval; +#[doc(hidden)] pub mod qualities; pub(crate) mod prelude { - pub use super::interval::*; pub use super::kinds::*; - pub use super::qualities::{IntervalQuality, Quality}; pub use super::IntervalKind; } @@ -26,8 +21,10 @@ pub trait MusicalInterval { fn as_i8(&self) -> i8; } +/// [IntoInterval] is a trait describing a method which consumes the current type, +/// converting it into an [Intervals] pub trait IntoInterval { - fn into_interval(self) -> Intervals; + fn into_interval(self) -> Interval; } /// [IntervalKind] denotes objects used to explicitly define the various @@ -35,8 +32,8 @@ pub trait IntoInterval { pub trait IntervalKind { private!(); /// Returns the interval associated with the value - fn kind(&self) -> Intervals { - Intervals::from_value(self.value()) + fn kind(&self) -> Interval { + Interval::from_value(self.value()) } /// Returns the value associated with the interval fn value(&self) -> IntervalTy; @@ -48,14 +45,14 @@ pub trait IntervalKind { impl IntoInterval for I where - I: Into, + I: Into, { - fn into_interval(self) -> Intervals { + fn into_interval(self) -> Interval { self.into() } } -impl IntervalKind for Intervals { +impl IntervalKind for Interval { seal!(); fn value(&self) -> IntervalTy { self.value() diff --git a/core/src/macros/errors.rs b/core/src/macros/errors.rs index 5c82fbf..11cb1b8 100644 --- a/core/src/macros/errors.rs +++ b/core/src/macros/errors.rs @@ -2,3 +2,43 @@ Appellation: errors Contrib: FL03 */ + +macro_rules! error { + (@impl $name:ident {$($err:ident: $msg:literal),* $(,)?}) => { + #[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::AsRefStr, + strum::Display, + strum::EnumIs, + strum::EnumString, + strum::VariantNames, + )] + #[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "PascalCase") + )] + #[strum(serialize_all = "PascalCase")] + pub enum $name { + $($err),* + } + + impl $name { + + } + + #[cfg(feature = "std")] + impl std::error::Error for $name {} + + unsafe impl Send for $name {} + + unsafe impl Sync for $name {} + }; +} diff --git a/core/src/macros/intervals.rs b/core/src/macros/intervals.rs index 25cc160..191ef24 100644 --- a/core/src/macros/intervals.rs +++ b/core/src/macros/intervals.rs @@ -20,7 +20,7 @@ macro_rules! interval { Self::try_from(value) } - pub fn interval(&self) -> $crate::intervals::Intervals { + pub fn interval(&self) -> $crate::Interval { (*self).into() } diff --git a/core/src/notes/impls/impl_note_ops.rs b/core/src/notes/impls/impl_note_ops.rs index 1e70076..39242e1 100644 --- a/core/src/notes/impls/impl_note_ops.rs +++ b/core/src/notes/impls/impl_note_ops.rs @@ -2,24 +2,23 @@ Appellation: macros Contrib: FL03 */ -use crate::{Intervals, Note}; +use crate::Note; macro_rules! impl_interval_ops { (@assign $trait:ident.$call:ident) => { paste::paste! { - impl core::ops::[<$trait Assign>]<$crate::Intervals> for $crate::Note { - - fn [<$call _assign>](&mut self, rhs: $crate::Intervals) { - self.pitch = ::core::ops::$trait::$call(self.pitch, rhs.value()); + impl core::ops::[<$trait Assign>]<$crate::Interval> for $crate::Interval { + fn [<$call _assign>](&mut self, rhs: $crate::Interval) { + self = $crate::Interval::from(::core::ops::$trait::$call(self.pitch, rhs.value())); } } } }; (@note $trait:ident.$call:ident) => { - impl core::ops::$trait<$crate::Intervals> for $crate::Note { + impl core::ops::$trait<$crate::Interval> for Note { type Output = Note; - fn $call(self, rhs: $crate::Intervals) -> Self::Output { + fn $call(self, rhs: $crate::Interval) -> Self::Output { Note { octave: self.octave, pitch: core::ops::$trait::$call(self.pitch, rhs.value()) @@ -27,10 +26,10 @@ macro_rules! impl_interval_ops { } } - impl<'a> core::ops::$trait<$crate::Intervals> for &'a $crate::Note { + impl<'a> core::ops::$trait<$crate::Interval> for &'a Note { type Output = Note; - fn $call(self, rhs: $crate::Intervals) -> Self::Output { + fn $call(self, rhs: $crate::Interval) -> Self::Output { Note { octave: self.octave, pitch: ::core::ops::$trait::$call(self.pitch, rhs.value()) @@ -39,7 +38,7 @@ macro_rules! impl_interval_ops { } }; (@inter $trait:ident.$call:ident) => { - impl core::ops::$trait for $crate::Intervals { + impl core::ops::$trait for $crate::Interval { type Output = Note; fn $call(self, rhs: Note) -> Self::Output { @@ -50,7 +49,7 @@ macro_rules! impl_interval_ops { } } - impl<'a> core::ops::$trait<&'a Note> for Intervals { + impl<'a> core::ops::$trait<&'a Note> for $crate::Interval { type Output = Note; fn $call(self, rhs: &'a Note) -> Self::Output { @@ -61,7 +60,7 @@ macro_rules! impl_interval_ops { } } - impl<'a> core::ops::$trait for &'a Intervals { + impl<'a> core::ops::$trait for &'a $crate::Interval { type Output = Note; fn $call(self, rhs: Note) -> Self::Output { @@ -72,7 +71,7 @@ macro_rules! impl_interval_ops { } } - impl<'a> core::ops::$trait<&'a Note> for &'a Intervals { + impl<'a> core::ops::$trait<&'a Note> for &'a $crate::Interval { type Output = Note; fn $call(self, rhs: &'a Note) -> Self::Output { @@ -85,7 +84,6 @@ macro_rules! impl_interval_ops { }; ($($trait:ident.$call:ident),* $(,)?) => { $( - impl_interval_ops!(@assign $trait.$call); impl_interval_ops!(@note $trait.$call); impl_interval_ops!(@inter $trait.$call); )* @@ -93,7 +91,6 @@ macro_rules! impl_interval_ops { } macro_rules! impl_std_ops { - // (@selfmut ) (@assign $trait:ident.$call:ident) => { paste::paste! { impl core::ops::[<$trait Assign>] for Note { @@ -101,13 +98,19 @@ macro_rules! impl_std_ops { self.pitch = ::core::ops::$trait::$call(self.pitch, rhs.pitch); } } + + impl core::ops::[<$trait Assign>]<$crate::Interval> for Note { + fn [<$call _assign>](&mut self, rhs: $crate::Interval) { + self.pitch = ::core::ops::$trait::$call(self.pitch, rhs.as_pitch()); + } + } } }; (@impl $trait:ident.$call:ident) => { - impl core::ops::$trait<$crate::Note> for $crate::Note { - type Output = $crate::Note; + impl core::ops::$trait for Note { + type Output = Note; - fn $call(self, rhs: $crate::Note) -> Self::Output { + fn $call(self, rhs: Note) -> Self::Output { Note { octave: ::core::ops::$trait::$call(self.octave, rhs.octave), pitch: ::core::ops::$trait::$call(self.pitch, rhs.pitch) @@ -148,6 +151,7 @@ macro_rules! impl_std_ops { } } }; + ($($trait:ident.$call:ident),* $(,)?) => { $( impl_std_ops!(@assign $trait.$call); diff --git a/core/src/pitch/mod.rs b/core/src/pitch/mod.rs index 46f8474..f167945 100644 --- a/core/src/pitch/mod.rs +++ b/core/src/pitch/mod.rs @@ -8,6 +8,9 @@ pub use self::{kinds::*, pitch::Pitch}; pub(crate) mod kinds; pub(crate) mod pitch; +#[doc(hidden)] +pub mod signs; + mod impls { mod pitch_ops; } @@ -47,29 +50,3 @@ where self.into() } } - -pub enum SymbolCount { - Double = 2, - Single = 1, -} -pub struct FlatSymbol(SymbolCount); - -pub struct SharpSym(SymbolCount); - -impl SharpSym { - pub fn symbol(&self) -> &str { - match self.0 { - SymbolCount::Double => "♯♯", - SymbolCount::Single => "♯", - } - } -} - -impl FlatSymbol { - pub fn symbol(&self) -> &str { - match self.0 { - SymbolCount::Double => "♭♭", - SymbolCount::Single => "♭", - } - } -} diff --git a/core/src/pitch/pitch.rs b/core/src/pitch/pitch.rs index 14e2d64..909d70e 100644 --- a/core/src/pitch/pitch.rs +++ b/core/src/pitch/pitch.rs @@ -15,12 +15,11 @@ pub struct Pitch(pub(crate) PitchTy); impl Pitch { const MOD: PitchTy = crate::MODULUS; - pub fn new(pitch: impl Into) -> Self { - let val: PitchTy = pitch.into(); - Self(val.pymod(Self::MOD)) + pub fn new(pitch: PitchTy) -> Self { + Self(pitch) } /// Returns the absolute value of the remainder of the pitch divided by the modulus. - pub fn abs(&self) -> Self { + pub fn abs(self) -> Self { Self(self.0.pymod(Self::MOD).abs()) } /// Returns a new instance of the class representing the given pitch. diff --git a/core/src/pitch/signs.rs b/core/src/pitch/signs.rs new file mode 100644 index 0000000..f0412b7 --- /dev/null +++ b/core/src/pitch/signs.rs @@ -0,0 +1,30 @@ +/* + Appellation: signs + Contrib: FL03 +*/ + +pub enum SymbolCount { + Double = 2, + Single = 1, +} +pub struct FlatSymbol(SymbolCount); + +pub struct SharpSym(SymbolCount); + +impl SharpSym { + pub fn symbol(&self) -> &str { + match self.0 { + SymbolCount::Double => "♯♯", + SymbolCount::Single => "♯", + } + } +} + +impl FlatSymbol { + pub fn symbol(&self) -> &str { + match self.0 { + SymbolCount::Double => "♭♭", + SymbolCount::Single => "♭", + } + } +} diff --git a/neo/src/transform/mod.rs b/neo/src/transform/mod.rs index 5948332..9177073 100644 --- a/neo/src/transform/mod.rs +++ b/neo/src/transform/mod.rs @@ -51,7 +51,7 @@ pub(crate) mod utils { where K: Clone + TriadCls, { - use rstmt::Intervals::{Semitone, Tone}; + use rstmt::Interval::{Semitone, Tone}; let (mut r, mut t, mut f) = triad.clone().into_tuple(); match triad.root_to_third()? { Third::Major => match lpr { diff --git a/neo/src/utils.rs b/neo/src/utils.rs index de49bb0..932dda0 100644 --- a/neo/src/utils.rs +++ b/neo/src/utils.rs @@ -3,11 +3,11 @@ Contrib: FL03 */ use num::traits::NumOps; -use rstmt::Intervals; +use rstmt::Interval; -pub fn interval(lhs: A, rhs: B) -> Intervals +pub fn interval(lhs: A, rhs: B) -> Interval where A: NumOps, { - Intervals::from_value(lhs - rhs) + Interval::from_value(lhs - rhs) } From f55b2ae0f1be8c8ae453608f869e69b035c50678 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 31 Jul 2024 13:47:33 -0500 Subject: [PATCH 2/2] update Signed-off-by: Joe McCain III --- core/src/intervals/kinds.rs | 2 +- core/src/pitch/kinds.rs | 24 ++- core/src/pitch/pitch.rs | 52 +++--- neo/src/transform/lpr.rs | 61 ++++++- neo/src/transform/mod.rs | 91 +++++++--- neo/src/triad/classes.rs | 290 +++++++++++++++++++------------- neo/src/triad/impls/impl_ops.rs | 34 +--- neo/src/triad/mod.rs | 29 ++++ neo/src/triad/triad.rs | 105 +++++------- neo/tests/transform.rs | 21 --- rstmt/examples/triads.rs | 6 +- 11 files changed, 432 insertions(+), 283 deletions(-) diff --git a/core/src/intervals/kinds.rs b/core/src/intervals/kinds.rs index d427786..fc9ed1a 100644 --- a/core/src/intervals/kinds.rs +++ b/core/src/intervals/kinds.rs @@ -51,7 +51,7 @@ impl Interval { pub fn from_value(value: impl IntoPitch) -> Self { use Interval::*; let pitch = value.into_pitch(); - match *pitch.abs() { + match *pitch.absmod() { 1 => Semitone, 2 => Tone, 3 => Thirds(Third::Minor), diff --git a/core/src/pitch/kinds.rs b/core/src/pitch/kinds.rs index e5e607f..aa2d8a7 100644 --- a/core/src/pitch/kinds.rs +++ b/core/src/pitch/kinds.rs @@ -43,7 +43,6 @@ pitch_class! { #[derive( Clone, Copy, - Debug, Eq, Hash, Ord, @@ -51,7 +50,6 @@ pitch_class! { PartialOrd, smart_default::SmartDefault, strum::AsRefStr, - strum::Display, strum::EnumCount, strum::EnumIs, strum::VariantNames, @@ -92,6 +90,28 @@ impl Pitches { } } +impl core::fmt::Debug for Pitches { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use Pitches::*; + match self { + Flat(cls) => write!(f, "{}♭", cls.as_ref()), + Natural(cls) => write!(f, "{}", cls.as_ref()), + Sharp(cls) => write!(f, "{}#", cls.as_ref()), + } + } +} + +impl core::fmt::Display for Pitches { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use Pitches::*; + match self { + Flat(cls) => write!(f, "{}♭", cls.as_ref()), + Natural(cls) => write!(f, "{}", cls.as_ref()), + Sharp(cls) => write!(f, "{}#", cls.as_ref()), + } + } +} + impl PitchClass for Pitches { seal!(); diff --git a/core/src/pitch/pitch.rs b/core/src/pitch/pitch.rs index 909d70e..3e981a0 100644 --- a/core/src/pitch/pitch.rs +++ b/core/src/pitch/pitch.rs @@ -7,7 +7,7 @@ use crate::PyMod; /// A [pitch](Pitch) is a discrete tone with an individual frequency that may be /// classified as a [pitch class](Pitches). -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[repr(transparent)] pub struct Pitch(pub(crate) PitchTy); @@ -18,8 +18,12 @@ impl Pitch { pub fn new(pitch: PitchTy) -> Self { Self(pitch) } - /// Returns the absolute value of the remainder of the pitch divided by the modulus. + pub fn abs(self) -> Self { + Self(self.0.abs()) + } + /// Returns the absolute value of the remainder of the pitch divided by the modulus. + pub fn absmod(self) -> Self { Self(self.0.pymod(Self::MOD).abs()) } /// Returns a new instance of the class representing the given pitch. @@ -72,41 +76,35 @@ impl core::ops::DerefMut for Pitch { } } -impl core::fmt::Binary for Pitch { +impl core::fmt::Debug for Pitch { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::Binary::fmt(&self.0, f) + f.debug_tuple(&self.class().to_string()) + .field(&self.0) + .finish() } } impl core::fmt::Display for Pitch { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl core::fmt::LowerExp for Pitch { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::LowerExp::fmt(&self.0, f) - } -} - -impl core::fmt::LowerHex for Pitch { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::LowerHex::fmt(&self.0, f) + write!(f, "{}({})", self.class(), self.0) } } - -impl core::fmt::Octal for Pitch { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::Octal::fmt(&self.0, f) - } +macro_rules! impl_fmt { + (@impl $trait:ident) => { + impl ::core::fmt::$trait for Pitch { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + ::core::fmt::$trait::fmt(&self.0, f) + } + } + }; + ($($trait:ident),* $(,)?) => { + $( + impl_fmt!(@impl $trait); + )* + }; } -impl core::fmt::UpperExp for Pitch { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::UpperExp::fmt(&self.0, f) - } -} +impl_fmt!(Binary, LowerHex, Octal, UpperHex); impl From for Pitch { fn from(pitch: PitchTy) -> Self { diff --git a/neo/src/transform/lpr.rs b/neo/src/transform/lpr.rs index 47d9a36..6f2b5f1 100644 --- a/neo/src/transform/lpr.rs +++ b/neo/src/transform/lpr.rs @@ -4,6 +4,21 @@ */ use crate::Triad; +/// +/// +/// ### Leading (L) +/// +/// ### Parallel (P) +/// +/// Parallel transformations affect the third by half a step while leaving the root and fifth +/// unchanged. When applied on a major triad, the transformation results in a minor and vise +/// versa. For example, applying a single parallel transformation to an F major triad gives us +/// an F minor triad. +/// +/// ### Relative (R) +/// +/// A relative transformation transforms a triad into its relative. The transformation is more +/// involved than either leading or parallel transformations as they depend upon #[derive( Clone, Copy, @@ -52,7 +67,49 @@ impl LPR { } /// Apply the current transformation to the given triad; /// returns a [Triad] with the new notes and classification - pub fn apply(&self, _triad: &Triad) -> Triad { - unimplemented!() + pub fn apply(self, triad: &mut Triad) -> Triad { + use rstmt::{ + Interval::{Semitone, Tone}, + Third::*, + }; + let rt = triad + .root_to_third() + .expect("The given triad contained an invalid interval between the root and third!"); + let [r, t, f] = triad.as_mut_array(); + match rt { + Major => match self { + LPR::L => *r -= Semitone, + LPR::P => *t -= Semitone, + LPR::R => *f += Tone, + }, + Minor => match self { + LPR::L => *f += Semitone, + LPR::P => *t += Semitone, + LPR::R => *r -= Tone, + }, + }; + + Triad::try_from_arr(dbg!([*r, *t, *f])).expect( + "Transformation Error: the triad could not be constructed from the given notes.", + ) + } + + pub fn dyna(&self) -> Box { + match self { + LPR::L => Box::new(0), + LPR::P => Box::new(0), + LPR::R => Box::new(0), + } } } + +pub trait A { + fn a() -> bool + where + Self: Sized, + { + false + } +} + +impl A for T {} diff --git a/neo/src/transform/mod.rs b/neo/src/transform/mod.rs index 9177073..06805a3 100644 --- a/neo/src/transform/mod.rs +++ b/neo/src/transform/mod.rs @@ -43,29 +43,82 @@ where pub(crate) mod utils { use super::LPR; - use crate::error::TriadError; - use crate::triad::{Triad, TriadCls, Triads}; + use crate::prelude::TriadError; + use crate::triad::*; use rstmt::Third; - pub(crate) fn _transform(triad: Triad, lpr: LPR) -> Result, TriadError> + /// + /// + /// should result in a [Minor](crate::triad::Minor) triad. + pub fn _leading(triad: Triad) -> Result, TriadError> where - K: Clone + TriadCls, + K: TriadKind, + K2: TriadKind, { - use rstmt::Interval::{Semitone, Tone}; - let (mut r, mut t, mut f) = triad.clone().into_tuple(); - match triad.root_to_third()? { - Third::Major => match lpr { - LPR::L => r -= Semitone, - LPR::P => t -= Semitone, - LPR::R => f += Tone, - }, - Third::Minor => match lpr { - LPR::L => r += Semitone, - LPR::P => t += Semitone, - LPR::R => f -= Tone, - }, - }; + use rstmt::Interval::Semitone; + let rt = triad.root_to_third()?; + let (mut r, t, mut f) = triad.into_tuple(); + match rt { + Third::Major => { + r -= Semitone; + Triad::try_from_notes(t, f, r) + } + Third::Minor => { + f += Semitone; + Triad::try_from_notes(f, r, t) + } + } + } + + pub fn _parallel(triad: Triad) -> Result, TriadError> + where + K: TriadKind, + K2: TriadKind, + { + use rstmt::Interval::Semitone; + let rt = triad.root_to_third()?; + let (r, mut t, mut f) = triad.into_tuple(); + match rt { + Third::Major => { + t -= Semitone; + Triad::try_from_notes(f, r, t) + } + Third::Minor => { + f += Semitone; + Triad::try_from_notes(t, f, r) + } + } + } - Triad::try_from_arr([r, t, f]) + pub fn _relative(triad: Triad) -> Result, TriadError> + where + K: TriadKind, + K2: TriadKind, + { + use rstmt::Interval::Tone; + let rt = triad.root_to_third()?; + let (mut r, t, mut f) = triad.into_tuple(); + match rt { + Third::Major => { + f += Tone; + Triad::try_from_notes(f, r, t) + } + Third::Minor => { + r -= Tone; + Triad::try_from_notes(t, f, r) + } + } + } + + pub(crate) fn _transform(triad: Triad, lpr: LPR) -> Result, TriadError> + where + K: TriadKind, + K2: TriadKind, + { + match lpr { + LPR::L => _leading(triad), + LPR::P => _parallel(triad), + LPR::R => _relative(triad), + } } } diff --git a/neo/src/triad/classes.rs b/neo/src/triad/classes.rs index 88782e1..4f94780 100644 --- a/neo/src/triad/classes.rs +++ b/neo/src/triad/classes.rs @@ -7,65 +7,164 @@ use core::marker::PhantomData; use rstmt::{Fifth, Note, Third}; use strum::IntoEnumIterator; +pub trait Named { + fn named(&self) -> &'static str; +} + +pub trait Relative { + type Rel; + + fn relative(&self) -> Self::Rel; +} + /// This trait denotes privately declared instances of different classes of triads. /// Traditionally, triads have two primary classes: [major](Major) and [minor](Minor), however, there are /// two additional classes: [augmented](Augmented) and [diminished](Diminished). This trait is used to determine -pub trait TriadCls: Clone + Sized { +pub trait TriadCls { private!(); - #[doc(hidden)] - fn name() -> &'static str { - core::any::type_name::() + fn named(&self) -> &'static str; +} + +impl TriadCls for Triads { + seal!(); + + fn named(&self) -> &'static str { + match self { + Triads::Augmented => "augmented", + Triads::Diminished => "diminished", + Triads::Major => "major", + Triads::Minor => "minor", + } } } -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Kinds { - Augmented(PhantomData), - Diminished(PhantomData), - Major(PhantomData), - Minor(PhantomData), +impl TriadCls for PhantomData +where + K: TriadKind, +{ + seal!(); + + fn named(&self) -> &'static str { + K::name() + } } -impl Kinds { - pub fn augmented() -> Self { - Kinds::Augmented(PhantomData::) +impl Relative for PhantomData +where + K: TriadKind, +{ + type Rel = Triads; + + fn relative(&self) -> Self::Rel { + K::class() } +} - pub fn diminished() -> Self { - Kinds::Diminished(PhantomData::) +impl TriadKind for PhantomData +where + K: TriadKind, +{ + seal!(); + + fn class() -> Triads { + K::class() } - pub fn major() -> Self { - Kinds::Major(PhantomData::) + fn name() -> &'static str { + K::name() } +} - pub fn minor() -> Self { - Kinds::Minor(PhantomData::) +pub trait TriadKind: Relative + TriadCls { + private!(); + + fn class() -> Triads + where + Self: Sized; + + fn name() -> &'static str + where + Self: Sized; + /// Returns a new instance of [PhantomData](core::marker::PhantomData); + /// This method is the only possible constructor for these objects, + /// a charecteristic enfored with 0-variant enum declarations. + fn phantom() -> core::marker::PhantomData + where + Self: Sized, + { + core::marker::PhantomData:: } - pub fn is(&self) -> bool { - match self { - Kinds::Augmented(_) => K::is_augmented(), - Kinds::Diminished(_) => K::is_diminished(), - Kinds::Major(_) => K::is_major(), - Kinds::Minor(_) => K::is_minor(), - } + fn is_valid(notes: &[Note; 3]) -> bool + where + Self: Sized, + { + Self::class().validate(notes) } - // pub fn into_kind(self) -> PhantomData { - // match self { - // Class::Augmented(cls) => cls, - // Class::Diminished(cls) => cls, - // Class::Major(cls) => cls, - // Class::Minor(cls) => cls, - // } - // } -} + fn thirds() -> (Third, Third) + where + Self: Sized, + { + Self::class().thirds() + } + + fn root_to_third() -> Third + where + Self: Sized, + { + Self::thirds().0 + } + + fn third_to_fifth() -> Third + where + Self: Sized, + { + Self::thirds().1 + } + + fn root_to_fifth() -> Fifth + where + Self: Sized, + { + Self::class().root_to_fifth() + } + + fn intervals() -> (Third, Third, Fifth) + where + Self: Sized, + { + let (a, b) = Self::thirds(); + (a, b, Self::root_to_fifth()) + } + + fn is_augmented() -> bool + where + Self: Sized, + { + Self::class().is_augmented() + } + + fn is_diminished() -> bool + where + Self: Sized, + { + Self::class().is_diminished() + } + + fn is_major() -> bool + where + Self: Sized, + { + Self::class().is_major() + } -impl Default for Kinds { - fn default() -> Self { - Kinds::Major(PhantomData::) + fn is_minor() -> bool + where + Self: Sized, + { + Self::class().is_minor() } } @@ -229,10 +328,6 @@ impl Triads { } } -impl TriadCls for Triads { - seal!(); -} - impl From> for Triads where K: TriadKind, @@ -251,86 +346,47 @@ where } } -pub trait TriadKind: TriadCls -where - Self: Copy + Sized, -{ - /// Returns a new instance of [PhantomData](core::marker::PhantomData); - /// This method is the only possible constructor for these objects, - /// a charecteristic enfored with 0-variant enum declarations. - fn phantom() -> core::marker::PhantomData { - core::marker::PhantomData:: - } - fn is_valid(notes: &[Note; 3]) -> bool { - Self::class().validate(notes) - } - - fn class() -> Triads { - if Self::is_major() { - Triads::major() - } else if Self::is_minor() { - Triads::minor() - } else if Self::is_augmented() { - Triads::augmented() - } else { - Triads::diminished() - } - } - - fn thirds() -> (Third, Third) { - Self::class().thirds() - } - - fn root_to_third() -> Third { - Self::thirds().0 - } - - fn third_to_fifth() -> Third { - Self::thirds().1 - } - - fn root_to_fifth() -> Fifth { - Self::class().root_to_fifth() - } - - fn intervals() -> (Third, Third, Fifth) { - let (a, b) = Self::thirds(); - (a, b, Self::root_to_fifth()) - } - - fn name() -> &'static str; - - fn is_augmented() -> bool { - false - } +macro_rules! class { + (@impl $name:ident::$call:ident -> $relative:ident) => { + #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize),)] + pub struct $name; - fn is_diminished() -> bool { - false - } + impl $name { + pub fn class() -> Triads { + Triads::$name + } - fn is_major() -> bool { - false - } + pub fn name(&self) -> &'static str { + stringify!($call) + } + } - fn is_minor() -> bool { - false - } -} + impl Relative for $name { + type Rel = Triads; -macro_rules! class { - (@impl $name:ident::$call:ident) => { - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] - #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize),)] - pub enum $name {} + fn relative(&self) -> Self::Rel { + Triads::$relative + } + } impl TriadCls for $name { seal!(); + + fn named(&self) -> &'static str { + stringify!($call) + } } impl TriadKind for $name { + seal!(); + + fn class() -> Triads where Self: Sized { + Triads::$name + } - fn name() -> &'static str { - stringify!($name) + fn name() -> &'static str where Self: Sized { + stringify!($call) } paste::paste! { @@ -344,16 +400,16 @@ macro_rules! class { unsafe impl Sync for $name {} }; - ($($name:ident::$call:ident),* $(,)?) => { + ($($name:ident::$call:ident -> $rel:ident),* $(,)?) => { $( - class!(@impl $name::$call); + class!(@impl $name::$call -> $rel); )* }; } class!( - Augmented::augmented, - Diminished::diminished, - Major::major, - Minor::minor + Augmented::augmented -> Diminished, + Diminished::diminished -> Augmented, + Major::major -> Minor, + Minor::minor -> Major ); diff --git a/neo/src/triad/impls/impl_ops.rs b/neo/src/triad/impls/impl_ops.rs index 91e8557..f7d2084 100644 --- a/neo/src/triad/impls/impl_ops.rs +++ b/neo/src/triad/impls/impl_ops.rs @@ -2,26 +2,11 @@ Appellation: impl_triad Contrib: FL03 */ -use crate::transform::{Transform, LPR}; -use crate::triad::{Triad, TriadCls, TriadKind, Triads}; +use crate::triad::Triad; use crate::Factors; use rstmt::Note; -impl Transform for Triad -where - K: TriadCls, -{ - type Output = Result, crate::TriadError>; - - fn transform(self, lpr: LPR) -> Self::Output { - crate::transform::utils::_transform(self, lpr) - } -} - -impl core::ops::Index for Triad -where - K: TriadKind, -{ +impl core::ops::Index for Triad { type Output = Note; fn index(&self, index: Factors) -> &Self::Output { @@ -29,19 +14,13 @@ where } } -impl core::ops::IndexMut for Triad -where - K: TriadKind, -{ +impl core::ops::IndexMut for Triad { fn index_mut(&mut self, index: Factors) -> &mut Self::Output { &mut self.notes[index as usize] } } -impl core::ops::Index> for Triad -where - K: TriadKind, -{ +impl core::ops::Index> for Triad { type Output = [Note]; fn index(&self, index: core::ops::Range) -> &Self::Output { @@ -49,10 +28,7 @@ where } } -impl core::ops::IndexMut> for Triad -where - K: TriadKind, -{ +impl core::ops::IndexMut> for Triad { fn index_mut(&mut self, index: core::ops::Range) -> &mut Self::Output { &mut self.notes[index.start as usize..index.end as usize] } diff --git a/neo/src/triad/mod.rs b/neo/src/triad/mod.rs index c834927..ad45a5d 100644 --- a/neo/src/triad/mod.rs +++ b/neo/src/triad/mod.rs @@ -25,6 +25,35 @@ pub(crate) mod prelude { use crate::TriadError; +pub trait Kind { + type Class: Classifier; + + fn phantom() -> core::marker::PhantomData + where + Self: Sized, + { + core::marker::PhantomData:: + } + + fn name() -> &'static str + where + Self: Sized; +} + +pub trait Classifier { + fn name(&self) -> &'static str; +} + +impl Classifier for core::marker::PhantomData +where + T: Kind, +{ + fn name(&self) -> &'static str { + T::name() + } +} + +/// [IntoTriad] converts a type into a [Triad]. pub trait IntoTriad { fn into_triad(self) -> Triad; } diff --git a/neo/src/triad/triad.rs b/neo/src/triad/triad.rs index 974f1de..1f1134e 100644 --- a/neo/src/triad/triad.rs +++ b/neo/src/triad/triad.rs @@ -53,20 +53,9 @@ pub struct Triad { pub(crate) _class: PhantomData, } -impl Triad { +impl Triad { pub const LEN: usize = 3; /// Create a new triad from a root note. - pub fn new(class: Triads, root: Note) -> Self { - let (rt, tf) = class.thirds(); - let octave = *root.octave(); - let t = Note::new(octave, root.pitch() + rt.value()); - let f = Note::new(octave, t.pitch() + tf.value()); - Self { - _class: PhantomData::, - notes: [root, t, f], - } - } - /// Create a new triad from a root note. pub fn from_root(root: Note) -> Self where K: TriadKind, @@ -86,6 +75,7 @@ impl Triad { /// that is valid. If no valid configuration is found, an error is returned. pub fn try_from_arr(notes: [Note; 3]) -> Result { for (&a, &b, &c) in notes.iter().circular_tuple_windows() { + println!("{} {} {}", a, b, c); if let Ok(triad) = Triad::try_from_notes(a, b, c) { return Ok(triad); } @@ -121,6 +111,32 @@ impl Triad { _class: PhantomData::, } } + /// Returns the name of the class + pub fn class_name(&self) -> &str + where + K: TriadKind, + { + TriadCls::named(&self._class) + } + /// Swaps the classifying type of the triad; + /// useful for converting from dynamically typed triads to statically typed triads. + pub fn swap_kind(&self) -> Triad { + Triad { + notes: self.notes, + _class: PhantomData::, + } + } + /// Transforms the triad using one of the [LPR] transformations; + /// see [LPR::apply] for more information. + pub fn apply(mut self, lpr: LPR) -> Triad + where + K: TriadKind, + { + lpr.apply(&mut self) + } +} + +impl Triad { /// Returns an owned reference to the array of notes pub fn as_array(&self) -> &[Note; 3] { &self.notes @@ -137,10 +153,6 @@ impl Triad { pub fn as_tuple(&self) -> (Note, Note, Note) { (self.notes[0], self.notes[1], self.notes[2]) } - /// Returns the name of the class - pub fn class_name(&self) -> &str { - K::name() - } /// Consumes and returns an array of notes pub fn into_array(self) -> [Note; 3] { self.notes @@ -164,15 +176,6 @@ impl Triad { pub fn iter_mut(&mut self) -> core::slice::IterMut { self.notes.iter_mut() } - /// Swaps the classifying type of the triad; - /// useful for converting from dynamically typed triads to statically typed triads. - pub fn swap_kind(&self) -> Triad { - Triad { - notes: self.notes, - _class: PhantomData::, - } - } - /// Returns the root note of the triad pub fn root(&self) -> Note { self.notes[0] @@ -181,6 +184,22 @@ impl Triad { pub fn root_mut(&mut self) -> &mut Note { &mut self.notes[0] } + /// Returns the third note of the triad + pub fn third(&self) -> Note { + self.notes[1] + } + /// Returns a mutable reference to the third note of the triad + pub fn third_mut(&mut self) -> &mut Note { + &mut self.notes[1] + } + /// Returns the final note of the triad + pub fn fifth(&self) -> Note { + self.notes[2] + } + /// Returns a mutable reference to the final note of the triad + pub fn fifth_mut(&mut self) -> &mut Note { + &mut self.notes[2] + } /// Returns the distance (interval) between the root and the third pub fn root_to_third(&self) -> Result { Third::new(self.notes[0], self.notes[1]).map_err(|_| { @@ -197,14 +216,6 @@ impl Triad { ) }) } - /// Returns the third note of the triad - pub fn third(&self) -> Note { - self.notes[1] - } - /// Returns a mutable reference to the third note of the triad - pub fn third_mut(&mut self) -> &mut Note { - &mut self.notes[1] - } /// Returns the distance (interval) between the third and the fifth pub fn third_to_fifth(&self) -> Result { Third::new(self.notes[1], self.notes[2]).map_err(|_| { @@ -213,14 +224,6 @@ impl Triad { ) }) } - /// Returns the final note of the triad - pub fn fifth(&self) -> Note { - self.notes[2] - } - /// Returns a mutable reference to the final note of the triad - pub fn fifth_mut(&mut self) -> &mut Note { - &mut self.notes[2] - } /// Returns a new instance of [Triad] with the notes in reverse order pub fn reversed(&self) -> Self { Self { @@ -228,24 +231,4 @@ impl Triad { _class: PhantomData::, } } - /// Transforms the triad using one of the [LPR] transformations. - /// Each transformation - pub fn apply(self, lpr: LPR) -> Triad - where - K: Clone, - { - crate::transform::_transform(self, lpr).unwrap() - } - - pub fn chain(self, steps: I) -> Result, TriadError> - where - I: IntoIterator, - K: Clone, - { - let mut triad = self.as_dyn(); - for i in steps { - triad = triad.transform(i)? - } - Ok(triad) - } } diff --git a/neo/tests/transform.rs b/neo/tests/transform.rs index eafc94c..17c8067 100644 --- a/neo/tests/transform.rs +++ b/neo/tests/transform.rs @@ -23,17 +23,6 @@ fn test_parallel() { assert_ne!(c_major.root_to_third(), next.root_to_third()); } -#[test] -fn test_parallel_invert() { - use LPR::P; - - let triad = Triad::::from_root(Note::from_pitch(0)); - // Validate the transformations invertability - let pp = triad.chain([P, P]).unwrap(); - assert_eq!(triad.as_dyn(), pp); - assert_eq!(triad, pp.cast()); -} - #[test] fn test_leading() { use LPR::L; @@ -47,13 +36,3 @@ fn test_leading() { // Compare the intervals between the two triads assert_ne!(c_major.third_to_fifth(), next.third_to_fifth()); } - -#[test] -fn test_leading_invert() { - use LPR::L; - - let triad = Triad::::from_root(Note::from_pitch(0)); - let ll = triad.chain([L, L]).unwrap(); - assert_eq!(triad.as_dyn(), ll); - assert_eq!(triad, ll.cast()); -} diff --git a/rstmt/examples/triads.rs b/rstmt/examples/triads.rs index db51e16..a8ba303 100644 --- a/rstmt/examples/triads.rs +++ b/rstmt/examples/triads.rs @@ -7,9 +7,7 @@ use rstmt::Note; fn main() -> Result<(), Box> { let root = Note::from_pitch(0); - let triad = Triad::::from_root(root); - let triad2 = Triad::new(Triads::Major, root).cast(); - assert_eq!(triad, triad2); - println!("{:?}", triad); + let triad = Triad::major(root); + println!("{triad:?}"); Ok(()) }