diff --git a/src/bin/main.rs b/src/bin/main.rs index ee5ef9a..aa7bbb4 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::process::exit; 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::time::TimeSignature; @@ -53,10 +53,10 @@ fn validate_and_parse_part( match cli { None => {} Some(pattern) => match dsl::groups(pattern.as_str()) { - Ok((_, group)) => { - println!("{:?}: {:?}", part, group); - println!("group to 128th: {}", group.to_128th()); - patterns.insert(part, group); + Ok((_, groups)) => { + println!("{:?}: {:?}", part, groups); + // println!("group to 128th: {}", group.to_128th()); + patterns.insert(part, groups); } Err(_) => { panic!("{} pattern is malformed.", part_to_string(part)) diff --git a/src/dsl/dsl.rs b/src/dsl/dsl.rs index 0c8f1fe..3efcb19 100644 --- a/src/dsl/dsl.rs +++ b/src/dsl/dsl.rs @@ -1,17 +1,15 @@ use std::num::ParseIntError; +use std::ops::Add; use std::str::{self, FromStr}; use std::vec::Vec; -use std::ops::{Add}; +use nom::branch::alt; pub use nom::character::complete::{char, digit1}; use nom::multi::many1; -use nom::sequence::{separated_pair, tuple, delimited}; +use nom::sequence::{delimited, separated_pair, tuple}; 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. pub trait KnownLength { @@ -26,7 +24,7 @@ pub enum BasicLength { Eighth, Sixteenth, ThirtySecond, - SixtyFourth + SixtyFourth, } impl FromStr for BasicLength { @@ -36,7 +34,7 @@ impl FromStr for BasicLength { let result: Result = s.parse(); match result { Ok(n) => Self::from_num(n), - Result::Err(e) => panic!("{}", e) + Result::Err(e) => panic!("{}", e), } } } @@ -65,8 +63,11 @@ impl BasicLength { 4 => Ok(BasicLength::Fourth), 2 => Ok(BasicLength::Half), 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 + )), + } } /// Private unsafe method, so it should only be used from `add`. @@ -80,7 +81,10 @@ impl BasicLength { 32 => Ok(BasicLength::Fourth), 64 => Ok(BasicLength::Half), 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 for BasicLength { BasicLength::SixtyFourth => 2, }; 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 { - let n1 : u16 = f(self); + let n1: u16 = f(self); let n2 = f(rhs); let total = n1 + n2; - + 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 { - 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 { - 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 { - 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 { - 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 { - 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 for BasicLength { #[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))); + 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)] pub enum ModdedLength { Plain(BasicLength), - Dotted(BasicLength) + Dotted(BasicLength), } impl KnownLength for ModdedLength { @@ -141,7 +180,7 @@ impl KnownLength for ModdedLength { ModdedLength::Plain(bl) => bl.to_128th(), ModdedLength::Dotted(bl) => { let l = bl.to_128th(); - l + l /2 + l + l / 2 } } } @@ -151,7 +190,7 @@ impl KnownLength for ModdedLength { pub enum Length { Simple(ModdedLength), Tied(ModdedLength, ModdedLength), - Triplet(ModdedLength) + Triplet(ModdedLength), } impl KnownLength for Length { @@ -159,7 +198,7 @@ impl KnownLength for Length { match self { Length::Simple(ml) => ml.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)] pub enum Note { Hit, - Rest + Rest, } use Note::*; #[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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -pub(crate) static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit); +pub(crate) static HIT: GroupOrNote = GroupOrNote::SingleNote(Note::Hit); #[allow(dead_code)] -pub(crate) static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest); +pub(crate) static REST: GroupOrNote = GroupOrNote::SingleNote(Note::Rest); #[allow(dead_code)] -pub(crate) static ONCE : &Times = &Times(1); +pub(crate) static ONCE: &Times = &Times(1); #[allow(dead_code)] pub(crate) static TWICE: &Times = &Times(2); #[allow(dead_code)] -pub(crate) static THRICE : &Times = &Times(3); +pub(crate) static THRICE: &Times = &Times(3); #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] @@ -235,95 +289,145 @@ pub struct Times(pub u16); #[derive(Debug, Clone, PartialEq, Eq)] pub enum GroupOrNote { - SingleGroup(Group), - SingleNote(Note) + SingleGroup(Group), + SingleNote(Note), } use GroupOrNote::*; +/// There are two useful instantiations of this type: +/// `Group` acts as a recursive `Group`, dsl parser uses this as return type +/// `Group` is a non-recursive group. To go from recursive groups to not-recursive ones, try using `flatten_group`. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Group { - pub notes: Vec, +pub struct Group { + pub notes: Vec, pub length: Length, - pub times: Times + pub times: Times, } -impl Group { +impl Group { 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 { fn to_128th(&self) -> u32 { let mut acc = 0; let note_length = self.length.to_128th(); for group in self.notes.iter() { match group { - GroupOrNote::SingleGroup(subgroup) => { acc += subgroup.to_128th(); }, - GroupOrNote::SingleNote(_) => { acc += note_length; }, + GroupOrNote::SingleGroup(subgroup) => { + acc += subgroup.to_128th(); + } + GroupOrNote::SingleNote(_) => { + acc += note_length; + } } - }; + } acc * self.times.0 as u32 } } -impl KnownLength for Group { +impl KnownLength for Group { fn to_128th(&self) -> u32 { let mut acc = 0; let note_length = self.length.to_128th(); - println!("NOTE LENGTH: {}", note_length); for group in self.notes.iter() { match group { - GroupOrNote::SingleGroup(subgroup) => { acc += subgroup.to_128th(); }, - GroupOrNote::SingleNote(_) => { acc += note_length; }, + GroupOrNote::SingleGroup(subgroup) => { + acc += subgroup.to_128th(); + } + GroupOrNote::SingleNote(_) => { + acc += note_length; + } } - }; + } + acc * self.times.0 as u32 + } +} + +impl KnownLength for Group { + 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 } } #[test] 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); } -impl std::ops::Deref for Group { - type Target = Vec; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Groups(pub Vec>); - fn deref(&self) -> &Self::Target { - &self.notes +impl IntoIterator for Groups { + type Item = Group; + + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Groups(pub Vec); +impl FromIterator> for Groups { + fn from_iter>>(iter: T) -> Self { + Self(Vec::from_iter(iter)) + } +} impl KnownLength for Groups { 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 { 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] 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); } 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> { - map(char('-'), |_| { Note::Rest })(input) + map(char('-'), |_| Note::Rest)(input) } fn note(input: &str) -> IResult<&str, Note> { @@ -332,99 +436,316 @@ fn note(input: &str) -> IResult<&str, Note> { fn length_basic(input: &str) -> IResult<&str, BasicLength> { match map_res(digit1, str::parse)(input) { - Ok((r,1)) => Ok((r, BasicLength::Whole)), - Ok((r,2)) => Ok((r, BasicLength::Half)), - Ok((r,4)) => Ok((r, BasicLength::Fourth)), - Ok((r,8)) => Ok((r, BasicLength::Eighth)), - Ok((r,16)) => Ok((r, BasicLength::Sixteenth)), - Ok((r,32)) => Ok((r, BasicLength::ThirtySecond)), + Ok((r, 1)) => Ok((r, BasicLength::Whole)), + Ok((r, 2)) => Ok((r, BasicLength::Half)), + Ok((r, 4)) => Ok((r, BasicLength::Fourth)), + Ok((r, 8)) => Ok((r, BasicLength::Eighth)), + Ok((r, 16)) => Ok((r, BasicLength::Sixteenth)), + Ok((r, 32)) => Ok((r, BasicLength::ThirtySecond)), Ok((r, 64)) => Ok((r, BasicLength::SixtyFourth)), - Ok((r, _)) => { - Err(Err::Error(nom::error::make_error(r, nom::error::ErrorKind::Fail))) - }, - Err(e) => Err(e) + Ok((r, _)) => Err(Err::Error(nom::error::make_error( + r, + nom::error::ErrorKind::Fail, + ))), + Err(e) => Err(e), } } 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - let repeated = map(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) } ); +fn group(input: &str) -> IResult<&str, Group> { + let repeated = map( + 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)?; - 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> { delimited(char('('), group, char(')'))(input) } -pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group> { - alt((delimited_group, group))(input) +pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group> { + alt((delimited_group, group))(input) } 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) -> 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(input_groups: I) -> Groups +where + I: IntoIterator> +{ + 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] fn parse_length() { - 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("8t"), Ok(("", *EIGHTH_TRIPLET))); - assert_eq!(length("4.t"), Ok(("", *FOURTH_DOTTED_TRIPLET))); + 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("8t"), Ok(("", *EIGHTH_TRIPLET))); + assert_eq!(length("4.t"), Ok(("", *FOURTH_DOTTED_TRIPLET))); } #[test] 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!(groups("8x-(7,8xx"), Err(Err::Error(nom::error::make_error("(7,8xx", nom::error::ErrorKind::Eof)))); + assert_eq!( + 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] 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!(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()] }))); + 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!( + 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] 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] 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!(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)))); + 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!( + 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 // “-“ rest // 16x-- => 16th hit and 16th rests -// - 16x-xx-x-8txxx(3,16+32x-xx)4x-x- => x-xx-x- of 16th, then three hits of 8th triplets, repeat a group of tied 16+32th x-xx three times, then 4th x-x \ No newline at end of file +// - 16x-xx-x-8txxx(3,16+32x-xx)4x-x- => x-xx-x- of 16th, then three hits of 8th triplets, repeat a group of tied 16+32th x-xx three times, then 4th x-x diff --git a/src/midi/core.rs b/src/midi/core.rs index e351885..fe5b797 100644 --- a/src/midi/core.rs +++ b/src/midi/core.rs @@ -14,7 +14,7 @@ use midly::{MetaMessage, TrackEvent}; use crate::dsl::dsl::{ 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 GroupOrNote::*; @@ -201,7 +201,21 @@ impl EventGrid { } } -// FIXME: add a mutable version for use in `flatten_groups` +impl EventGrid +where + T: Clone +{ + pub fn extend(&self, other: &EventGrid) -> EventGrid { + 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 + Clone + Ord + std::fmt::Debug> Add for EventGrid { type Output = EventGrid; @@ -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, /// so we need it to cycle the group. -fn flatten_group( +fn group_to_event_grid( Group { notes, length, times, - }: &Group, + }: &Group, part: Part, start: &Tick, ) -> EventGrid { @@ -418,18 +432,19 @@ fn flatten_group( let mut grid = EventGrid::empty(); notes.iter().for_each(|entry| { match entry { - SingleGroup(group) => { - let mut eg = flatten_group(&group, part, &time.clone()); - grid.events.append(&mut eg.events); - grid.length = grid.length + eg.length; - time = time + grid.length; - } - SingleNote(Note::Rest) => { + // SingleGroup(group) => { + // let mut eg = group_to_event_grid(&group, part, &time.clone()); + // println!("SINGLE GROUP EVENTGRID: {:?}", eg); + // grid.events.append(&mut eg.events); + // grid.length = grid.length + eg.length; + // time = time + grid.length; + // } + Rest => { let rest_end = time + note_length; time = rest_end; grid.length = rest_end; } - SingleNote(Note::Hit) => { + Hit => { let note_end = time + note_length; let note_on = Event { tick: time, @@ -451,11 +466,11 @@ fn flatten_group( } #[test] -fn test_flatten_group() { +fn test_group_to_event_grid() { let start_time = Tick(0); assert_eq!( - flatten_group( - &group_or_delimited_group("(2,8x--)").unwrap().1, + group_to_event_grid( + flatten_group(group_or_delimited_group("(2,8x--)").unwrap().1).0.first().unwrap(), KickDrum, &start_time ), @@ -500,13 +515,17 @@ fn test_cycle_grid() { /// Takes multiple `Group`s and turn them into a single `EventGrid`. /// The point of it is to combine timings into a single MIDI track. -fn flatten_groups(part: Part, groups: &Groups) -> EventGrid { +fn groups_to_event_grid(part: Part, groups: &Groups) -> EventGrid { let mut time: Tick = Tick(0); let mut grid: EventGrid = EventGrid::empty(); 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. - 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; }); grid @@ -574,13 +593,13 @@ impl Iterator for EventIterator { #[test] fn test_event_iterator_impl() { let empty = EventGrid::empty(); - let kick1 = flatten_group( - &group_or_delimited_group("(4x-)").unwrap().1, + let kick1 = group_to_event_grid( + &flatten_group(group_or_delimited_group("(4x-)").unwrap().1).0.first().unwrap(), KickDrum, &mut Tick(0), ); - let snare1 = flatten_group( - &group_or_delimited_group("4-x").unwrap().1, + let snare1 = group_to_event_grid( + &flatten_group(group_or_delimited_group("(4-x)").unwrap().1).0.first().unwrap(), SnareDrum, &mut Tick(0), ); @@ -642,7 +661,7 @@ fn test_event_iterator_impl() { /// 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. -fn flatten_to_iterator( +fn merge_to_iterator( groups: BTreeMap, time_signature: TimeSignature, ) -> EventIterator { @@ -677,7 +696,7 @@ fn flatten_to_iterator( let length_128th = length_map.get(part).unwrap(); let times = length_limit / length_128th; println!("TIMES: {}", times); - let flattened = flatten_groups(*part, groups); + let flattened = groups_to_event_grid(*part, groups); println!("FLATTENED: {:?}", flattened); (flattened, times) } @@ -702,14 +721,14 @@ fn flatten_to_iterator( } #[test] -fn test_flatten_to_iterator() { +fn test_merge_to_iterator() { let snare_group = "8-x--x-"; 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 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 flattened_kick_and_snare = flatten_to_iterator( + let flattened_kick_and_snare = merge_to_iterator( BTreeMap::from_iter([ (KickDrum, groups("16xx-x-xx-").unwrap().1), (SnareDrum, groups("8-x--x-").unwrap().1), @@ -718,8 +737,8 @@ fn test_flatten_to_iterator() { ) .collect::>>(); - assert_eq!(flatten_to_iterator(BTreeMap::from_iter([(KickDrum, groups(kick_group).unwrap().1)]), four_fourth).collect::>>(), kick_events); - assert_eq!(flatten_to_iterator(BTreeMap::from_iter([(SnareDrum, groups(snare_group).unwrap().1)]), four_fourth).collect::>>(), snare_events); + assert_eq!(merge_to_iterator(BTreeMap::from_iter([(KickDrum, groups(kick_group).unwrap().1)]), four_fourth).collect::>>(), kick_events); + assert_eq!(merge_to_iterator(BTreeMap::from_iter([(SnareDrum, groups(snare_group).unwrap().1)]), four_fourth).collect::>>(), snare_events); assert_eq!( kick_events .iter() @@ -765,7 +784,7 @@ fn create_tracks<'a>( text_event: &'a str, midi_tempo: MidiTempo ) -> Vec>> { - 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> = events_iter.collect(); // Notice this time can be incorrect, but it shouldn't matter. let time = match events.last() {