helpers for note length arithmetics

This commit is contained in:
Denis Redozubov 2023-05-11 13:56:12 +04:00
parent 69f389008c
commit f210b76454
2 changed files with 107 additions and 1 deletions

View file

@ -1,5 +1,6 @@
use std::str; use std::str;
use std::vec::Vec; use std::vec::Vec;
use std::ops::{Add, Mul};
pub use nom::character::complete::{char, digit1}; pub use nom::character::complete::{char, digit1};
use nom::multi::many1; use nom::multi::many1;
@ -20,6 +21,66 @@ pub enum BasicLength {
SixtyFourth SixtyFourth
} }
impl BasicLength {
/// Unsafe method, so it should only be used from `add`.
fn from_num(n: u16) -> Self {
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)
}
}
}
impl Add<BasicLength> for BasicLength {
type Output = Length;
fn add(self, rhs: BasicLength) -> Length {
let f = |x| match x {
BasicLength::Whole => 64,
BasicLength::Half => 32,
BasicLength::Fourth => 16,
BasicLength::Eighth => 8,
BasicLength::Sixteenth => 4,
BasicLength::ThirtySecond => 2,
BasicLength::SixtyFourth => 1,
};
if self == rhs && self != BasicLength::Whole {
Length::Simple(ModdedLength::Plain(BasicLength::from_num(f(self) * 2)))
} 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)))
} else if total > 32 {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 32)))
} else if total > 16 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 16)))
} else if total > 8 {
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_num(total - 8)))
} else if total > 4 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 4)))
} else {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 2)))
}
}
}
}
#[test]
fn test_add_basic_length() {
assert_eq!(BasicLength::Half + BasicLength::Half, Length::Simple(ModdedLength::Plain(BasicLength::Whole)));
assert_eq!(BasicLength::Whole + BasicLength::Whole, Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::Whole)));
assert_eq!(BasicLength::Half + BasicLength::SixtyFourth, Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::SixtyFourth)));
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModdedLength { pub enum ModdedLength {
Plain(BasicLength), Plain(BasicLength),
@ -33,6 +94,36 @@ pub enum Length {
Triplet(ModdedLength) Triplet(ModdedLength)
} }
// impl Length {
// fn from_group(group: Group) -> Self {
// let mut numerator = 0;
// for x in group.notes {
// match x {
// crate::dsl::dsl::GroupOrNote::SingleGroup(g) => {
// todo!()
// },
// crate::dsl::dsl::GroupOrNote::SingleNote(_) => {
// numerator = numerator + 1;
// },
// }
// }
// }
// }
impl Add<Length> for Length {
type Output = Self;
fn add(self, rhs: Length) -> Length {
match self {
Length::Simple(mlen) => todo!(),
Length::Tied(_, _) => todo!(),
Length::Triplet(_) => todo!(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Note { pub enum Note {
Hit, Hit,

View file

@ -1,7 +1,7 @@
extern crate derive_more; extern crate derive_more;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Add; use std::ops::{Add, Mul};
use midly::{live::LiveEvent, num::u15, Header, MidiMessage, Smf, Track}; use midly::{live::LiveEvent, num::u15, Header, MidiMessage, Smf, Track};
@ -52,6 +52,19 @@ pub struct TimeSignature {
pub denominator: BasicLength, pub denominator: BasicLength,
} }
impl TimeSignature {
pub fn new(numerator: u8, denominator: BasicLength) -> Self {
Self { numerator, denominator }
}
}
impl std::ops::Mul<u8> for TimeSignature {
type Output = TimeSignature;
fn mul(self, rhs: u8) -> TimeSignature {
TimeSignature { numerator: self.numerator * rhs as u8, denominator: self.denominator }
}
}
#[test] #[test]
fn test_cmp_time_signature() { fn test_cmp_time_signature() {
let three_sixteenth = TimeSignature { let three_sixteenth = TimeSignature {
@ -73,6 +86,8 @@ fn test_cmp_time_signature() {
} }
impl TimeSignature { impl TimeSignature {
/// Checks if these two signatures converges for the next 200 bars. /// Checks if these two signatures converges for the next 200 bars.
fn converges_with(&self, other: TimeSignature) -> Result<(u32, TimeSignature), String> { fn converges_with(&self, other: TimeSignature) -> Result<(u32, TimeSignature), String> {
let d: u32 = std::cmp::max(self.denominator, other.denominator) let d: u32 = std::cmp::max(self.denominator, other.denominator)