Skip to main content

klib/core/
scale.rs

1//! A module for working with scales.
2
3use std::fmt::{Display, Error, Formatter};
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use pest::Parser;
9
10use crate::core::{
11    base::{HasDescription, HasName, HasPreciseName, HasStaticName, Parsable, Res},
12    chord::HasRoot,
13    interval::{HasIntervals, Interval},
14    note::Note,
15    parser::{note_str_to_note, scale_name_str_to_scale_kind, ChordParser, Rule},
16    scale_kind::ScaleKind,
17};
18
19// Traits.
20
21/// A trait that represents a type that has a scale kind.
22pub trait HasScaleKind {
23    /// Returns the scale kind of the implementor (most likely a [`Scale`]).
24    fn kind(&self) -> ScaleKind;
25}
26
27// Struct.
28
29/// A scale with a root note.
30///
31/// This combines a root note with a scale kind to produce an actual scale
32/// with specific notes.
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34#[derive(PartialEq, Eq, Copy, Clone, Debug)]
35pub struct Scale {
36    /// The root note of the scale.
37    root: Note,
38    /// The kind of scale.
39    kind: ScaleKind,
40}
41
42// Impls.
43
44impl Scale {
45    /// Creates a new scale with the given root note and scale kind.
46    pub fn new(root: Note, kind: ScaleKind) -> Self {
47        Self { root, kind }
48    }
49
50    /// Returns the intervals of this scale (delegates to the scale kind).
51    pub fn intervals(&self) -> &'static [Interval] {
52        self.kind.intervals()
53    }
54
55    /// Returns the notes of this scale (root + each interval).
56    pub fn notes(&self) -> Vec<Note> {
57        self.intervals().iter().map(|&interval| self.root + interval).collect()
58    }
59}
60
61impl HasRoot for Scale {
62    fn root(&self) -> Note {
63        self.root
64    }
65}
66
67impl HasScaleKind for Scale {
68    fn kind(&self) -> ScaleKind {
69        self.kind
70    }
71}
72
73impl HasIntervals for Scale {
74    fn intervals(&self) -> &'static [Interval] {
75        self.kind.intervals()
76    }
77}
78
79impl HasStaticName for Scale {
80    fn static_name(&self) -> &'static str {
81        self.kind.static_name()
82    }
83}
84
85impl HasName for Scale {
86    fn name(&self) -> String {
87        format!("{} {}", self.root.static_name(), self.kind.static_name())
88    }
89}
90
91impl HasPreciseName for Scale {
92    fn precise_name(&self) -> String {
93        format!("{} {}", self.root.name(), self.kind.static_name())
94    }
95}
96
97impl HasDescription for Scale {
98    fn description(&self) -> &'static str {
99        self.kind.description()
100    }
101}
102
103impl Display for Scale {
104    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
105        let notes = self.notes().iter().map(|n| n.static_name()).collect::<Vec<_>>().join(", ");
106        write!(f, "{}\n   {}\n   {}", self.name(), self.description(), notes)
107    }
108}
109
110impl Parsable for Scale {
111    fn parse(input: &str) -> Res<Self>
112    where
113        Self: Sized,
114    {
115        let root = ChordParser::parse(Rule::scale, input)?.next().unwrap();
116
117        assert_eq!(Rule::scale, root.as_rule());
118
119        let mut components = root.into_inner();
120
121        let note = components.next().unwrap();
122        assert_eq!(Rule::note_atomic, note.as_rule());
123        let root_note = note_str_to_note(note.as_str().trim())?;
124
125        let scale_name = components.next().unwrap();
126        assert_eq!(Rule::scale_name, scale_name.as_rule());
127        let scale_kind = scale_name_str_to_scale_kind(scale_name.as_str())?;
128
129        Ok(Scale::new(root_note, scale_kind))
130    }
131}
132
133// Tests.
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use crate::core::named_pitch::{HasLetter, HasNamedPitch};
139    use crate::core::note::*;
140    use pretty_assertions::assert_eq;
141
142    impl Scale {
143        /// Validates that the scale has correct enharmonic spelling.
144        ///
145        /// For 7-note scales (major, natural minor, harmonic minor, melodic minor, modes),
146        /// each letter A-G should appear exactly once.
147        /// For other scales, no letter should repeat unless it's a chromatic/octatonic/blues exception.
148        /// Blues scale duplicates the 4th degree letter (e.g., F and F# in C blues).
149        ///
150        /// This is a test-only helper and is only compiled when running tests.
151        pub(crate) fn validate_spelling(&self) -> Result<(), String> {
152            use crate::core::named_pitch::{HasLetter, HasNamedPitch};
153            use std::collections::HashMap;
154
155            let notes = self.notes();
156            let intervals_count = self.intervals().len();
157
158            // For chromatic scale (12 notes), octatonic (8 notes), and blues (6 notes with ♯4 duplicating 4th degree), we allow letter repeats
159            if intervals_count == 12 || intervals_count == 8 || self.kind() == ScaleKind::Blues {
160                return Ok(());
161            }
162
163            // Check for letter uniqueness
164            let mut letter_counts: HashMap<&str, usize> = HashMap::new();
165            for note in &notes {
166                let letter = note.named_pitch().letter();
167                *letter_counts.entry(letter).or_insert(0) += 1;
168            }
169
170            // For 7-note collections, we expect exactly one of each letter
171            if intervals_count == 7 {
172                if letter_counts.len() != 7 {
173                    return Err(format!(
174                        "{} {} has {} unique letters, expected 7. Letters: {:?}",
175                        self.root().static_name(),
176                        self.kind().static_name(),
177                        letter_counts.len(),
178                        notes.iter().map(|n| n.static_name()).collect::<Vec<_>>()
179                    ));
180                }
181
182                for (letter, count) in &letter_counts {
183                    if *count != 1 {
184                        return Err(format!(
185                            "{} {} has letter {} appearing {} times, expected 1. Notes: {:?}",
186                            self.root().static_name(),
187                            self.kind().static_name(),
188                            letter,
189                            count,
190                            notes.iter().map(|n| n.static_name()).collect::<Vec<_>>()
191                        ));
192                    }
193                }
194            } else {
195                // For non-7-note collections (pentatonic, whole tone), just check no duplicates
196                for (letter, count) in &letter_counts {
197                    if *count > 1 {
198                        return Err(format!(
199                            "{} {} has letter {} appearing {} times. Notes: {:?}",
200                            self.root().static_name(),
201                            self.kind().static_name(),
202                            letter,
203                            count,
204                            notes.iter().map(|n| n.static_name()).collect::<Vec<_>>()
205                        ));
206                    }
207                }
208            }
209
210            Ok(())
211        }
212    }
213
214    #[test]
215    fn test_scale_creation() {
216        let scale = Scale::new(C, ScaleKind::Major);
217        assert_eq!(scale.root(), C);
218        assert_eq!(scale.kind(), ScaleKind::Major);
219    }
220
221    #[test]
222    fn test_scale_intervals() {
223        let scale = Scale::new(C, ScaleKind::Major);
224        assert_eq!(scale.intervals().len(), 7);
225        assert_eq!(
226            scale.intervals(),
227            &[
228                Interval::PerfectUnison,
229                Interval::MajorSecond,
230                Interval::MajorThird,
231                Interval::PerfectFourth,
232                Interval::PerfectFifth,
233                Interval::MajorSixth,
234                Interval::MajorSeventh,
235            ]
236        );
237    }
238
239    #[test]
240    fn test_scale_notes() {
241        // C major scale
242        let scale = Scale::new(C, ScaleKind::Major);
243        assert_eq!(scale.notes(), vec![C, D, E, F, G, A, B]);
244
245        // D major scale
246        let scale = Scale::new(D, ScaleKind::Major);
247        assert_eq!(scale.notes(), vec![D, E, FSharp, G, A, B, CSharpFive]);
248
249        // A natural minor scale
250        let scale = Scale::new(A, ScaleKind::NaturalMinor);
251        assert_eq!(scale.notes(), vec![A, B, CFive, DFive, EFive, FFive, GFive]);
252
253        // A harmonic minor scale
254        let scale = Scale::new(A, ScaleKind::HarmonicMinor);
255        assert_eq!(scale.notes(), vec![A, B, CFive, DFive, EFive, FFive, GSharpFive]);
256
257        // A melodic minor scale
258        let scale = Scale::new(A, ScaleKind::MelodicMinor);
259        assert_eq!(scale.notes(), vec![A, B, CFive, DFive, EFive, FSharpFive, GSharpFive]);
260
261        // C whole tone scale
262        let scale = Scale::new(C, ScaleKind::WholeTone);
263        assert_eq!(scale.notes(), vec![C, D, E, FSharp, GSharp, ASharp]);
264
265        // C chromatic scale
266        let scale = Scale::new(C, ScaleKind::Chromatic);
267        assert_eq!(scale.notes().len(), 12);
268    }
269
270    #[test]
271    fn test_scale_names() {
272        let scale = Scale::new(C, ScaleKind::Major);
273        assert_eq!(scale.name(), "C major");
274        assert_eq!(scale.static_name(), "major");
275
276        let scale = Scale::new(DFlat, ScaleKind::HarmonicMinor);
277        assert_eq!(scale.name(), "D♭ harmonic minor");
278
279        let scale = Scale::new(FSharp, ScaleKind::WholeTone);
280        assert_eq!(scale.name(), "F♯ whole tone");
281    }
282
283    #[test]
284    fn test_scale_display() {
285        let scale = Scale::new(C, ScaleKind::Major);
286        let display = format!("{}", scale);
287        assert!(display.contains("C major"));
288        assert!(display.contains("C, D, E, F, G, A, B"));
289    }
290
291    #[test]
292    fn test_different_roots() {
293        // G major has one sharp (F#)
294        let scale = Scale::new(G, ScaleKind::Major);
295        assert_eq!(scale.notes(), vec![G, A, B, CFive, DFive, EFive, FSharpFive]);
296
297        // F major has one flat (Bb)
298        let scale = Scale::new(F, ScaleKind::Major);
299        assert_eq!(scale.notes(), vec![F, G, A, BFlat, CFive, DFive, EFive]);
300
301        // E natural minor
302        let scale = Scale::new(E, ScaleKind::NaturalMinor);
303        assert_eq!(scale.notes(), vec![E, FSharp, G, A, B, CFive, DFive]);
304    }
305
306    #[test]
307    fn test_scale_parse() {
308        // Test parsing various scales
309        let scale = Scale::parse("C major").unwrap();
310        assert_eq!(scale.root(), C);
311        assert_eq!(scale.kind(), ScaleKind::Major);
312
313        let scale = Scale::parse("A natural minor").unwrap();
314        assert_eq!(scale.root(), A);
315        assert_eq!(scale.kind(), ScaleKind::NaturalMinor);
316
317        let scale = Scale::parse("A naturalminor").unwrap();
318        assert_eq!(scale.root(), A);
319        assert_eq!(scale.kind(), ScaleKind::NaturalMinor);
320
321        let scale = Scale::parse("A harmonic minor").unwrap();
322        assert_eq!(scale.root(), A);
323        assert_eq!(scale.kind(), ScaleKind::HarmonicMinor);
324
325        let scale = Scale::parse("A melodic minor").unwrap();
326        assert_eq!(scale.root(), A);
327        assert_eq!(scale.kind(), ScaleKind::MelodicMinor);
328
329        let scale = Scale::parse("C whole tone").unwrap();
330        assert_eq!(scale.root(), C);
331        assert_eq!(scale.kind(), ScaleKind::WholeTone);
332
333        let scale = Scale::parse("C chromatic").unwrap();
334        assert_eq!(scale.root(), C);
335        assert_eq!(scale.kind(), ScaleKind::Chromatic);
336
337        // Test with accidentals
338        let scale = Scale::parse("F# major").unwrap();
339        assert_eq!(scale.root(), FSharp);
340        assert_eq!(scale.kind(), ScaleKind::Major);
341
342        let scale = Scale::parse("Bb harmonic minor").unwrap();
343        assert_eq!(scale.root(), BFlat);
344        assert_eq!(scale.kind(), ScaleKind::HarmonicMinor);
345
346        // Test pentatonic scales
347        let scale = Scale::parse("C major pentatonic").unwrap();
348        assert_eq!(scale.root(), C);
349        assert_eq!(scale.kind(), ScaleKind::MajorPentatonic);
350
351        let scale = Scale::parse("C majorpentatonic").unwrap();
352        assert_eq!(scale.root(), C);
353        assert_eq!(scale.kind(), ScaleKind::MajorPentatonic);
354
355        let scale = Scale::parse("A minor pentatonic").unwrap();
356        assert_eq!(scale.root(), A);
357        assert_eq!(scale.kind(), ScaleKind::MinorPentatonic);
358
359        let scale = Scale::parse("A minorpentatonic").unwrap();
360        assert_eq!(scale.root(), A);
361        assert_eq!(scale.kind(), ScaleKind::MinorPentatonic);
362
363        // Test blues scale
364        let scale = Scale::parse("C blues").unwrap();
365        assert_eq!(scale.root(), C);
366        assert_eq!(scale.kind(), ScaleKind::Blues);
367
368        let scale = Scale::parse("E blues").unwrap();
369        assert_eq!(scale.root(), E);
370        assert_eq!(scale.kind(), ScaleKind::Blues);
371    }
372
373    #[test]
374    fn test_enharmonic_spelling_major_scales() {
375        // Test major scales with various roots to ensure correct enharmonic spelling
376
377        // C Major - all natural notes
378        let scale = Scale::new(C, ScaleKind::Major);
379        scale.validate_spelling().unwrap();
380
381        // G Major - should be G A B C D E F#
382        let scale = Scale::new(G, ScaleKind::Major);
383        scale.validate_spelling().unwrap();
384        let notes = scale.notes();
385        assert_eq!(notes.len(), 7);
386
387        // Db Major - should use flats: Db Eb F Gb Ab Bb C
388        let scale = Scale::new(DFlat, ScaleKind::Major);
389        scale.validate_spelling().unwrap();
390        let notes = scale.notes();
391        assert_eq!(notes[0].named_pitch().letter(), "D");
392        assert_eq!(notes[1].named_pitch().letter(), "E");
393        assert_eq!(notes[2].named_pitch().letter(), "F");
394        assert_eq!(notes[3].named_pitch().letter(), "G");
395        assert_eq!(notes[4].named_pitch().letter(), "A");
396        assert_eq!(notes[5].named_pitch().letter(), "B");
397        assert_eq!(notes[6].named_pitch().letter(), "C");
398
399        // F# Major - should use sharps: F# G# A# B C# D# E#
400        let scale = Scale::new(FSharp, ScaleKind::Major);
401        scale.validate_spelling().unwrap();
402        let notes = scale.notes();
403        assert_eq!(notes[0].named_pitch().letter(), "F");
404        assert_eq!(notes[1].named_pitch().letter(), "G");
405        assert_eq!(notes[2].named_pitch().letter(), "A");
406        assert_eq!(notes[3].named_pitch().letter(), "B");
407        assert_eq!(notes[4].named_pitch().letter(), "C");
408        assert_eq!(notes[5].named_pitch().letter(), "D");
409        assert_eq!(notes[6].named_pitch().letter(), "E");
410    }
411
412    #[test]
413    fn test_enharmonic_spelling_minor_scales() {
414        // Test minor scales
415
416        // A Natural Minor
417        let scale = Scale::new(A, ScaleKind::NaturalMinor);
418        scale.validate_spelling().unwrap();
419
420        // A Harmonic Minor - A B C D E F G#
421        let scale = Scale::new(A, ScaleKind::HarmonicMinor);
422        scale.validate_spelling().unwrap();
423        let notes = scale.notes();
424        assert_eq!(notes[6].named_pitch().letter(), "G"); // Should be G#, not Ab
425
426        // C# Harmonic Minor
427        let scale = Scale::new(CSharp, ScaleKind::HarmonicMinor);
428        scale.validate_spelling().unwrap();
429
430        // F Melodic Minor
431        let scale = Scale::new(F, ScaleKind::MelodicMinor);
432        scale.validate_spelling().unwrap();
433    }
434
435    #[test]
436    fn test_enharmonic_spelling_pentatonic_scales() {
437        // Test pentatonic scales (5 notes, no letter repeats)
438
439        // C Major Pentatonic - C D E G A
440        let scale = Scale::new(C, ScaleKind::MajorPentatonic);
441        scale.validate_spelling().unwrap();
442        let notes = scale.notes();
443        assert_eq!(notes.len(), 5);
444
445        // A Minor Pentatonic - A C D E G
446        let scale = Scale::new(A, ScaleKind::MinorPentatonic);
447        scale.validate_spelling().unwrap();
448        let notes = scale.notes();
449        assert_eq!(notes.len(), 5);
450
451        // F# Major Pentatonic
452        let scale = Scale::new(FSharp, ScaleKind::MajorPentatonic);
453        scale.validate_spelling().unwrap();
454
455        // Bb Minor Pentatonic
456        let scale = Scale::new(BFlat, ScaleKind::MinorPentatonic);
457        scale.validate_spelling().unwrap();
458    }
459
460    #[test]
461    fn test_enharmonic_spelling_blues_scale() {
462        // Test blues scale (6 notes, allows letter duplication on 4th degree)
463
464        // C Blues - C Eb F F# G Bb (F and F# both present)
465        let scale = Scale::new(C, ScaleKind::Blues);
466        scale.validate_spelling().unwrap();
467        let notes = scale.notes();
468        assert_eq!(notes.len(), 6);
469
470        // E Blues
471        let scale = Scale::new(E, ScaleKind::Blues);
472        scale.validate_spelling().unwrap();
473
474        // G Blues
475        let scale = Scale::new(G, ScaleKind::Blues);
476        scale.validate_spelling().unwrap();
477    }
478
479    #[test]
480    fn test_enharmonic_spelling_whole_tone() {
481        // Test whole tone scale (6 notes, no letter repeats)
482
483        // C Whole Tone - C D E F# G# A#
484        let scale = Scale::new(C, ScaleKind::WholeTone);
485        scale.validate_spelling().unwrap();
486        let notes = scale.notes();
487        assert_eq!(notes.len(), 6);
488
489        // Db Whole Tone
490        let scale = Scale::new(DFlat, ScaleKind::WholeTone);
491        scale.validate_spelling().unwrap();
492    }
493
494    #[test]
495    fn test_enharmonic_spelling_diminished() {
496        // Diminished scales are octatonic (8 notes), so we allow letter repeats
497
498        // C Diminished Whole-Half
499        let scale = Scale::new(C, ScaleKind::DiminishedWholeHalf);
500        scale.validate_spelling().unwrap(); // Should pass even with repeats
501        let notes = scale.notes();
502        assert_eq!(notes.len(), 8);
503
504        // C Diminished Half-Whole
505        let scale = Scale::new(C, ScaleKind::DiminishedHalfWhole);
506        scale.validate_spelling().unwrap(); // Should pass even with repeats
507        let notes = scale.notes();
508        assert_eq!(notes.len(), 8);
509    }
510
511    #[test]
512    fn test_enharmonic_spelling_chromatic() {
513        // Chromatic scale (12 notes), we allow letter repeats
514
515        // C Chromatic
516        let scale = Scale::new(C, ScaleKind::Chromatic);
517        scale.validate_spelling().unwrap(); // Should pass even with repeats
518        let notes = scale.notes();
519        assert_eq!(notes.len(), 12);
520    }
521
522    #[test]
523    fn test_enharmonic_spelling_all_roots() {
524        // Test all scales with multiple root notes to ensure consistency
525        for root in [C, CSharp, D, DFlat, E, F, FSharp, G, GFlat, A, AFlat, B, BFlat] {
526            // Major
527            let scale = Scale::new(root, ScaleKind::Major);
528            scale.validate_spelling().unwrap_or_else(|e| panic!("Major spelling failed for {}: {}", root.static_name(), e));
529
530            // Natural Minor
531            let scale = Scale::new(root, ScaleKind::NaturalMinor);
532            scale.validate_spelling().unwrap_or_else(|e| panic!("Natural Minor spelling failed for {}: {}", root.static_name(), e));
533
534            // Harmonic Minor
535            let scale = Scale::new(root, ScaleKind::HarmonicMinor);
536            scale.validate_spelling().unwrap_or_else(|e| panic!("Harmonic Minor spelling failed for {}: {}", root.static_name(), e));
537
538            // Major Pentatonic
539            let scale = Scale::new(root, ScaleKind::MajorPentatonic);
540            scale
541                .validate_spelling()
542                .unwrap_or_else(|e| panic!("Major Pentatonic spelling failed for {}: {}", root.static_name(), e));
543
544            // Blues
545            let scale = Scale::new(root, ScaleKind::Blues);
546            scale.validate_spelling().unwrap_or_else(|e| panic!("Blues spelling failed for {}: {}", root.static_name(), e));
547        }
548    }
549
550    #[test]
551    fn test_heptatonic_spelling() {
552        let scale = Scale::new(DFlat, ScaleKind::Major);
553        assert_eq!(scale.notes(), vec![DFlat, EFlat, F, GFlat, AFlat, BFlat, CFive], "Db major scale spelling incorrect");
554        scale.validate_spelling().unwrap();
555
556        let scale = Scale::new(CSharp, ScaleKind::Major);
557        assert_eq!(
558            scale.notes(),
559            vec![CSharp, DSharp, ESharp, FSharp, GSharp, ASharp, BSharp],
560            "C# major scale spelling incorrect - should use sharps consistently"
561        );
562        scale.validate_spelling().unwrap();
563    }
564
565    #[test]
566    fn test_whole_tone_spelling() {
567        let scale = Scale::new(A, ScaleKind::WholeTone);
568        assert_eq!(
569            scale.intervals(),
570            &[
571                Interval::PerfectUnison,
572                Interval::MajorSecond,
573                Interval::MajorThird,
574                Interval::AugmentedFourth,
575                Interval::AugmentedFifth,
576                Interval::AugmentedSixth,
577            ],
578            "Whole tone scale intervals should use augmented intervals, not respelled for prettiness"
579        );
580
581        let notes = scale.notes();
582        assert_eq!(notes.len(), 6, "Whole tone scale should have 6 notes");
583        scale.validate_spelling().unwrap();
584
585        let scale = Scale::new(FSharp, ScaleKind::WholeTone);
586        let notes = scale.notes();
587        assert_eq!(notes.len(), 6, "F# whole tone scale should have 6 notes");
588        scale.validate_spelling().unwrap();
589    }
590
591    #[test]
592    fn test_octatonic_spelling() {
593        let scale = Scale::new(A, ScaleKind::DiminishedHalfWhole);
594        let notes = scale.notes();
595        assert_eq!(
596            scale.intervals(),
597            &[
598                Interval::PerfectUnison,
599                Interval::MinorSecond,
600                Interval::MinorThird,
601                Interval::MajorThird,
602                Interval::AugmentedFourth,
603                Interval::PerfectFifth,
604                Interval::MajorSixth,
605                Interval::MinorSeventh,
606            ]
607        );
608        assert_eq!(notes.len(), 8, "Diminished half-whole should have 8 notes");
609
610        let scale = Scale::new(A, ScaleKind::DiminishedWholeHalf);
611        let notes = scale.notes();
612        assert_eq!(
613            scale.intervals(),
614            &[
615                Interval::PerfectUnison,
616                Interval::MajorSecond,
617                Interval::MinorThird,
618                Interval::PerfectFourth,
619                Interval::DiminishedFifth,
620                Interval::MinorSixth,
621                Interval::DiminishedSeventh,
622                Interval::MajorSeventh,
623            ]
624        );
625        assert_eq!(notes.len(), 8, "Diminished whole-half should have 8 notes");
626    }
627
628    #[test]
629    fn test_pentatonic_blues_spelling() {
630        let scale = Scale::new(DFlat, ScaleKind::MajorPentatonic);
631        assert_eq!(scale.notes(), vec![DFlat, EFlat, F, AFlat, BFlat], "Db major pentatonic spelling incorrect");
632        scale.validate_spelling().unwrap();
633
634        let scale = Scale::new(A, ScaleKind::MinorPentatonic);
635        assert_eq!(scale.notes(), vec![A, CFive, DFive, EFive, GFive], "A minor pentatonic spelling incorrect");
636        scale.validate_spelling().unwrap();
637
638        let scale = Scale::new(FSharp, ScaleKind::Blues);
639        let notes = scale.notes();
640        assert_eq!(
641            notes,
642            vec![FSharp, A, B, BSharp, CSharpFive, EFive],
643            "F# blues scale spelling incorrect - should use B# (augmented 4th), not C (diminished 5th)"
644        );
645        assert_eq!(
646            scale.intervals(),
647            &[
648                Interval::PerfectUnison,
649                Interval::MinorThird,
650                Interval::PerfectFourth,
651                Interval::AugmentedFourth,
652                Interval::PerfectFifth,
653                Interval::MinorSeventh,
654            ]
655        );
656        scale.validate_spelling().unwrap();
657    }
658}