TimeSignature parsing

This commit is contained in:
Denis Redozubov 2023-06-07 13:47:57 +04:00
parent e843a98876
commit 02bb26516e
3 changed files with 65 additions and 23 deletions

View file

@ -1,5 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::process::exit; use std::process::exit;
use std::str::FromStr;
use poly::dsl::dsl; use poly::dsl::dsl;
use poly::midi::core::{Part, create_smf}; use poly::midi::core::{Part, create_smf};
@ -73,16 +74,18 @@ fn main() {
validate_and_parse_part(hihat, Part::HiHat, &mut groups); validate_and_parse_part(hihat, Part::HiHat, &mut groups);
validate_and_parse_part(crash, Part::CrashCymbal, &mut groups); validate_and_parse_part(crash, Part::CrashCymbal, &mut groups);
// TODO let signature = match TimeSignature::from_str(&time_signature) {
let time_signature = TimeSignature { numerator: 4, denominator: dsl::BasicLength::Fourth }; Err(e) => panic!("Can't parse the time signature: {}", e),
Ok(x) => x
};
match output { match output {
None => { None => {
println!("No output file path was supplied, running a dry run..."); println!("No output file path was supplied, running a dry run...");
create_smf(groups, time_signature) create_smf(groups, signature)
}, },
Some(path) => { Some(path) => {
match create_smf(groups, time_signature).save(path.clone()) { match create_smf(groups, signature).save(path.clone()) {
Ok(_) => { Ok(_) => {
println!("{} was written successfully", path); println!("{} was written successfully", path);
exit(0) exit(0)

View file

@ -1,4 +1,5 @@
use std::str; use std::num::ParseIntError;
use std::str::{self, FromStr};
use std::vec::Vec; use std::vec::Vec;
use std::ops::{Add}; use std::ops::{Add};
@ -27,6 +28,18 @@ pub enum BasicLength {
SixtyFourth SixtyFourth
} }
impl FromStr for BasicLength {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let result: Result<u16, ParseIntError> = s.parse();
match result {
Ok(n) => Self::from_num(n),
Result::Err(e) => panic!("{}", e)
}
}
}
impl KnownLength for BasicLength { impl KnownLength for BasicLength {
fn to_128th(&self) -> u32 { fn to_128th(&self) -> u32 {
match self { match self {
@ -43,16 +56,16 @@ impl KnownLength for BasicLength {
impl BasicLength { impl BasicLength {
/// Unsafe method, so it should only be used from `add`. /// Unsafe method, so it should only be used from `add`.
fn from_num(n: u16) -> Self { fn from_num(n: u16) -> Result<Self, String> {
match n { match n {
1 => BasicLength::SixtyFourth, 1 => Ok(BasicLength::SixtyFourth),
2 => BasicLength::ThirtySecond, 2 => Ok(BasicLength::ThirtySecond),
4 => BasicLength::Sixteenth, 4 => Ok(BasicLength::Sixteenth),
8 => BasicLength::Eighth, 8 => Ok(BasicLength::Eighth),
16 => BasicLength::Fourth, 16 => Ok(BasicLength::Fourth),
32 => BasicLength::Half, 32 => Ok(BasicLength::Half),
64 => BasicLength::Whole, 64 => Ok(BasicLength::Whole),
e => panic!("{} is not a num BasicLength can be constructed from", e) e => Err(format!("{} is not a num BasicLength can be constructed from", e))
} }
} }
} }
@ -71,24 +84,24 @@ impl Add<BasicLength> for BasicLength {
BasicLength::SixtyFourth => 1, BasicLength::SixtyFourth => 1,
}; };
if self == rhs && self != BasicLength::Whole { if self == rhs && self != BasicLength::Whole {
Length::Simple(ModdedLength::Plain(BasicLength::from_num(f(self) * 2))) Length::Simple(ModdedLength::Plain(BasicLength::from_num(f(self) * 2).unwrap()))
} else { } else {
let n1 : u16 = f(self); let n1 : u16 = f(self);
let n2 = f(rhs); let n2 = f(rhs);
let total = n1 + n2; let total = n1 + n2;
if total > 64 { if total > 64 {
Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_num(total - 64))) Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_num(total - 64).unwrap()))
} else if total > 32 { } else if total > 32 {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 32))) Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 32).unwrap()))
} else if total > 16 { } else if total > 16 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 16))) Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 16).unwrap()))
} else if total > 8 { } else if total > 8 {
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_num(total - 8))) Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_num(total - 8).unwrap()))
} else if total > 4 { } else if total > 4 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 4))) Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 4).unwrap()))
} else { } else {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 2))) Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 2).unwrap()))
} }
} }
} }

View file

@ -3,6 +3,7 @@ use crate::dsl::dsl::{BasicLength, Group, GroupOrNote, KnownLength, Note, Times,
use std::cmp::Ordering; use std::cmp::Ordering;
use std; use std;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeSignature { pub struct TimeSignature {
@ -17,6 +18,31 @@ impl TimeSignature {
denominator, denominator,
} }
} }
}
impl FromStr for TimeSignature {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut after_split = s.splitn(2, '/');
let num = after_split.next();
let den = after_split.next();
match (num, den) {
(None, None) => Err(format!("Can't parse neither numerator nor denominator of a time signature: {}", s)),
(None, Some(_)) => Err(format!("Can't parse time signature numerator: {}", s)),
(Some(_), None) => Err(format!("Can't parse time signature denominator: {}", s)),
(Some(numerator_str), Some(d)) => {
match BasicLength::from_str(d) {
Ok(denominator) => match u8::from_str(numerator_str) {
Ok(numerator) => Ok(TimeSignature { numerator, denominator }),
Err(e) => Err(format!("Can't parse time signature numerator: {}", s)),
} ,
Err(e) => Err(e),
}
}
}
}
} }
impl std::ops::Mul<u8> for TimeSignature { impl std::ops::Mul<u8> for TimeSignature {
@ -56,10 +82,10 @@ impl KnownLength for TimeSignature {
} }
impl TimeSignature { impl TimeSignature {
pub fn converges<T: KnownLength>(&self, multiple: Vec<T>) -> Result<u32, String> { pub fn converges<T: KnownLength, I: IntoIterator<Item = T>>(&self, multiple: I) -> Result<u32, String> {
let bar_len = self.to_128th(); let bar_len = self.to_128th();
let result = multiple let result = multiple
.iter() .into_iter()
.fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc)); .fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc));
let limit = 1000; let limit = 1000;