From 02bb26516ef407060cb6ddf92040d9b9f11bbf06 Mon Sep 17 00:00:00 2001 From: Denis Redozubov Date: Wed, 7 Jun 2023 13:47:57 +0400 Subject: [PATCH] TimeSignature parsing --- src/bin/main.rs | 11 +++++++---- src/dsl/dsl.rs | 47 ++++++++++++++++++++++++++++++----------------- src/midi/time.rs | 30 ++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index fbde342..8ea8e07 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -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) diff --git a/src/dsl/dsl.rs b/src/dsl/dsl.rs index 3d384d9..628ec69 100644 --- a/src/dsl/dsl.rs +++ b/src/dsl/dsl.rs @@ -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 { + let result: Result = 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 { 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 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())) } } } diff --git a/src/midi/time.rs b/src/midi/time.rs index 0ff3f3d..12ee071 100644 --- a/src/midi/time.rs +++ b/src/midi/time.rs @@ -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 { + 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 for TimeSignature { @@ -56,10 +82,10 @@ impl KnownLength for TimeSignature { } impl TimeSignature { - pub fn converges(&self, multiple: Vec) -> Result { + pub fn converges>(&self, multiple: I) -> Result { 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;