rust_music_theory/scale/
mode.rs1use crate::scale::errors::ScaleError;
2use crate::scale::errors::ScaleError::ModeFromRegex;
3use crate::scale::mode::Mode::*;
4use lazy_static::lazy_static;
5use regex::{Match, Regex};
6use strum_macros::{Display, EnumIter};
7
8lazy_static! {
9 static ref MODE_REGEXES: Vec<(Regex, Mode)> = vec![
10 (
11 Regex::new(r"^(M\s+|M$|(?i)maj|major|ionian)").unwrap(),
12 Ionian
13 ),
14 (
15 Regex::new(r"(?i)(har minor|harmonicminor|harmonic\s+minor)").unwrap(),
16 HarmonicMinor
17 ),
18 (
19 Regex::new(r"(?i)(mel minor|melodicminor|melodic\s+minor)").unwrap(),
20 MelodicMinor
21 ),
22 (
23 Regex::new(r"(?i)(pentatonic\s+major|pentatonic\s+maj|pent\s+maj|pent\s+major)").unwrap(),
24 PentatonicMajor
25 ),
26 (
27 Regex::new(r"(?i)(pentatonic\s+minor|pentatonic\s+min|pent\s+min|pent\s+minor)").unwrap(),
28 PentatonicMinor
29 ),
30 (
31 Regex::new(r"(?i)(blues)").unwrap(),
32 Blues
33 ),
34 (
35 Regex::new(r"(?i)(chromatic)").unwrap(),
36 Chromatic
37 ),
38 (
39 Regex::new(r"(?i)(whole\s+tone|wholetone)").unwrap(),
40 WholeTone
41 ),
42 (
43 Regex::new(r"^(m\s+|m$|(?i)min|minor|aeolian)").unwrap(),
44 Aeolian
45 ),
46 (Regex::new(r"(?i)^(dorian)").unwrap(), Dorian),
47 (Regex::new(r"(?i)^(locrian)").unwrap(), Locrian),
48 (Regex::new(r"(?i)^(mixolydian)").unwrap(), Mixolydian),
49 (Regex::new(r"(?i)^(phrygian)").unwrap(), Phrygian),
50 (Regex::new(r"(?i)^(lydian)").unwrap(), Lydian),
51 ];
52}
53
54#[derive(Display, Debug, Clone, Copy, EnumIter, PartialEq, Eq)]
56pub enum Mode {
57 Ionian,
59 Dorian,
60 Phrygian,
61 Lydian,
62 Mixolydian,
63 Aeolian,
65 Locrian,
66 HarmonicMinor,
67 MelodicMinor,
68 PentatonicMajor,
69 PentatonicMinor,
70 Blues,
71 Chromatic,
72 WholeTone,
73}
74
75impl Mode {
76 pub fn from_regex(string: &str) -> Result<(Self, Match), ScaleError> {
78 for (regex, mode_enum) in &*MODE_REGEXES {
79 let mode = regex.find(string.trim());
80
81 if let Some(mode_match) = mode {
82 return Ok((*mode_enum, mode_match));
83 };
84 }
85
86 Err(ModeFromRegex)
87 }
88
89 pub fn is_diatonic(self) -> bool {
91 !matches!(self, Self::HarmonicMinor | Self::MelodicMinor |
92 Self::PentatonicMajor | Self::PentatonicMinor |
93 Self::Blues | Self::Chromatic | Self::WholeTone)
94 }
95}