crate::ix!();
#[derive(Debug,Clone)]
pub struct Scale {
pub name: String,
pub description: String,
pub raw_text: TuningData,
pub count: usize,
pub tones: Vec<Tone>,
}
impl Init for Scale {
fn init(&mut self) {
self.name = "empty scale".to_string();
self.description = "".to_string();
self.raw_text = TuningData("".to_string());
self.count = 0;
self.tones = vec![];
}
}
impl Default for Scale {
fn default() -> Self {
Self {
name: "empty scale".to_string(),
description: "".to_string(),
raw_text: TuningData("".to_string()),
count: 0,
tones: vec![],
}
}
}
impl<R: std::io::Read> From<&mut BufReader<R>> for Scale {
fn from(reader: &mut BufReader<R>) -> Self {
enhanced_enum![
ParsePosition {
ReadHeader,
ReadCount,
ReadNote,
}
];
impl ParsePosition {
pub fn next(&self) -> Self {
match self {
ParsePosition::ReadHeader => ParsePosition::ReadCount,
ParsePosition::ReadCount => ParsePosition::ReadNote,
ParsePosition::ReadNote => ParsePosition::ReadNote, }
}
}
let mut res = Scale::default();
let mut raw_oss = Vec::<u8>::new();
let mut state: ParsePosition = ParsePosition::ReadHeader;
let mut line: String = String::new();
while reader.read_line(&mut line).unwrap() != 0 {
let bytes = line.as_bytes();
let _written = raw_oss.write(bytes).unwrap();
let _written = raw_oss.write("\n".as_bytes()).unwrap();
if bytes[0] == "!".as_bytes()[0] {
continue;
}
let _i: i32 = line.parse::<i32>().unwrap();
let _v: f32 = line.parse::<f32>().unwrap();
match state {
ParsePosition::ReadHeader => {
res.description = line.clone();
},
ParsePosition::ReadCount => {
res.count = line.parse::<usize>().unwrap();
},
ParsePosition::ReadNote => {
let mut t = Tone {
repr: line.clone(),
.. Default::default()
};
if let Some(_pos) = line.find('.') {
t.ty = ToneType::Cents;
t.cents = line.parse::<f32>().unwrap();
} else {
t.ty = ToneType::Ratio;
if let Some(slash_pos) = line.find('/') {
t.ratio_n = line[0..slash_pos].parse::<i32>().unwrap() as f32;
t.ratio_d = line[slash_pos..].parse::<i32>().unwrap() as f32;
} else {
t.ratio_n = line.parse::<i32>().unwrap() as f32;
t.ratio_d = 1.0;
}
t.cents = 1200.0 * (1.0 * t.ratio_n / t.ratio_d).log2();
}
t.val = t.cents / 1200.0 + 1.0;
res.tones.push(t);
},
}
state = state.next();
}
res.raw_text = TuningData(String::from_utf8(raw_oss).unwrap());
res
}
}
impl Scale {
pub fn is_valid(&self) -> bool {
if self.count == 0 {
return false;
}
true
}
pub fn even_temperament_12_note_scale() -> Scale {
let scl = crate::TWELVE_TONE_EQUAL_TEMPERAMENT.as_bytes();
let mut reader = BufReader::new(scl);
Scale::from(&mut reader)
}
pub fn scale_432() -> Scale {
let scl = crate::ED2_25.as_bytes();
let mut reader = BufReader::new(scl);
Scale::from(&mut reader)
}
}
impl fmt::Display for Scale {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
"Scale\n {}\n {}\n --- {} tones ---\n{:?}",
self.name,
self.description,
self.count,
self.tones)
}
}
impl From<SclFileName> for Scale {
fn from(x: SclFileName) -> Self {
let file = File::open(x.0).unwrap();
let mut reader = BufReader::new(file);
Self::from(&mut reader)
}
}
impl From<TuningData> for Scale {
fn from(x: TuningData) -> Self {
let mut reader = BufReader::new(x.0.as_bytes());
Self::from(&mut reader)
}
}