rust_music_theory/chord/
quality.rs

1use crate::chord::errors::ChordError;
2use lazy_static::lazy_static;
3use regex::{Match, Regex};
4use strum_macros::Display;
5
6lazy_static! {
7    static ref QUALITY_REGEXES: Vec<(Regex, Quality)> = {
8        use Quality::*;
9
10        vec![
11            (
12                Regex::new(r"^(M\s+|M$|(?i)maj|Maj|Major|major)").unwrap(),
13                Major,
14            ),
15            (
16                Regex::new(r"^(m\s+|m$|(?i)min|Min|Minor|minor)").unwrap(),
17                Minor,
18            ),
19            (Regex::new(r"(?i)^(diminished)").unwrap(), Diminished),
20            (Regex::new(r"(?i)^(augmented)").unwrap(), Augmented),
21            (
22                Regex::new(r"(?i)^(half\s*diminished|halfdiminished)").unwrap(),
23                HalfDiminished,
24            ),
25            (Regex::new(r"(?i)^(dominant)").unwrap(), Dominant),
26            (
27                Regex::new(r"(?i)^(sus2\s+|sus2$|suspended2)").unwrap(),
28                Suspended2,
29            ),
30            (
31                Regex::new(r"(?i)^(sus4\s+|sus4$|suspended4)").unwrap(),
32                Suspended4,
33            ),
34        ]
35    };
36}
37
38/// The quality of a chord.
39#[derive(Display, Debug, Clone, Copy, PartialEq)]
40pub enum Quality {
41    Major,
42    Minor,
43    Diminished,
44    Augmented,
45    HalfDiminished,
46    Dominant,
47    Suspended2,
48    Suspended4,
49}
50
51impl Quality {
52    /// Parse a quality from a regex.
53    pub fn from_regex(string: &str) -> Result<(Self, Option<Match>), ChordError> {
54        use Quality::*;
55
56        for (regex, quality_enum) in &*QUALITY_REGEXES {
57            let mode = regex.find(string.trim());
58
59            if let Some(quality_match) = mode {
60                return Ok((*quality_enum, Some(quality_match)));
61            };
62        }
63
64        Ok((Major, None))
65    }
66}