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::process::exit;
use std::str::FromStr;
use poly::dsl::dsl;
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(crash, Part::CrashCymbal, &mut groups);
// TODO
let time_signature = TimeSignature { numerator: 4, denominator: dsl::BasicLength::Fourth };
let signature = match TimeSignature::from_str(&time_signature) {
Err(e) => panic!("Can't parse the time signature: {}", e),
Ok(x) => x
};
match output {
None => {
println!("No output file path was supplied, running a dry run...");
create_smf(groups, time_signature)
create_smf(groups, signature)
},
Some(path) => {
match create_smf(groups, time_signature).save(path.clone()) {
match create_smf(groups, signature).save(path.clone()) {
Ok(_) => {
println!("{} was written successfully", path);
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::ops::{Add};
@ -27,6 +28,18 @@ pub enum BasicLength {
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 {
fn to_128th(&self) -> u32 {
match self {
@ -43,16 +56,16 @@ impl KnownLength for BasicLength {
impl BasicLength {
/// 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 {
1 => BasicLength::SixtyFourth,
2 => BasicLength::ThirtySecond,
4 => BasicLength::Sixteenth,
8 => BasicLength::Eighth,
16 => BasicLength::Fourth,
32 => BasicLength::Half,
64 => BasicLength::Whole,
e => panic!("{} is not a num BasicLength can be constructed from", e)
1 => Ok(BasicLength::SixtyFourth),
2 => Ok(BasicLength::ThirtySecond),
4 => Ok(BasicLength::Sixteenth),
8 => Ok(BasicLength::Eighth),
16 => Ok(BasicLength::Fourth),
32 => Ok(BasicLength::Half),
64 => Ok(BasicLength::Whole),
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,
};
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 {
let n1 : u16 = f(self);
let n2 = f(rhs);
let total = n1 + n2;
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 {
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 {
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 {
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 {
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 {
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;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeSignature {
@ -17,6 +18,31 @@ impl TimeSignature {
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 {
@ -56,10 +82,10 @@ impl KnownLength for 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 result = multiple
.iter()
.into_iter()
.fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc));
let limit = 1000;