use crate::util;
#[derive(PartialEq, Clone, Copy)]
pub enum Scale {
Major,
Minor,
Harmonicminor,
Melodicminor,
Dorian,
Phrygian,
Lydian,
Locrian,
Mixolydian,
Overtone,
Augmented,
Wholetone,
Pentatonic,
Chromatic,
}
impl Into<String> for Scale {
fn into(self) -> String {
match self {
Scale::Major => "major",
Scale::Minor => "minor",
Scale::Harmonicminor => "harmonicminor",
Scale::Melodicminor => "melodicminor",
Scale::Dorian => "dorian",
Scale::Phrygian => "phrygian",
Scale::Lydian => "lydian",
Scale::Locrian => "locrian",
Scale::Mixolydian => "mixolydian",
Scale::Overtone => "overtone",
Scale::Augmented => "augmented",
Scale::Wholetone => "wholetone",
Scale::Pentatonic => "pentatonic",
Scale::Chromatic => "chromatic",
}
.into()
}
}
impl From<String> for Scale {
fn from(s: String) -> Self {
match &s[..] {
"major" => Scale::Major,
"minor" => Scale::Minor,
"harmonicminor" => Scale::Harmonicminor,
"melodicminor" => Scale::Melodicminor,
"dorian" => Scale::Dorian,
"phrygian" => Scale::Phrygian,
"lydian" => Scale::Lydian,
"locrian" => Scale::Locrian,
"mixolydian" => Scale::Mixolydian,
"overtone" => Scale::Overtone,
"augmented" => Scale::Augmented,
"wholetone" => Scale::Wholetone,
"pentatonic" => Scale::Pentatonic,
_ => Scale::Chromatic,
}
}
}
pub fn chromatic_notes(root: (char, i8)) -> Vec<(char, i8)> {
let mut v = vec![];
v.push(('a', 0));
v.push(('a', 1));
v.push(('b', 0));
v.push(('c', 0));
v.push(('c', 1));
v.push(('d', 0));
v.push(('d', 1));
v.push(('e', 0));
v.push(('f', 0));
v.push(('f', 1));
v.push(('g', 0));
v.push(('g', 1));
let root_index = v
.iter()
.position(|¬e| note == root || note == util::alt_note(root))
.unwrap();
let a = v[..root_index].to_vec();
let b = v[root_index..].to_vec();
let mut v = vec![];
v.extend(b);
v.extend(a);
v
}
pub fn print_supported_scales() {
println!("Supported scales:");
for scale in supported_scales() {
println!("\t{}", scale);
}
println!("Custom scale syntax: --scale 1,2,1,3,2,1");
}
pub fn supported_scales() -> Vec<String> {
vec![
"major",
"minor",
"harmonicminor",
"melodicminor",
"dorian",
"phrygian",
"lydian",
"locrian",
"mixolydian",
"overtone",
"augmented",
"wholetone",
"pentatonic",
]
.iter()
.map(|s| s.to_string())
.collect()
}
pub fn get_scale(scale: &str) -> Vec<u8> {
vec_sum(match scale {
"major" | "ionian" => vec![2, 2, 1, 2, 2, 2, 1],
"minor" | "naturalminor" | "aeolian" => vec![2, 1, 2, 2, 1, 2, 2],
"harmonicminor" => vec![2, 1, 2, 2, 1, 3, 1],
"melodicminor" => vec![2, 1, 2, 2, 2, 2],
"dorian" => vec![2, 1, 2, 2, 2, 1, 2],
"phrygian" => vec![1, 2, 2, 2, 1, 2, 2],
"lydian" => vec![2, 2, 2, 1, 2, 2, 1],
"locrian" => vec![1, 2, 2, 1, 2, 2, 2],
"mixolydian" => vec![2, 2, 1, 2, 2, 1, 2],
"overtone" => vec![2, 2, 2, 1, 2, 1],
"augmented" => vec![1, 3, 1, 3, 1],
"wholetone" => vec![2, 2, 2, 2, 2, 2],
"pentatonic" => vec![2, 2, 3, 2],
"chromatic" => vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
_ => parse_scale(scale),
})
}
fn parse_scale(scalestr: &str) -> Vec<u8> {
scalestr
.split(",")
.map(|s| s.parse::<u8>().unwrap_or(1))
.collect()
}
fn vec_sum(interval: Vec<u8>) -> Vec<u8> {
let mut vec: Vec<u8> = vec![0];
vec.extend(interval.into_iter().scan(0, |sum, step| {
*sum = *sum + step;
Some(*sum)
}));
vec
}
pub fn friendly_name(name: &str) -> String {
String::from(match name {
"major" => "Major",
"minor" | "naturalminor" => "Natural minor",
"hmin" | "harmonicminor" => "Harmonic minor",
"augmented" => "Augmented",
"wholetone" => "Wholetone",
"melodicminor" => "Melodic minor",
"overtone" => "Overtone",
"chromatic" => "Chromatic",
_ => name,
})
}