mirror of
https://github.com/dredozubov/polyrhythmix.git
synced 2024-11-22 11:57:43 +00:00
Group refactoring WIP: Broken parsing & tests
This commit is contained in:
parent
3bc67d66cc
commit
1582b47194
3 changed files with 494 additions and 154 deletions
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use poly::dsl::dsl::{self, KnownLength};
|
use poly::dsl::dsl::{self, KnownLength, flatten_groups};
|
||||||
use poly::midi::core::{create_smf, Part};
|
use poly::midi::core::{create_smf, Part};
|
||||||
use poly::midi::time::TimeSignature;
|
use poly::midi::time::TimeSignature;
|
||||||
|
|
||||||
|
@ -53,10 +53,10 @@ fn validate_and_parse_part(
|
||||||
match cli {
|
match cli {
|
||||||
None => {}
|
None => {}
|
||||||
Some(pattern) => match dsl::groups(pattern.as_str()) {
|
Some(pattern) => match dsl::groups(pattern.as_str()) {
|
||||||
Ok((_, group)) => {
|
Ok((_, groups)) => {
|
||||||
println!("{:?}: {:?}", part, group);
|
println!("{:?}: {:?}", part, groups);
|
||||||
println!("group to 128th: {}", group.to_128th());
|
// println!("group to 128th: {}", group.to_128th());
|
||||||
patterns.insert(part, group);
|
patterns.insert(part, groups);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
panic!("{} pattern is malformed.", part_to_string(part))
|
panic!("{} pattern is malformed.", part_to_string(part))
|
||||||
|
|
547
src/dsl/dsl.rs
547
src/dsl/dsl.rs
|
@ -1,17 +1,15 @@
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
use std::ops::Add;
|
||||||
use std::str::{self, FromStr};
|
use std::str::{self, FromStr};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use std::ops::{Add};
|
|
||||||
|
|
||||||
|
use nom::branch::alt;
|
||||||
pub use nom::character::complete::{char, digit1};
|
pub use nom::character::complete::{char, digit1};
|
||||||
use nom::multi::many1;
|
use nom::multi::many1;
|
||||||
use nom::sequence::{separated_pair, tuple, delimited};
|
use nom::sequence::{delimited, separated_pair, tuple};
|
||||||
use nom::{Err, IResult};
|
use nom::{Err, IResult};
|
||||||
use nom::branch::alt;
|
|
||||||
use nom::Err::Error;
|
|
||||||
|
|
||||||
use nom::combinator::{map, map_res, all_consuming};
|
|
||||||
|
|
||||||
|
use nom::combinator::{all_consuming, map, map_res};
|
||||||
|
|
||||||
/// Allows measurement in 128th notes.
|
/// Allows measurement in 128th notes.
|
||||||
pub trait KnownLength {
|
pub trait KnownLength {
|
||||||
|
@ -26,7 +24,7 @@ pub enum BasicLength {
|
||||||
Eighth,
|
Eighth,
|
||||||
Sixteenth,
|
Sixteenth,
|
||||||
ThirtySecond,
|
ThirtySecond,
|
||||||
SixtyFourth
|
SixtyFourth,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for BasicLength {
|
impl FromStr for BasicLength {
|
||||||
|
@ -36,7 +34,7 @@ impl FromStr for BasicLength {
|
||||||
let result: Result<u16, ParseIntError> = s.parse();
|
let result: Result<u16, ParseIntError> = s.parse();
|
||||||
match result {
|
match result {
|
||||||
Ok(n) => Self::from_num(n),
|
Ok(n) => Self::from_num(n),
|
||||||
Result::Err(e) => panic!("{}", e)
|
Result::Err(e) => panic!("{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +63,10 @@ impl BasicLength {
|
||||||
4 => Ok(BasicLength::Fourth),
|
4 => Ok(BasicLength::Fourth),
|
||||||
2 => Ok(BasicLength::Half),
|
2 => Ok(BasicLength::Half),
|
||||||
1 => Ok(BasicLength::Whole),
|
1 => Ok(BasicLength::Whole),
|
||||||
e => Err(format!("{} is not a num BasicLength can be constructed from", e))
|
e => Err(format!(
|
||||||
|
"{} is not a num BasicLength can be constructed from",
|
||||||
|
e
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,10 @@ impl BasicLength {
|
||||||
32 => Ok(BasicLength::Fourth),
|
32 => Ok(BasicLength::Fourth),
|
||||||
64 => Ok(BasicLength::Half),
|
64 => Ok(BasicLength::Half),
|
||||||
128 => Ok(BasicLength::Whole),
|
128 => Ok(BasicLength::Whole),
|
||||||
e => Err(format!("{} is not a num BasicLength can be constructed from", e))
|
e => Err(format!(
|
||||||
|
"{} is not a num BasicLength can be constructed from",
|
||||||
|
e
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,24 +103,44 @@ impl Add<BasicLength> for BasicLength {
|
||||||
BasicLength::SixtyFourth => 2,
|
BasicLength::SixtyFourth => 2,
|
||||||
};
|
};
|
||||||
if self == rhs && self != BasicLength::Whole {
|
if self == rhs && self != BasicLength::Whole {
|
||||||
Length::Simple(ModdedLength::Plain(BasicLength::from_128th(f(self) * 2).unwrap()))
|
Length::Simple(ModdedLength::Plain(
|
||||||
|
BasicLength::from_128th(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 > 128 {
|
if total > 128 {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_128th(total - 128).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Whole),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 128).unwrap()),
|
||||||
|
)
|
||||||
} else if total > 32 {
|
} else if total > 32 {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 64).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Half),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 64).unwrap()),
|
||||||
|
)
|
||||||
} else if total > 16 {
|
} else if total > 16 {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 32).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Fourth),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 32).unwrap()),
|
||||||
|
)
|
||||||
} else if total > 8 {
|
} else if total > 8 {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_128th(total - 16).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Eighth),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 16).unwrap()),
|
||||||
|
)
|
||||||
} else if total > 4 {
|
} else if total > 4 {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 8).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Fourth),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 8).unwrap()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 4).unwrap()))
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Half),
|
||||||
|
ModdedLength::Plain(BasicLength::from_128th(total - 4).unwrap()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,15 +148,30 @@ impl Add<BasicLength> for BasicLength {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_basic_length() {
|
fn test_add_basic_length() {
|
||||||
assert_eq!(BasicLength::Half + BasicLength::Half, Length::Simple(ModdedLength::Plain(BasicLength::Whole)));
|
assert_eq!(
|
||||||
assert_eq!(BasicLength::Whole + BasicLength::Whole, Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::Whole)));
|
BasicLength::Half + BasicLength::Half,
|
||||||
assert_eq!(BasicLength::Half + BasicLength::SixtyFourth, Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::SixtyFourth)));
|
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),
|
||||||
Dotted(BasicLength)
|
Dotted(BasicLength),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KnownLength for ModdedLength {
|
impl KnownLength for ModdedLength {
|
||||||
|
@ -141,7 +180,7 @@ impl KnownLength for ModdedLength {
|
||||||
ModdedLength::Plain(bl) => bl.to_128th(),
|
ModdedLength::Plain(bl) => bl.to_128th(),
|
||||||
ModdedLength::Dotted(bl) => {
|
ModdedLength::Dotted(bl) => {
|
||||||
let l = bl.to_128th();
|
let l = bl.to_128th();
|
||||||
l + l /2
|
l + l / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +190,7 @@ impl KnownLength for ModdedLength {
|
||||||
pub enum Length {
|
pub enum Length {
|
||||||
Simple(ModdedLength),
|
Simple(ModdedLength),
|
||||||
Tied(ModdedLength, ModdedLength),
|
Tied(ModdedLength, ModdedLength),
|
||||||
Triplet(ModdedLength)
|
Triplet(ModdedLength),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KnownLength for Length {
|
impl KnownLength for Length {
|
||||||
|
@ -159,7 +198,7 @@ impl KnownLength for Length {
|
||||||
match self {
|
match self {
|
||||||
Length::Simple(ml) => ml.to_128th(),
|
Length::Simple(ml) => ml.to_128th(),
|
||||||
Length::Tied(ml1, ml2) => ml1.to_128th() + ml2.to_128th(),
|
Length::Tied(ml1, ml2) => ml1.to_128th() + ml2.to_128th(),
|
||||||
Length::Triplet(ml) => ml.to_128th() * 2 / 3
|
Length::Triplet(ml) => ml.to_128th() * 2 / 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,67 +206,82 @@ impl KnownLength for Length {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Note {
|
pub enum Note {
|
||||||
Hit,
|
Hit,
|
||||||
Rest
|
Rest,
|
||||||
}
|
}
|
||||||
|
|
||||||
use Note::*;
|
use Note::*;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static WHOLE : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Whole));
|
pub(crate) static WHOLE: &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Whole));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static HALF : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half));
|
pub(crate) static HALF: &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Fourth));
|
pub(crate) static FOURTH: &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Fourth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static EIGHTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth));
|
pub(crate) static EIGHTH: &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTEENTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Sixteenth));
|
pub(crate) static SIXTEENTH: &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Sixteenth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static THIRTY_SECOND : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond));
|
pub(crate) static THIRTY_SECOND: &Length =
|
||||||
|
&Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTY_FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::SixtyFourth));
|
pub(crate) static SIXTY_FOURTH: &Length =
|
||||||
|
&Length::Simple(ModdedLength::Plain(BasicLength::SixtyFourth));
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static WHOLE_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Whole));
|
pub(crate) static WHOLE_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::Whole));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static HALF_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Half));
|
pub(crate) static HALF_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::Half));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Fourth));
|
pub(crate) static FOURTH_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::Fourth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static EIGHTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Eighth));
|
pub(crate) static EIGHTH_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::Eighth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTEENTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Sixteenth));
|
pub(crate) static SIXTEENTH_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::Sixteenth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static THIRTY_SECOND_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::ThirtySecond));
|
pub(crate) static THIRTY_SECOND_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::ThirtySecond));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTY_FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::SixtyFourth));
|
pub(crate) static SIXTY_FOURTH_DOTTED_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Dotted(BasicLength::SixtyFourth));
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static WHOLE_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Whole));
|
pub(crate) static WHOLE_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::Whole));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static HALF_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Half));
|
pub(crate) static HALF_TRIPLET: &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Half));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Fourth));
|
pub(crate) static FOURTH_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::Fourth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static EIGHTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Eighth));
|
pub(crate) static EIGHTH_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::Eighth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTEENTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth));
|
pub(crate) static SIXTEENTH_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static THIRTY_SECOND_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::ThirtySecond));
|
pub(crate) static THIRTY_SECOND_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::ThirtySecond));
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static SIXTY_FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::SixtyFourth));
|
pub(crate) static SIXTY_FOURTH_TRIPLET: &Length =
|
||||||
|
&Length::Triplet(ModdedLength::Plain(BasicLength::SixtyFourth));
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit);
|
pub(crate) static HIT: GroupOrNote = GroupOrNote::SingleNote(Note::Hit);
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest);
|
pub(crate) static REST: GroupOrNote = GroupOrNote::SingleNote(Note::Rest);
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static ONCE : &Times = &Times(1);
|
pub(crate) static ONCE: &Times = &Times(1);
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static TWICE: &Times = &Times(2);
|
pub(crate) static TWICE: &Times = &Times(2);
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) static THRICE : &Times = &Times(3);
|
pub(crate) static THRICE: &Times = &Times(3);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -235,95 +289,145 @@ pub struct Times(pub u16);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum GroupOrNote {
|
pub enum GroupOrNote {
|
||||||
SingleGroup(Group),
|
SingleGroup(Group<GroupOrNote>),
|
||||||
SingleNote(Note)
|
SingleNote(Note),
|
||||||
}
|
}
|
||||||
|
|
||||||
use GroupOrNote::*;
|
use GroupOrNote::*;
|
||||||
|
|
||||||
|
/// There are two useful instantiations of this type:
|
||||||
|
/// `Group<GroupOrNote>` acts as a recursive `Group`, dsl parser uses this as return type
|
||||||
|
/// `Group<Note>` is a non-recursive group. To go from recursive groups to not-recursive ones, try using `flatten_group`.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Group {
|
pub struct Group<T> {
|
||||||
pub notes: Vec<GroupOrNote>,
|
pub notes: Vec<T>,
|
||||||
pub length: Length,
|
pub length: Length,
|
||||||
pub times: Times
|
pub times: Times,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Group {
|
impl<T> Group<T> {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Group { notes: Vec::new(), length: FOURTH.clone(), times: Times(1) }
|
Group {
|
||||||
|
notes: Vec::new(),
|
||||||
|
length: FOURTH.clone(),
|
||||||
|
times: Times(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KnownLength for &Group {
|
impl KnownLength for &Group<GroupOrNote> {
|
||||||
fn to_128th(&self) -> u32 {
|
fn to_128th(&self) -> u32 {
|
||||||
let mut acc = 0;
|
let mut acc = 0;
|
||||||
let note_length = self.length.to_128th();
|
let note_length = self.length.to_128th();
|
||||||
for group in self.notes.iter() {
|
for group in self.notes.iter() {
|
||||||
match group {
|
match group {
|
||||||
GroupOrNote::SingleGroup(subgroup) => { acc += subgroup.to_128th(); },
|
GroupOrNote::SingleGroup(subgroup) => {
|
||||||
GroupOrNote::SingleNote(_) => { acc += note_length; },
|
acc += subgroup.to_128th();
|
||||||
|
}
|
||||||
|
GroupOrNote::SingleNote(_) => {
|
||||||
|
acc += note_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
acc * self.times.0 as u32
|
acc * self.times.0 as u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KnownLength for Group {
|
impl KnownLength for Group<GroupOrNote> {
|
||||||
fn to_128th(&self) -> u32 {
|
fn to_128th(&self) -> u32 {
|
||||||
let mut acc = 0;
|
let mut acc = 0;
|
||||||
let note_length = self.length.to_128th();
|
let note_length = self.length.to_128th();
|
||||||
println!("NOTE LENGTH: {}", note_length);
|
|
||||||
for group in self.notes.iter() {
|
for group in self.notes.iter() {
|
||||||
match group {
|
match group {
|
||||||
GroupOrNote::SingleGroup(subgroup) => { acc += subgroup.to_128th(); },
|
GroupOrNote::SingleGroup(subgroup) => {
|
||||||
GroupOrNote::SingleNote(_) => { acc += note_length; },
|
acc += subgroup.to_128th();
|
||||||
|
}
|
||||||
|
GroupOrNote::SingleNote(_) => {
|
||||||
|
acc += note_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc * self.times.0 as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KnownLength for Group<Note> {
|
||||||
|
fn to_128th(&self) -> u32 {
|
||||||
|
let mut acc = 0;
|
||||||
|
let note_length = self.length.to_128th();
|
||||||
|
for group in self.notes.iter() {
|
||||||
|
acc += note_length;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
acc * self.times.0 as u32
|
acc * self.times.0 as u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_known_length_group() {
|
fn test_known_length_group() {
|
||||||
let group = Group { notes: vec![SingleNote(Hit), SingleNote(Hit), SingleNote(Rest), SingleNote(Hit), SingleNote(Rest), SingleNote(Hit), SingleNote(Hit), SingleNote(Rest)], length: SIXTEENTH.clone(), times: Times(1) };
|
let group = Group {
|
||||||
|
notes: vec![
|
||||||
|
SingleNote(Hit),
|
||||||
|
SingleNote(Hit),
|
||||||
|
SingleNote(Rest),
|
||||||
|
SingleNote(Hit),
|
||||||
|
SingleNote(Rest),
|
||||||
|
SingleNote(Hit),
|
||||||
|
SingleNote(Hit),
|
||||||
|
SingleNote(Rest),
|
||||||
|
],
|
||||||
|
length: SIXTEENTH.clone(),
|
||||||
|
times: Times(1),
|
||||||
|
};
|
||||||
assert_eq!(group.to_128th(), 64);
|
assert_eq!(group.to_128th(), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for Group {
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
type Target = Vec<GroupOrNote>;
|
pub struct Groups(pub Vec<Group<Note>>);
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
impl IntoIterator for Groups {
|
||||||
&self.notes
|
type Item = Group<Note>;
|
||||||
|
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
impl FromIterator<Group<Note>> for Groups {
|
||||||
pub struct Groups(pub Vec<Group>);
|
fn from_iter<T: IntoIterator<Item = Group<Note>>>(iter: T) -> Self {
|
||||||
|
Self(Vec::from_iter(iter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl KnownLength for Groups {
|
impl KnownLength for Groups {
|
||||||
fn to_128th(&self) -> u32 {
|
fn to_128th(&self) -> u32 {
|
||||||
self.0.iter().fold(0, |acc, x| { acc + x.to_128th() })
|
self.0.iter().fold(0, |acc, x| acc + x.to_128th())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KnownLength for &Groups {
|
impl KnownLength for &Groups {
|
||||||
fn to_128th(&self) -> u32 {
|
fn to_128th(&self) -> u32 {
|
||||||
self.0.iter().fold(0, |acc, x| { acc + x.to_128th() })
|
self.0.iter().fold(0, |acc, x| acc + x.to_128th())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_known_length_groups() {
|
fn test_known_length_groups() {
|
||||||
let groups = Groups(vec![Group { notes: vec![SingleNote(Hit), SingleNote(Hit), SingleNote(Rest), SingleNote(Hit), SingleNote(Rest), SingleNote(Hit), SingleNote(Hit), SingleNote(Rest)], length: SIXTEENTH.clone(), times: Times(1) }]);
|
let groups = Groups(vec![Group {
|
||||||
|
notes: vec![Hit, Hit, Rest, Hit, Rest, Hit, Hit, Rest],
|
||||||
|
length: SIXTEENTH.clone(),
|
||||||
|
times: Times(1),
|
||||||
|
}]);
|
||||||
assert_eq!(groups.to_128th(), 96);
|
assert_eq!(groups.to_128th(), 96);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hit(input: &str) -> IResult<&str, Note> {
|
fn hit(input: &str) -> IResult<&str, Note> {
|
||||||
map(char('x'), |_| { Note::Hit })(input)
|
map(char('x'), |_| Note::Hit)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rest(input: &str) -> IResult<&str, Note> {
|
fn rest(input: &str) -> IResult<&str, Note> {
|
||||||
map(char('-'), |_| { Note::Rest })(input)
|
map(char('-'), |_| Note::Rest)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note(input: &str) -> IResult<&str, Note> {
|
fn note(input: &str) -> IResult<&str, Note> {
|
||||||
|
@ -332,95 +436,312 @@ fn note(input: &str) -> IResult<&str, Note> {
|
||||||
|
|
||||||
fn length_basic(input: &str) -> IResult<&str, BasicLength> {
|
fn length_basic(input: &str) -> IResult<&str, BasicLength> {
|
||||||
match map_res(digit1, str::parse)(input) {
|
match map_res(digit1, str::parse)(input) {
|
||||||
Ok((r,1)) => Ok((r, BasicLength::Whole)),
|
Ok((r, 1)) => Ok((r, BasicLength::Whole)),
|
||||||
Ok((r,2)) => Ok((r, BasicLength::Half)),
|
Ok((r, 2)) => Ok((r, BasicLength::Half)),
|
||||||
Ok((r,4)) => Ok((r, BasicLength::Fourth)),
|
Ok((r, 4)) => Ok((r, BasicLength::Fourth)),
|
||||||
Ok((r,8)) => Ok((r, BasicLength::Eighth)),
|
Ok((r, 8)) => Ok((r, BasicLength::Eighth)),
|
||||||
Ok((r,16)) => Ok((r, BasicLength::Sixteenth)),
|
Ok((r, 16)) => Ok((r, BasicLength::Sixteenth)),
|
||||||
Ok((r,32)) => Ok((r, BasicLength::ThirtySecond)),
|
Ok((r, 32)) => Ok((r, BasicLength::ThirtySecond)),
|
||||||
Ok((r, 64)) => Ok((r, BasicLength::SixtyFourth)),
|
Ok((r, 64)) => Ok((r, BasicLength::SixtyFourth)),
|
||||||
Ok((r, _)) => {
|
Ok((r, _)) => Err(Err::Error(nom::error::make_error(
|
||||||
Err(Err::Error(nom::error::make_error(r, nom::error::ErrorKind::Fail)))
|
r,
|
||||||
},
|
nom::error::ErrorKind::Fail,
|
||||||
Err(e) => Err(e)
|
))),
|
||||||
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dotted_length(input: &str) -> IResult<&str, ModdedLength> {
|
fn dotted_length(input: &str) -> IResult<&str, ModdedLength> {
|
||||||
map(tuple((length_basic, char('.'))), |(l, _)| { ModdedLength::Dotted(l)})(input)
|
map(tuple((length_basic, char('.'))), |(l, _)| {
|
||||||
|
ModdedLength::Dotted(l)
|
||||||
|
})(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modded_length(input: &str) -> IResult<&str, ModdedLength> {
|
fn modded_length(input: &str) -> IResult<&str, ModdedLength> {
|
||||||
alt((dotted_length, map(length_basic, |x| {ModdedLength::Plain(x)})))(input)
|
alt((dotted_length, map(length_basic, |x| ModdedLength::Plain(x))))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn triplet_length(input: &str) -> IResult<&str, Length> {
|
fn triplet_length(input: &str) -> IResult<&str, Length> {
|
||||||
map(tuple((modded_length, char('t'))), |(l, _)| { Length::Triplet(l)})(input)
|
map(tuple((modded_length, char('t'))), |(l, _)| {
|
||||||
|
Length::Triplet(l)
|
||||||
|
})(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tied_length(input: &str) -> IResult<&str, Length> {
|
fn tied_length(input: &str) -> IResult<&str, Length> {
|
||||||
map(separated_pair(modded_length, char('+'), modded_length), |(x, y)| { Length::Tied(x,y)})(input)
|
map(
|
||||||
|
separated_pair(modded_length, char('+'), modded_length),
|
||||||
|
|(x, y)| Length::Tied(x, y),
|
||||||
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn length(input: &str) -> IResult<&str, Length> {
|
fn length(input: &str) -> IResult<&str, Length> {
|
||||||
alt((triplet_length, tied_length, map(modded_length, |x| { Length::Simple(x) })))(input)
|
alt((
|
||||||
|
triplet_length,
|
||||||
|
tied_length,
|
||||||
|
map(modded_length, |x| Length::Simple(x)),
|
||||||
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn times(input: &str) -> IResult<&str, Times> {
|
fn times(input: &str) -> IResult<&str, Times> {
|
||||||
map(map_res(digit1, str::parse), |x| { Times(x) } )(input)
|
map(map_res(digit1, str::parse), |x| Times(x))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group(input: &str) -> IResult<&str, Group> {
|
fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
|
||||||
let repeated = map(tuple((times, char(','), length, many1(note))), |(t, _, l, n)| { (t, l, n)} );
|
let repeated = map(
|
||||||
let single = map(tuple((length, many1(note))), |(l, vn)| { (Times(1), l, vn) } );
|
tuple((times, char(','), length, many1(note)),
|
||||||
|
|(t, _, l, n)| (t, l, n),
|
||||||
|
);
|
||||||
|
let single = map(tuple((length, many1(note))), |(l, vn)| (Times(1), l, vn));
|
||||||
let (rem, (t, l, n)) = alt((repeated, single))(input)?;
|
let (rem, (t, l, n)) = alt((repeated, single))(input)?;
|
||||||
Ok((rem, Group{ notes: n.iter().map(|x| GroupOrNote::SingleNote(x.clone())).collect(), length: l, times: t}))
|
Ok((
|
||||||
|
rem,
|
||||||
|
Group {
|
||||||
|
notes: n
|
||||||
|
.iter()
|
||||||
|
.map(|x| GroupOrNote::SingleNote(x.clone()))
|
||||||
|
.collect(),
|
||||||
|
length: l,
|
||||||
|
times: t,
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delimited_group(input: &str) -> IResult<&str, Group> {
|
fn delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
|
||||||
delimited(char('('), group, char(')'))(input)
|
delimited(char('('), group, char(')'))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group> {
|
pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
|
||||||
alt((delimited_group, group))(input)
|
alt((delimited_group, group))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn groups(input: &str) -> IResult<&str, Groups> {
|
pub fn groups(input: &str) -> IResult<&str, Groups> {
|
||||||
all_consuming(many1(group_or_delimited_group))(input).map(|x| { (x.0, Groups(x.1)) } )
|
all_consuming(many1(group_or_delimited_group))(input).map(|x| (x.0, flatten_groups(x.1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flatten_group(input: Group<GroupOrNote>) -> Groups {
|
||||||
|
let mut note_group = Vec::new();
|
||||||
|
let mut out_groups = Vec::new();
|
||||||
|
input.notes.iter().for_each(|g| match g {
|
||||||
|
SingleGroup(group) => {
|
||||||
|
let isolated_group = Group { notes: note_group.clone(), length: input.length, times: Times(1) };
|
||||||
|
out_groups.push(isolated_group);
|
||||||
|
note_group.clear();
|
||||||
|
out_groups.extend(flatten_group(group.clone()).0);
|
||||||
|
},
|
||||||
|
SingleNote(note) => {
|
||||||
|
note_group.push(*note);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Groups(out_groups.iter().cloned().cycle().take(out_groups.len() * (input.times.0 as usize)).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flatten_groups<I>(input_groups: I) -> Groups
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Group<GroupOrNote>>
|
||||||
|
{
|
||||||
|
let mut out = Vec::new();
|
||||||
|
input_groups.into_iter().for_each(|g| {
|
||||||
|
let flattened = flatten_group(g).0;
|
||||||
|
out.extend(flattened);
|
||||||
|
});
|
||||||
|
|
||||||
|
Groups(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_group() {
|
||||||
|
let out = Groups(vec![
|
||||||
|
Group {
|
||||||
|
notes: vec![Hit],
|
||||||
|
length: *SIXTEENTH,
|
||||||
|
times: Times(1),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
notes: vec![Rest, Hit],
|
||||||
|
length: *EIGHTH,
|
||||||
|
times: Times(3),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
notes: vec![Hit],
|
||||||
|
length: *SIXTEENTH,
|
||||||
|
times: Times(1)
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
notes: vec![Rest, Hit],
|
||||||
|
length: *EIGHTH,
|
||||||
|
times: Times(3)
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
assert_eq!(flatten_group(group("(2,16x(3,8-x))").unwrap().1), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_length() {
|
fn parse_length() {
|
||||||
assert_eq!(length("16"), Ok(("", *SIXTEENTH)));
|
assert_eq!(length("16"), Ok(("", *SIXTEENTH)));
|
||||||
assert_eq!(length("8+16"), Ok(("", Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::Sixteenth)))));
|
assert_eq!(
|
||||||
|
length("8+16"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Eighth),
|
||||||
|
ModdedLength::Plain(BasicLength::Sixteenth)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
);
|
||||||
assert_eq!(length("8t"), Ok(("", *EIGHTH_TRIPLET)));
|
assert_eq!(length("8t"), Ok(("", *EIGHTH_TRIPLET)));
|
||||||
assert_eq!(length("4.t"), Ok(("", *FOURTH_DOTTED_TRIPLET)));
|
assert_eq!(length("4.t"), Ok(("", *FOURTH_DOTTED_TRIPLET)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_groups() {
|
fn parse_groups() {
|
||||||
assert_eq!(groups("8x-(7,8xx)"), Ok(("", Groups(vec![Group { notes: vec![SingleNote(Hit), SingleNote(Rest)], length: *EIGHTH, times: Times(1) }, Group { notes: vec![SingleNote(Hit), SingleNote(Hit)], length: *EIGHTH, times: Times(7) }]))));
|
assert_eq!(
|
||||||
assert_eq!(groups("8x-(7,8xx"), Err(Err::Error(nom::error::make_error("(7,8xx", nom::error::ErrorKind::Eof))));
|
groups("8x-(7,8xx)"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Groups(vec![
|
||||||
|
Group {
|
||||||
|
notes: vec![Hit, Rest],
|
||||||
|
length: *EIGHTH,
|
||||||
|
times: Times(1)
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
notes: vec![Hit, Hit],
|
||||||
|
length: *EIGHTH,
|
||||||
|
times: Times(7)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
groups("8x-(7,8xx"),
|
||||||
|
Err(Err::Error(nom::error::make_error(
|
||||||
|
"(7,8xx",
|
||||||
|
nom::error::ErrorKind::Eof
|
||||||
|
)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_group() {
|
fn parse_group() {
|
||||||
assert_eq!(group("16x--x-"), Ok(("", Group { times: *ONCE, notes: vec![HIT.clone(), REST.clone(), REST.clone(), HIT.clone(), REST.clone()], length: *SIXTEENTH})));
|
assert_eq!(
|
||||||
assert_eq!(group("8txxx"), Ok(("", Group { times: *ONCE, notes: vec![HIT.clone(), HIT.clone(), HIT.clone()], length: *EIGHTH_TRIPLET})));
|
group("16x--x-"),
|
||||||
assert_eq!(group("16+32x-xx"), Ok(("", Group { times: *ONCE, notes: vec![HIT.clone(), REST.clone(), HIT.clone(), HIT.clone()], length: Length::Tied(ModdedLength::Plain(BasicLength::Sixteenth), ModdedLength::Plain(BasicLength::ThirtySecond))})));
|
Ok((
|
||||||
assert_eq!(group("3,16xx"), Ok(("", Group { times: *THRICE, length: *SIXTEENTH, notes: vec![HIT.clone(), HIT.clone()] })));
|
"",
|
||||||
|
Group {
|
||||||
|
times: *ONCE,
|
||||||
|
notes: vec![
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone()
|
||||||
|
],
|
||||||
|
length: *SIXTEENTH
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
group("8txxx"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *ONCE,
|
||||||
|
notes: vec![HIT.clone(), HIT.clone(), HIT.clone()],
|
||||||
|
length: *EIGHTH_TRIPLET
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
group("16+32x-xx"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *ONCE,
|
||||||
|
notes: vec![HIT.clone(), REST.clone(), HIT.clone(), HIT.clone()],
|
||||||
|
length: Length::Tied(
|
||||||
|
ModdedLength::Plain(BasicLength::Sixteenth),
|
||||||
|
ModdedLength::Plain(BasicLength::ThirtySecond)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
group("3,16xx"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *THRICE,
|
||||||
|
length: *SIXTEENTH,
|
||||||
|
notes: vec![HIT.clone(), HIT.clone()]
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_delimited_group() {
|
fn parse_delimited_group() {
|
||||||
assert_eq!(delimited_group("(3,16x--x-)"), Ok(("", Group { times: *THRICE, notes: vec![HIT.clone(), REST.clone(), REST.clone(), HIT.clone(), REST.clone()], length: *SIXTEENTH})));
|
assert_eq!(
|
||||||
|
delimited_group("(3,16x--x-)"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *THRICE,
|
||||||
|
notes: vec![
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone()
|
||||||
|
],
|
||||||
|
length: *SIXTEENTH
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_group_or_delimited_group() {
|
fn parse_group_or_delimited_group() {
|
||||||
assert_eq!(group_or_delimited_group("(3,16x--x-)"), Ok(("", Group { times: *THRICE, notes: vec![HIT.clone(), REST.clone(), REST.clone(), HIT.clone(), REST.clone()], length: *SIXTEENTH})));
|
assert_eq!(
|
||||||
assert_eq!(group_or_delimited_group("16x--x-"), Ok(("", Group { times: *ONCE, notes: vec![HIT.clone(), REST.clone(), REST.clone(), HIT.clone(), REST.clone()], length: *SIXTEENTH})));
|
group_or_delimited_group("(3,16x--x-)"),
|
||||||
assert_eq!(group_or_delimited_group("(7,8xx"), Err(Err::Error(nom::error::make_error("(7,8xx", nom::error::ErrorKind::Digit))));
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *THRICE,
|
||||||
|
notes: vec![
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone()
|
||||||
|
],
|
||||||
|
length: *SIXTEENTH
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
group_or_delimited_group("16x--x-"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Group {
|
||||||
|
times: *ONCE,
|
||||||
|
notes: vec![
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
REST.clone(),
|
||||||
|
HIT.clone(),
|
||||||
|
REST.clone()
|
||||||
|
],
|
||||||
|
length: *SIXTEENTH
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
group_or_delimited_group("(7,8xx"),
|
||||||
|
Err(Err::Error(nom::error::make_error(
|
||||||
|
"(7,8xx",
|
||||||
|
nom::error::ErrorKind::Digit
|
||||||
|
)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// “x” hit
|
// “x” hit
|
||||||
|
|
|
@ -14,7 +14,7 @@ use midly::{MetaMessage, TrackEvent};
|
||||||
|
|
||||||
use crate::dsl::dsl::{
|
use crate::dsl::dsl::{
|
||||||
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Groups, KnownLength, Length,
|
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Groups, KnownLength, Length,
|
||||||
ModdedLength, Note, Times,
|
ModdedLength, Note, Times, flatten_group,
|
||||||
};
|
};
|
||||||
use crate::midi::time::TimeSignature;
|
use crate::midi::time::TimeSignature;
|
||||||
use GroupOrNote::*;
|
use GroupOrNote::*;
|
||||||
|
@ -201,7 +201,21 @@ impl<T> EventGrid<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: add a mutable version for use in `flatten_groups`
|
impl<T> EventGrid<T>
|
||||||
|
where
|
||||||
|
T: Clone
|
||||||
|
{
|
||||||
|
pub fn extend(&self, other: &EventGrid<T>) -> EventGrid<T> {
|
||||||
|
let combined = self.events.iter().cloned().chain(other.events.iter().cloned()).collect();
|
||||||
|
EventGrid { events: combined, length: self.length + other.length }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: add a mutable version for use in `groups_to_event_grid`
|
||||||
|
/// Adds two EventGrids together, manipulates the time of the right `EventGrid` by
|
||||||
|
/// adding the length of the left one to timings.
|
||||||
|
/// If you need to concat two `EventGrid`s without messing up with times, then use `extend`.
|
||||||
impl<T: Add<Tick, Output = T> + Clone + Ord + std::fmt::Debug> Add for EventGrid<T> {
|
impl<T: Add<Tick, Output = T> + Clone + Ord + std::fmt::Debug> Add for EventGrid<T> {
|
||||||
type Output = EventGrid<T>;
|
type Output = EventGrid<T>;
|
||||||
|
|
||||||
|
@ -404,12 +418,12 @@ impl MidiTempo {
|
||||||
|
|
||||||
/// Returns an EventGrid and a total length. Length is needed as a group can end with rests that are not in the grid,
|
/// Returns an EventGrid and a total length. Length is needed as a group can end with rests that are not in the grid,
|
||||||
/// so we need it to cycle the group.
|
/// so we need it to cycle the group.
|
||||||
fn flatten_group(
|
fn group_to_event_grid(
|
||||||
Group {
|
Group {
|
||||||
notes,
|
notes,
|
||||||
length,
|
length,
|
||||||
times,
|
times,
|
||||||
}: &Group,
|
}: &Group<Note>,
|
||||||
part: Part,
|
part: Part,
|
||||||
start: &Tick,
|
start: &Tick,
|
||||||
) -> EventGrid<Tick> {
|
) -> EventGrid<Tick> {
|
||||||
|
@ -418,18 +432,19 @@ fn flatten_group(
|
||||||
let mut grid = EventGrid::empty();
|
let mut grid = EventGrid::empty();
|
||||||
notes.iter().for_each(|entry| {
|
notes.iter().for_each(|entry| {
|
||||||
match entry {
|
match entry {
|
||||||
SingleGroup(group) => {
|
// SingleGroup(group) => {
|
||||||
let mut eg = flatten_group(&group, part, &time.clone());
|
// let mut eg = group_to_event_grid(&group, part, &time.clone());
|
||||||
grid.events.append(&mut eg.events);
|
// println!("SINGLE GROUP EVENTGRID: {:?}", eg);
|
||||||
grid.length = grid.length + eg.length;
|
// grid.events.append(&mut eg.events);
|
||||||
time = time + grid.length;
|
// grid.length = grid.length + eg.length;
|
||||||
}
|
// time = time + grid.length;
|
||||||
SingleNote(Note::Rest) => {
|
// }
|
||||||
|
Rest => {
|
||||||
let rest_end = time + note_length;
|
let rest_end = time + note_length;
|
||||||
time = rest_end;
|
time = rest_end;
|
||||||
grid.length = rest_end;
|
grid.length = rest_end;
|
||||||
}
|
}
|
||||||
SingleNote(Note::Hit) => {
|
Hit => {
|
||||||
let note_end = time + note_length;
|
let note_end = time + note_length;
|
||||||
let note_on = Event {
|
let note_on = Event {
|
||||||
tick: time,
|
tick: time,
|
||||||
|
@ -451,11 +466,11 @@ fn flatten_group(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flatten_group() {
|
fn test_group_to_event_grid() {
|
||||||
let start_time = Tick(0);
|
let start_time = Tick(0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
flatten_group(
|
group_to_event_grid(
|
||||||
&group_or_delimited_group("(2,8x--)").unwrap().1,
|
flatten_group(group_or_delimited_group("(2,8x--)").unwrap().1).0.first().unwrap(),
|
||||||
KickDrum,
|
KickDrum,
|
||||||
&start_time
|
&start_time
|
||||||
),
|
),
|
||||||
|
@ -500,13 +515,17 @@ fn test_cycle_grid() {
|
||||||
|
|
||||||
/// Takes multiple `Group`s and turn them into a single `EventGrid`.
|
/// Takes multiple `Group`s and turn them into a single `EventGrid`.
|
||||||
/// The point of it is to combine timings into a single MIDI track.
|
/// The point of it is to combine timings into a single MIDI track.
|
||||||
fn flatten_groups(part: Part, groups: &Groups) -> EventGrid<Tick> {
|
fn groups_to_event_grid(part: Part, groups: &Groups) -> EventGrid<Tick> {
|
||||||
let mut time: Tick = Tick(0);
|
let mut time: Tick = Tick(0);
|
||||||
let mut grid: EventGrid<Tick> = EventGrid::empty();
|
let mut grid: EventGrid<Tick> = EventGrid::empty();
|
||||||
groups.0.iter().for_each(|group| {
|
groups.0.iter().for_each(|group| {
|
||||||
// `flatten_group` doesn't know at which point in time groups starts unless we pass
|
// `group_to_event_grid` doesn't know at which point in time groups starts unless we pass
|
||||||
// `time` explicitly. Only the first `Group` in `Groups` starts at zero.
|
// `time` explicitly. Only the first `Group` in `Groups` starts at zero.
|
||||||
grid = grid.clone() + flatten_group(group, part, &time);
|
let flattened_group = group_to_event_grid(group, part, &time);
|
||||||
|
println!("(groups_to_event_grid) FLATTENED GROUP: {:?}", flattened_group);
|
||||||
|
|
||||||
|
// Note that using `+` is wrong here as it's messing with timings and it really shouldn't
|
||||||
|
grid = grid.extend(&flattened_group);
|
||||||
time = grid.length;
|
time = grid.length;
|
||||||
});
|
});
|
||||||
grid
|
grid
|
||||||
|
@ -574,13 +593,13 @@ impl Iterator for EventIterator {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_event_iterator_impl() {
|
fn test_event_iterator_impl() {
|
||||||
let empty = EventGrid::empty();
|
let empty = EventGrid::empty();
|
||||||
let kick1 = flatten_group(
|
let kick1 = group_to_event_grid(
|
||||||
&group_or_delimited_group("(4x-)").unwrap().1,
|
&flatten_group(group_or_delimited_group("(4x-)").unwrap().1).0.first().unwrap(),
|
||||||
KickDrum,
|
KickDrum,
|
||||||
&mut Tick(0),
|
&mut Tick(0),
|
||||||
);
|
);
|
||||||
let snare1 = flatten_group(
|
let snare1 = group_to_event_grid(
|
||||||
&group_or_delimited_group("4-x").unwrap().1,
|
&flatten_group(group_or_delimited_group("(4-x)").unwrap().1).0.first().unwrap(),
|
||||||
SnareDrum,
|
SnareDrum,
|
||||||
&mut Tick(0),
|
&mut Tick(0),
|
||||||
);
|
);
|
||||||
|
@ -642,7 +661,7 @@ fn test_event_iterator_impl() {
|
||||||
/// Calling .collect() on this EventIterator should produce an `EventGrid`.
|
/// Calling .collect() on this EventIterator should produce an `EventGrid`.
|
||||||
///
|
///
|
||||||
/// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
/// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
||||||
fn flatten_to_iterator(
|
fn merge_to_iterator(
|
||||||
groups: BTreeMap<Part, Groups>,
|
groups: BTreeMap<Part, Groups>,
|
||||||
time_signature: TimeSignature,
|
time_signature: TimeSignature,
|
||||||
) -> EventIterator {
|
) -> EventIterator {
|
||||||
|
@ -677,7 +696,7 @@ fn flatten_to_iterator(
|
||||||
let length_128th = length_map.get(part).unwrap();
|
let length_128th = length_map.get(part).unwrap();
|
||||||
let times = length_limit / length_128th;
|
let times = length_limit / length_128th;
|
||||||
println!("TIMES: {}", times);
|
println!("TIMES: {}", times);
|
||||||
let flattened = flatten_groups(*part, groups);
|
let flattened = groups_to_event_grid(*part, groups);
|
||||||
println!("FLATTENED: {:?}", flattened);
|
println!("FLATTENED: {:?}", flattened);
|
||||||
(flattened, times)
|
(flattened, times)
|
||||||
}
|
}
|
||||||
|
@ -702,14 +721,14 @@ fn flatten_to_iterator(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flatten_to_iterator() {
|
fn test_merge_to_iterator() {
|
||||||
let snare_group = "8-x--x-";
|
let snare_group = "8-x--x-";
|
||||||
let kick_group = "16xx-x-xx-";
|
let kick_group = "16xx-x-xx-";
|
||||||
|
|
||||||
let kick_events = vec![Event { tick: Tick(0), event_type: NoteOn(KickDrum) }, Event { tick: Tick(12), event_type: NoteOff(KickDrum) }, Event { tick: Tick(12), event_type: NoteOn(KickDrum) }, Event { tick: Tick(24), event_type: NoteOff(KickDrum) }, Event { tick: Tick(36), event_type: NoteOn(KickDrum) }, Event { tick: Tick(48), event_type: NoteOff(KickDrum) }, Event { tick: Tick(60), event_type: NoteOn(KickDrum) }, Event { tick: Tick(72), event_type: NoteOff(KickDrum) }, Event { tick: Tick(72), event_type: NoteOn(KickDrum) }, Event { tick: Tick(84), event_type: NoteOff(KickDrum) }, Event { tick: Tick(96), event_type: NoteOn(KickDrum) }, Event { tick: Tick(108), event_type: NoteOff(KickDrum) }, Event { tick: Tick(108), event_type: NoteOn(KickDrum) }, Event { tick: Tick(120), event_type: NoteOff(KickDrum) }, Event { tick: Tick(132), event_type: NoteOn(KickDrum) }, Event { tick: Tick(144), event_type: NoteOff(KickDrum) }, Event { tick: Tick(156), event_type: NoteOn(KickDrum) }, Event { tick: Tick(168), event_type: NoteOff(KickDrum) }, Event { tick: Tick(168), event_type: NoteOn(KickDrum) }, Event { tick: Tick(180), event_type: NoteOff(KickDrum) }];
|
let kick_events = vec![Event { tick: Tick(0), event_type: NoteOn(KickDrum) }, Event { tick: Tick(12), event_type: NoteOff(KickDrum) }, Event { tick: Tick(12), event_type: NoteOn(KickDrum) }, Event { tick: Tick(24), event_type: NoteOff(KickDrum) }, Event { tick: Tick(36), event_type: NoteOn(KickDrum) }, Event { tick: Tick(48), event_type: NoteOff(KickDrum) }, Event { tick: Tick(60), event_type: NoteOn(KickDrum) }, Event { tick: Tick(72), event_type: NoteOff(KickDrum) }, Event { tick: Tick(72), event_type: NoteOn(KickDrum) }, Event { tick: Tick(84), event_type: NoteOff(KickDrum) }, Event { tick: Tick(96), event_type: NoteOn(KickDrum) }, Event { tick: Tick(108), event_type: NoteOff(KickDrum) }, Event { tick: Tick(108), event_type: NoteOn(KickDrum) }, Event { tick: Tick(120), event_type: NoteOff(KickDrum) }, Event { tick: Tick(132), event_type: NoteOn(KickDrum) }, Event { tick: Tick(144), event_type: NoteOff(KickDrum) }, Event { tick: Tick(156), event_type: NoteOn(KickDrum) }, Event { tick: Tick(168), event_type: NoteOff(KickDrum) }, Event { tick: Tick(168), event_type: NoteOn(KickDrum) }, Event { tick: Tick(180), event_type: NoteOff(KickDrum) }];
|
||||||
let snare_events = vec![Event { tick: Tick(24), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+144), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+144), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+144), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+144), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+288), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+288), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+288), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+288), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+144*3), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+144*3), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+144*3), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+144*3), event_type: NoteOff(SnareDrum) }];
|
let snare_events = vec![Event { tick: Tick(24), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+144), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+144), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+144), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+144), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+288), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+288), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+288), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+288), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(24+144*3), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(48+144*3), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(96+144*3), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(120+144*3), event_type: NoteOff(SnareDrum) }];
|
||||||
let four_fourth = TimeSignature::from_str("4/4").unwrap();
|
let four_fourth = TimeSignature::from_str("4/4").unwrap();
|
||||||
let flattened_kick_and_snare = flatten_to_iterator(
|
let flattened_kick_and_snare = merge_to_iterator(
|
||||||
BTreeMap::from_iter([
|
BTreeMap::from_iter([
|
||||||
(KickDrum, groups("16xx-x-xx-").unwrap().1),
|
(KickDrum, groups("16xx-x-xx-").unwrap().1),
|
||||||
(SnareDrum, groups("8-x--x-").unwrap().1),
|
(SnareDrum, groups("8-x--x-").unwrap().1),
|
||||||
|
@ -718,8 +737,8 @@ fn test_flatten_to_iterator() {
|
||||||
)
|
)
|
||||||
.collect::<Vec<Event<Tick>>>();
|
.collect::<Vec<Event<Tick>>>();
|
||||||
|
|
||||||
assert_eq!(flatten_to_iterator(BTreeMap::from_iter([(KickDrum, groups(kick_group).unwrap().1)]), four_fourth).collect::<Vec<Event<Tick>>>(), kick_events);
|
assert_eq!(merge_to_iterator(BTreeMap::from_iter([(KickDrum, groups(kick_group).unwrap().1)]), four_fourth).collect::<Vec<Event<Tick>>>(), kick_events);
|
||||||
assert_eq!(flatten_to_iterator(BTreeMap::from_iter([(SnareDrum, groups(snare_group).unwrap().1)]), four_fourth).collect::<Vec<Event<Tick>>>(), snare_events);
|
assert_eq!(merge_to_iterator(BTreeMap::from_iter([(SnareDrum, groups(snare_group).unwrap().1)]), four_fourth).collect::<Vec<Event<Tick>>>(), snare_events);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
kick_events
|
kick_events
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -765,7 +784,7 @@ fn create_tracks<'a>(
|
||||||
text_event: &'a str,
|
text_event: &'a str,
|
||||||
midi_tempo: MidiTempo
|
midi_tempo: MidiTempo
|
||||||
) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
||||||
let events_iter = flatten_to_iterator(parts_and_groups, time_signature);
|
let events_iter = merge_to_iterator(parts_and_groups, time_signature);
|
||||||
let events: Vec<Event<Tick>> = events_iter.collect();
|
let events: Vec<Event<Tick>> = events_iter.collect();
|
||||||
// Notice this time can be incorrect, but it shouldn't matter.
|
// Notice this time can be incorrect, but it shouldn't matter.
|
||||||
let time = match events.last() {
|
let time = match events.last() {
|
||||||
|
|
Loading…
Reference in a new issue