diff --git a/src/music/mod.rs b/src/music/mod.rs index 292fdcf..3288ca8 100644 --- a/src/music/mod.rs +++ b/src/music/mod.rs @@ -40,9 +40,27 @@ impl

Primitive

{ pub type PlayerName = String; #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] -pub enum Mode { - Major, - Minor, +pub enum KeySig { + Major(PitchClass), + Minor(PitchClass), +} + +impl Default for KeySig { + fn default() -> Self { + // the white piano keys + Self::Major(PitchClass::C) + } +} + +impl KeySig { + pub fn get_scale(self) -> impl Iterator { + let oc4 = Octave::ONE_LINED; + let with_octave: Box> = match self { + KeySig::Major(pc) => Box::new(Pitch::new(pc, oc4).major_scale()), + KeySig::Minor(pc) => Box::new(Pitch::new(pc, oc4).natural_minor_scale()), + }; + with_octave.map(Pitch::class) + } } #[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)] @@ -52,7 +70,7 @@ pub enum Control { Instrument(InstrumentName), Phrase(Vec), Player(PlayerName), - KeySig(PitchClass, Mode), // key signature and mode + KeySig(KeySig), } #[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)] @@ -147,8 +165,8 @@ impl

Music

{ self.with(Control::Player(name)) } - pub fn with_key_sig(self, pitch_class: PitchClass, mode: Mode) -> Self { - self.with(Control::KeySig(pitch_class, mode)) + pub fn with_key_sig(self, key_signature: KeySig) -> Self { + self.with(Control::KeySig(key_signature)) } pub fn duration(&self) -> Dur { @@ -375,4 +393,40 @@ mod tests { let pitch = Pitch::C(Octave(-4)); assert_is_close_freq(pitch.get_frequency(), 1.022); } + + #[test] + fn key_sig_c_major_scale() { + let scale: Vec<_> = KeySig::Major(PitchClass::C).get_scale().collect(); + assert_eq!( + scale, + [ + PitchClass::C, + PitchClass::D, + PitchClass::E, + PitchClass::F, + PitchClass::G, + PitchClass::A, + PitchClass::B, + PitchClass::C, + ] + ); + } + + #[test] + fn key_sig_g_major_scale() { + let scale: Vec<_> = KeySig::Major(PitchClass::G).get_scale().collect(); + assert_eq!( + scale, + [ + PitchClass::G, + PitchClass::A, + PitchClass::B, + PitchClass::C, + PitchClass::D, + PitchClass::E, + PitchClass::Fs, + PitchClass::G, + ] + ); + } } diff --git a/src/music/performance.rs b/src/music/performance.rs index 3eb9d15..3de4832 100644 --- a/src/music/performance.rs +++ b/src/music/performance.rs @@ -7,8 +7,8 @@ use ordered_float::OrderedFloat; use crate::instruments::InstrumentName; use super::{ - duration::Dur, interval::AbsPitch, phrases::PhraseAttribute, pitch::PitchClass, Control, Mode, - Music, PlayerName, Primitive, Volume, + duration::Dur, interval::AbsPitch, phrases::PhraseAttribute, Control, KeySig, Music, + PlayerName, Primitive, Volume, }; #[derive(Debug)] @@ -84,8 +84,8 @@ where ctx.player = player; m.perf(players, ctx) } - Self::Modify(Control::KeySig(pc, mode), m) => { - ctx.key = (*pc, *mode); + Self::Modify(Control::KeySig(ks), m) => { + ctx.key = *ks; m.perf(players, ctx) } } @@ -126,7 +126,7 @@ pub struct Context<'p, P> { whole_note: Duration, pitch: AbsPitch, volume: Volume, - key: (PitchClass, Mode), + key: KeySig, } impl<'p, P> Clone for Context<'p, P> { @@ -495,7 +495,7 @@ mod defaults { whole_note: metro(120, Dur::QN), pitch: AbsPitch::from(0), volume: Volume::loudest(), - key: (PitchClass::C, Mode::Major), + key: KeySig::default(), } } }