1use pest_derive::Parser;
4
5use crate::core::{
6 base::Res,
7 mode_kind::ModeKind,
8 note::{self, Note},
9 octave::Octave,
10 scale_kind::ScaleKind,
11};
12
13#[derive(Parser)]
17#[grammar = "../chord.pest"]
18pub struct ChordParser;
19
20#[coverage(off)]
24pub fn note_str_to_note(note_str: &str) -> Res<Note> {
25 let chord = match note_str {
26 "A" => note::A,
27 "A#" | "A♯" => note::ASharp,
28 "A##" | "A𝄪" => note::ADoubleSharp,
29 "Ab" | "A♭" => note::AFlat,
30 "Abb" | "A𝄫" => note::ADoubleFlat,
31 "B" => note::B,
32 "B#" | "B♯" => note::BSharp,
33 "B##" | "B𝄪" => note::BDoubleSharp,
34 "Bb" | "B♭" => note::BFlat,
35 "Bbb" | "B𝄫" => note::BDoubleFlat,
36 "C" => note::C,
37 "C#" | "C♯" => note::CSharp,
38 "C##" | "C𝄪" => note::CDoubleSharp,
39 "Cb" | "C♭" => note::CFlat,
40 "Cbb" | "C𝄫" => note::CDoubleFlat,
41 "D" => note::D,
42 "D#" | "D♯" => note::DSharp,
43 "D##" | "D𝄪" => note::DDoubleSharp,
44 "Db" | "D♭" => note::DFlat,
45 "Dbb" | "D𝄫" => note::DDoubleFlat,
46 "E" => note::E,
47 "E#" | "E♯" => note::ESharp,
48 "E##" | "E𝄪" => note::EDoubleSharp,
49 "Eb" | "E♭" => note::EFlat,
50 "Ebb" | "E𝄫" => note::EDoubleFlat,
51 "F" => note::F,
52 "F#" | "F♯" => note::FSharp,
53 "F##" | "F𝄪" => note::FDoubleSharp,
54 "Fb" | "F♭" => note::FFlat,
55 "Fbb" | "F𝄫" => note::FDoubleFlat,
56 "G" => note::G,
57 "G#" | "G♯" => note::GSharp,
58 "G##" | "G𝄪" => note::GDoubleSharp,
59 "Gb" | "G♭" => note::GFlat,
60 "Gbb" | "G𝄫" => note::GDoubleFlat,
61 _ => return Err(crate::core::base::Err::msg("Please use fairly standard notes (e.g., don't use triple sharps / flats).")),
62 };
63
64 Ok(chord)
65}
66
67#[coverage(off)]
69pub fn octave_str_to_octave(note_str: &str) -> Res<Octave> {
70 let octave = match note_str {
71 "0" => Octave::Zero,
72 "1" => Octave::One,
73 "2" => Octave::Two,
74 "3" => Octave::Three,
75 "4" => Octave::Four,
76 "5" => Octave::Five,
77 "6" => Octave::Six,
78 "7" => Octave::Seven,
79 "8" => Octave::Eight,
80 "9" => Octave::Nine,
81 _ => return Err(crate::core::base::Err::msg("Please use a valid octave (0 - 9).")),
82 };
83
84 Ok(octave)
85}
86
87#[coverage(off)]
89pub fn mode_name_str_to_mode_kind(mode_str: &str) -> Res<ModeKind> {
90 let normalized = mode_str
91 .to_lowercase()
92 .replace("♮", "natural")
93 .replace("♯", "sharp")
94 .replace("#", "sharp")
95 .replace("♭", "flat")
96 .replace("b", "flat")
97 .replace(" ", "");
98
99 let mode = match normalized.as_str() {
100 "ionian" => ModeKind::Ionian,
102 "dorian" => ModeKind::Dorian,
103 "phrygian" => ModeKind::Phrygian,
104 "lydian" => ModeKind::Lydian,
105 "mixolydian" => ModeKind::Mixolydian,
106 "aeolian" => ModeKind::Aeolian,
107 "locrian" => ModeKind::Locrian,
108
109 "locriannatural6" | "locriannat6" => ModeKind::LocrianNatural6,
111 "ioniansharp5" | "ionianaugmented" | "majorsharp5" => ModeKind::IonianSharp5,
112 "doriansharp4" => ModeKind::DorianSharp4,
113 "phrygiandominant" | "spanishphrygian" | "phrygianmajor" => ModeKind::PhrygianDominant,
114 "lydiansharp2" => ModeKind::LydianSharp2,
115 "ultralocrian" => ModeKind::Ultralocrian,
116
117 "dorianflat2" | "phrygiannatural6" | "phrygiannat6" => ModeKind::DorianFlat2,
119 "lydianaugmented" | "lydiansharp5" => ModeKind::LydianAugmented,
120 "lydiandominant" | "lydianflat7" | "mixolydiansharp4" | "acoustic" | "acousticscale" => ModeKind::LydianDominant,
121 "mixolydianflat6" | "aeoliandominant" => ModeKind::MixolydianFlat6,
122 "locriannatural2" | "locriannat2" | "locriansharp2" => ModeKind::LocrianNatural2,
123 "altered" | "alteredscale" | "superlocrian" => ModeKind::Altered,
124
125 _ => return Err(crate::core::base::Err::msg("Unknown mode name")),
126 };
127
128 Ok(mode)
129}
130
131#[coverage(off)]
133pub fn scale_name_str_to_scale_kind(scale_str: &str) -> Res<ScaleKind> {
134 let normalized = scale_str.to_lowercase().replace(" ", "").replace("-", "");
135 let scale = match normalized.as_str() {
136 "major" => ScaleKind::Major,
137 "naturalminor" => ScaleKind::NaturalMinor,
138 "harmonicminor" => ScaleKind::HarmonicMinor,
139 "melodicminor" => ScaleKind::MelodicMinor,
140 "wholetone" => ScaleKind::WholeTone,
141 "chromatic" => ScaleKind::Chromatic,
142 "diminishedwholehalf" => ScaleKind::DiminishedWholeHalf,
143 "diminishedhalfwhole" => ScaleKind::DiminishedHalfWhole,
144 "majorpentatonic" => ScaleKind::MajorPentatonic,
145 "minorpentatonic" => ScaleKind::MinorPentatonic,
146 "blues" => ScaleKind::Blues,
147 _ => return Err(crate::core::base::Err::msg("Unknown scale name")),
148 };
149
150 Ok(scale)
151}