music21_rs/scale/
diatonicscale.rs1use crate::{chord::Chord, defaults::IntegerType, error::Result, pitch::Pitch};
2
3use super::concretescale::ConcreteScale;
4
5#[derive(Clone, Debug)]
6#[must_use]
8pub struct DiatonicScale {
9 concrete: ConcreteScale,
10 mode: String,
11}
12
13impl DiatonicScale {
14 pub(crate) fn new(tonic: Pitch, sharps: IntegerType, mode: &str) -> Self {
15 Self {
16 concrete: ConcreteScale::new(tonic, sharps),
17 mode: mode.to_string(),
18 }
19 }
20
21 pub fn mode(&self) -> &str {
23 &self.mode
24 }
25
26 pub fn tonic(&self) -> &Pitch {
28 self.concrete.tonic()
29 }
30
31 pub fn pitch_from_degree(&self, degree: usize) -> Result<Pitch> {
33 self.concrete.pitch_from_degree(degree)
34 }
35
36 pub fn pitches(&self) -> Result<Vec<Pitch>> {
38 self.concrete.pitches()
39 }
40
41 pub fn triad_from_degree(&self, degree: usize) -> Result<Chord> {
43 let notes = vec![
44 self.pitch_from_degree(degree)?,
45 self.pitch_from_degree(degree + 2)?,
46 self.pitch_from_degree(degree + 4)?,
47 ];
48 Chord::new(notes.as_slice())
49 }
50
51 pub fn seventh_chord_from_degree(&self, degree: usize) -> Result<Chord> {
53 let notes = vec![
54 self.pitch_from_degree(degree)?,
55 self.pitch_from_degree(degree + 2)?,
56 self.pitch_from_degree(degree + 4)?,
57 self.pitch_from_degree(degree + 6)?,
58 ];
59 Chord::new(notes.as_slice())
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 fn pitch(name: &str) -> Pitch {
68 Pitch::from_name(name).expect("valid pitch")
69 }
70
71 #[test]
72 fn diatonic_scale_degree_lookup() {
73 let scale = DiatonicScale::new(pitch("A4"), 0, "minor");
74 assert_eq!(scale.pitch_from_degree(1).unwrap().name_with_octave(), "A4");
75 assert_eq!(scale.pitch_from_degree(3).unwrap().name_with_octave(), "C5");
76 assert_eq!(scale.pitch_from_degree(7).unwrap().name_with_octave(), "G5");
77 }
78
79 #[test]
80 fn diatonic_scale_degree_chords() {
81 let scale = DiatonicScale::new(pitch("C4"), 0, "major");
82 assert_eq!(
83 scale.triad_from_degree(1).unwrap().pitched_common_name(),
84 "C-major triad"
85 );
86 assert_eq!(
87 scale
88 .seventh_chord_from_degree(5)
89 .unwrap()
90 .pitched_common_name(),
91 "G-dominant seventh chord"
92 );
93 }
94}