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