This commit is contained in:
Denis Redozubov 2023-06-27 13:57:06 +04:00
parent 9ad78242c5
commit 94a8340659
3 changed files with 499 additions and 134 deletions

View file

@ -104,6 +104,7 @@ fn main() {
let mut groups = BTreeMap::new(); let mut groups = BTreeMap::new();
validate_and_parse_part(kick, Part::KickDrum, &mut groups); validate_and_parse_part(kick, Part::KickDrum, &mut groups);
println!("KICK GROUPS: {:?}", groups);
validate_and_parse_part(snare, Part::SnareDrum, &mut groups); validate_and_parse_part(snare, Part::SnareDrum, &mut groups);
validate_and_parse_part(hihat, Part::HiHat, &mut groups); validate_and_parse_part(hihat, Part::HiHat, &mut groups);
validate_and_parse_part(crash, Part::CrashCymbal, &mut groups); validate_and_parse_part(crash, Part::CrashCymbal, &mut groups);

View file

@ -272,9 +272,9 @@ pub(crate) static SIXTY_FOURTH_TRIPLET: &Length =
&Length::Triplet(ModdedLength::Plain(BasicLength::SixtyFourth)); &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<Times> = GroupOrNote::SingleNote(Note::Hit);
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) static REST: GroupOrNote = GroupOrNote::SingleNote(Note::Rest); pub(crate) static REST: GroupOrNote<Times> = GroupOrNote::SingleNote(Note::Rest);
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) static ONCE: &Times = &Times(1); pub(crate) static ONCE: &Times = &Times(1);
@ -288,8 +288,8 @@ pub(crate) static THRICE: &Times = &Times(3);
pub struct Times(pub u16); pub struct Times(pub u16);
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum GroupOrNote { pub enum GroupOrNote<T> {
SingleGroup(Group<GroupOrNote>), SingleGroup(Group<GroupOrNote<T>, T>),
SingleNote(Note), SingleNote(Note),
} }
@ -299,13 +299,13 @@ use GroupOrNote::*;
/// `Group<GroupOrNote>` acts as a recursive `Group`, dsl parser uses this as return 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`. /// `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<T> { pub struct Group<T, R> {
pub notes: Vec<T>, pub notes: Vec<T>,
pub length: Length, pub length: Length,
pub times: Times, pub times: R,
} }
impl<T> Group<T> { impl<T> Group<T, Times> {
pub fn empty() -> Self { pub fn empty() -> Self {
Group { Group {
notes: Vec::new(), notes: Vec::new(),
@ -315,7 +315,7 @@ impl<T> Group<T> {
} }
} }
impl KnownLength for &Group<GroupOrNote> { impl KnownLength for &Group<GroupOrNote<Times>, Times> {
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();
@ -333,7 +333,7 @@ impl KnownLength for &Group<GroupOrNote> {
} }
} }
impl KnownLength for Group<GroupOrNote> { impl KnownLength for Group<GroupOrNote<Times>, Times> {
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();
@ -351,14 +351,14 @@ impl KnownLength for Group<GroupOrNote> {
} }
} }
impl KnownLength for Group<Note> { impl KnownLength for Group<Note, ()> {
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() {
acc += note_length; acc += note_length;
} }
acc * self.times.0 as u32 acc
} }
} }
@ -382,10 +382,10 @@ fn test_known_length_group() {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Groups(pub Vec<Group<Note>>); pub struct Groups(pub Vec<Group<Note, ()>>);
impl IntoIterator for Groups { impl IntoIterator for Groups {
type Item = Group<Note>; type Item = Group<Note, ()>;
type IntoIter = std::vec::IntoIter<Self::Item>; type IntoIter = std::vec::IntoIter<Self::Item>;
@ -394,8 +394,8 @@ impl IntoIterator for Groups {
} }
} }
impl FromIterator<Group<Note>> for Groups { impl FromIterator<Group<Note, ()>> for Groups {
fn from_iter<T: IntoIterator<Item = Group<Note>>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = Group<Note, ()>>>(iter: T) -> Self {
Self(Vec::from_iter(iter)) Self(Vec::from_iter(iter))
} }
} }
@ -417,7 +417,7 @@ fn test_known_length_groups() {
let groups = Groups(vec![Group { let groups = Groups(vec![Group {
notes: vec![Hit, Hit, Rest, Hit, Rest, Hit, Hit, Rest], notes: vec![Hit, Hit, Rest, Hit, Rest, Hit, Hit, Rest],
length: SIXTEENTH.clone(), length: SIXTEENTH.clone(),
times: Times(1), times: (),
}]); }]);
assert_eq!(groups.to_128th(), 64); assert_eq!(groups.to_128th(), 64);
} }
@ -486,15 +486,15 @@ 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<GroupOrNote>> { fn group(input: &str) -> IResult<&str, Group<GroupOrNote<Times>, Times>> {
let repeated_syntax = map( let repeated_syntax = map(
tuple(( tuple((
times, times,
char(','), char(','),
length, length,
many1(alt(( many1(alt((
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}), map_res(note, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleNote(x))}),
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}), map_res(delimited_group, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleGroup(x))}),
))), ))),
)), )),
|(t, _, l, n)| (t, l, n), |(t, _, l, n)| (t, l, n),
@ -503,8 +503,8 @@ fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
tuple(( tuple((
length, length,
many1(alt(( many1(alt((
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}), map_res(note, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleNote(x))}),
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}), map_res(delimited_group, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleGroup(x))}),
))), ))),
)), |(l, vn)| (Times(1), l, vn)); )), |(l, vn)| (Times(1), l, vn));
let (rem, (t, l, n)) = alt((repeated_syntax, single_syntax))(input)?; let (rem, (t, l, n)) = alt((repeated_syntax, single_syntax))(input)?;
@ -520,11 +520,11 @@ fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
)) ))
} }
fn delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote>> { fn delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote<Times>, Times>> {
delimited(char('('), group, char(')'))(input) delimited(char('('), group, char(')'))(input)
} }
pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote>> { pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote<Times>, Times>> {
alt((delimited_group, group))(input) alt((delimited_group, group))(input)
} }
@ -538,30 +538,31 @@ pub fn groups(input: &str) -> IResult<&str, Groups> {
pub fn flatten_groups<I>(input_groups: I) -> Groups pub fn flatten_groups<I>(input_groups: I) -> Groups
where where
I: IntoIterator<Item = Group<GroupOrNote>>, I: IntoIterator<Item = Group<GroupOrNote<Times>, Times>>,
{ {
let mut out = Vec::new(); let mut out = Vec::new();
input_groups.into_iter().for_each(|g| { input_groups.into_iter().for_each(|g| {
let flattened = flatten_group(g).0; let flattened = flatten_group(g).0;
out.extend(flattened); out.extend(flattened);
}); });
Groups(out) Groups(out)
} }
pub fn flatten_group(input: Group<GroupOrNote>) -> Groups { pub fn flatten_group(input: Group<GroupOrNote<Times>, Times>) -> Groups {
flatten_group_(&input, &mut Vec::new()) flatten_group_(&input, &mut Vec::new())
} }
fn flatten_group_(input: &Group<GroupOrNote>, out_groups: &mut Vec<Group<Note>>) -> Groups { fn flatten_group_(input: &Group<GroupOrNote<Times>, Times>, out_groups: &mut Vec<Group<Note, ()>>) -> Groups {
let mut note_group = Vec::new(); let mut note_group = Vec::new();
input.notes.iter().for_each(|g| { let inlined_notes = input.notes.iter().cycle().take(input.notes.len() * input.times.0 as usize);
let group = Group { notes: inlined_notes.collect(), times: (), length: input.length };
group.notes.iter().for_each(|&g| {
match g { match g {
SingleGroup(group) => { SingleGroup(group) => {
let isolated_group = Group { let isolated_group = Group {
notes: note_group.clone(), notes: note_group.clone(),
length: input.length, length: input.length,
times: Times(1), times: (),
}; };
out_groups.push(isolated_group); out_groups.push(isolated_group);
note_group.clear(); note_group.clear();
@ -575,30 +576,23 @@ fn flatten_group_(input: &Group<GroupOrNote>, out_groups: &mut Vec<Group<Note>>)
if !note_group.is_empty() { if !note_group.is_empty() {
let isolated_group = Group { let isolated_group = Group {
notes: note_group.clone(), notes: note_group.clone(),
length: input.length, length: group.length,
times: input.times, times: (),
}; };
out_groups.push(isolated_group); out_groups.push(isolated_group);
} }
Groups( Groups(out_groups.iter().cloned().collect())
out_groups
.iter()
.cloned()
.cycle()
.take(out_groups.len() * (input.times.0 as usize))
.collect(),
)
} }
#[test] #[test]
fn test_flatten_group() { fn test_flatten_group() {
let output = Groups(vec![ let output = Groups(vec![
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) }, Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) }, Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) }, Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) }, Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) }, Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) }, Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
]); ]);
// basically it's 3,16x(2,8-x) // basically it's 3,16x(2,8-x)
let input = Group { let input = Group {
@ -641,23 +635,23 @@ fn test_parse_groups() {
Group { Group {
notes: vec![Hit, Rest], notes: vec![Hit, Rest],
length: *EIGHTH, length: *EIGHTH,
times: Times(1) times: ()
}, },
Group { Group {
notes: vec![Hit, Hit], notes: vec![Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit],
length: *EIGHTH, length: *EIGHTH,
times: Times(7) times: ()
} }
]) ])
)) ))
); );
// assert_eq!( assert_eq!(
// groups("8x-(7,8xx"), groups("8x-(7,8xx"),
// Err(Err::Error(nom::error::make_error( Err(Err::Error(nom::error::make_error(
// "(7,8xx", "(7,8xx",
// nom::error::ErrorKind::Eof nom::error::ErrorKind::Eof
// ))) )))
// ); );
} }
#[test] #[test]

View file

@ -17,6 +17,7 @@ use crate::dsl::dsl::{
}; };
use crate::midi::time::TimeSignature; use crate::midi::time::TimeSignature;
use GroupOrNote::*; use GroupOrNote::*;
use Note::*;
#[allow(dead_code)] #[allow(dead_code)]
static BAR_LIMIT: u32 = 1000; static BAR_LIMIT: u32 = 1000;
@ -199,7 +200,7 @@ impl EventGrid<Tick> {
} else { } else {
match events.first() { match events.first() {
Some(x) => x.tick, Some(x) => x.tick,
None => Tick(0) None => Tick(0),
} }
}; };
EventGrid { EventGrid {
@ -225,29 +226,9 @@ impl<T> EventGrid<T> {
} }
} }
impl<T> EventGrid<T>
where
T: Clone,
{
pub fn unsafe_extend(&self, other: &EventGrid<T>) -> EventGrid<T> {
let combined = self
.events
.iter()
.cloned()
.chain(other.events.iter().cloned())
.collect();
EventGrid {
events: combined,
end: self.end + other.end,
start: self.start,
}
}
}
// FIXME: add a mutable version for use in `groups_to_event_grid` // FIXME: add a mutable version for use in `groups_to_event_grid`
/// Adds two EventGrids together, manipulates the time of the right `EventGrid` by /// Adds two EventGrids together, manipulates the time of the right `EventGrid` by
/// adding the length of the left one to timings. /// adding the length of the left one to timings.
/// If you need to concat two `EventGrid`s without messing up with times, then use `unsafe_extend`.
impl EventGrid<Tick> { impl EventGrid<Tick> {
fn extend(&self, other: EventGrid<Tick>) -> EventGrid<Tick> { fn extend(&self, other: EventGrid<Tick>) -> EventGrid<Tick> {
// FIXME: get rid of unnecessary cloning // FIXME: get rid of unnecessary cloning
@ -257,10 +238,55 @@ impl EventGrid<Tick> {
}); });
let mut self_event_copy = self.events.clone(); let mut self_event_copy = self.events.clone();
self_event_copy.extend(other_events); self_event_copy.extend(other_events);
EventGrid { events: self_event_copy, start: self.start, end: self.start + self.length() + other.length()} EventGrid {
events: self_event_copy,
start: self.start,
end: self.start + self.length() + other.length(),
} }
} }
pub fn concat(&self, other: EventGrid<Tick>) -> EventGrid<Tick> {
// FIXME: get rid of unnecessary cloning
let other_events = other.clone().events.into_iter().map(|mut e| {
e.tick = e.tick + self.length();
e
});
let mut self_event_copy = self.events.clone();
self_event_copy.extend(other_events);
EventGrid {
events: self_event_copy,
start: self.start,
end: self.start + self.length() + other.length(),
}
}
}
#[test]
fn test_concat_event_grid() {
let input = EventGrid {
events: vec![
Event {
tick: Tick(12),
event_type: NoteOn(HiHat),
},
Event {
tick: Tick(24),
event_type: NoteOff(HiHat),
},
],
start: Tick(12),
end: Tick(24),
};
assert_eq!(
input.concat(input.clone()),
EventGrid {
events: vec![Event { tick: Tick(12), event_type: NoteOn(HiHat) }, Event { tick: Tick(24), event_type: NoteOff(HiHat) }, Event { tick: Tick(24), event_type: NoteOn(HiHat) }, Event { tick: Tick(36), event_type: NoteOff(HiHat) }],
start: Tick(12),
end: Tick(36)
}
);
}
#[test] #[test]
fn test_extend_event_grid() { fn test_extend_event_grid() {
let empty: EventGrid<Tick> = EventGrid::empty(); let empty: EventGrid<Tick> = EventGrid::empty();
@ -283,19 +309,86 @@ fn test_extend_event_grid() {
assert_eq!( assert_eq!(
simple_grid.clone().extend(simple_grid.clone()), simple_grid.clone().extend(simple_grid.clone()),
EventGrid { EventGrid {
events: vec![Event { tick: Tick(0), event_type: NoteOn(KickDrum) }, Event { tick: Tick(24), event_type: NoteOff(KickDrum) }, Event { tick: Tick(48), event_type: NoteOn(KickDrum) }, Event { tick: Tick(72), event_type: NoteOff(KickDrum) }], events: vec![
Event {
tick: Tick(0),
event_type: NoteOn(KickDrum)
},
Event {
tick: Tick(24),
event_type: NoteOff(KickDrum)
},
Event {
tick: Tick(48),
event_type: NoteOn(KickDrum)
},
Event {
tick: Tick(72),
event_type: NoteOff(KickDrum)
}
],
start: Tick(0), start: Tick(0),
end: Tick(96) end: Tick(96)
} }
); );
let events = EventGrid { let events = EventGrid {
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) }], 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),
},
],
start: Tick(24), start: Tick(24),
end: Tick(144), end: Tick(144),
}; };
let expected = EventGrid { let expected = EventGrid {
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(144 + 24), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(144 + 48), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(144 + 96), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(144 + 120), event_type: NoteOff(SnareDrum) }], 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(144 + 24),
event_type: NoteOn(SnareDrum),
},
Event {
tick: Tick(144 + 48),
event_type: NoteOff(SnareDrum),
},
Event {
tick: Tick(144 + 96),
event_type: NoteOn(SnareDrum),
},
Event {
tick: Tick(144 + 120),
event_type: NoteOff(SnareDrum),
},
],
start: Tick(24), start: Tick(24),
end: Tick(264), end: Tick(264),
}; };
@ -308,14 +401,26 @@ fn test_extend_event_grid() {
], ],
Tick(96), Tick(96),
); );
let events2_2: EventGrid<Tick> = EventGrid { events: vec![], start: Tick(96), end: Tick(192) }; let events2_2: EventGrid<Tick> = EventGrid {
events: vec![],
start: Tick(96),
end: Tick(192),
};
let result2 = EventGrid::new(events2_1.events.clone(), Tick(192)); let result2 = EventGrid::new(events2_1.events.clone(), Tick(192));
assert_eq!(events2_1.extend(events2_2), result2); assert_eq!(events2_1.extend(events2_2), result2);
let events3 = EventGrid { events: Vec::new(), start: Tick(96), end: Tick(144) }; let events3 = EventGrid {
events: Vec::new(),
start: Tick(96),
end: Tick(144),
};
assert_eq!( assert_eq!(
events3.extend(events3.clone()), events3.extend(events3.clone()),
EventGrid { events: Vec::new(), start: Tick(96), end: Tick(192) } EventGrid {
events: Vec::new(),
start: Tick(96),
end: Tick(192)
}
); );
} }
@ -450,7 +555,7 @@ fn group_to_event_grid(
notes, notes,
length, length,
times, times,
}: &Group<Note>, }: &Group<Note, ()>,
part: Part, part: Part,
start: &Tick, start: &Tick,
) -> EventGrid<Tick> { ) -> EventGrid<Tick> {
@ -482,23 +587,26 @@ fn group_to_event_grid(
} }
}; };
}); });
println!("GRID before cycling: {:?}", grid); grid
// FIXME: this one fails. Either fix the cycle_grid and underlying operations (best) or reimplement a hack here(worst)
cycle_grid(grid, *times)
} }
#[test] #[test]
fn test_group_to_event_grid() { fn test_group_to_event_grid() {
let start_time = Tick(12); let start_time = Tick(12);
let group = Group { let group = Group {
notes: vec![Note::Hit], notes: vec![Hit, Hit],
length: SIXTEENTH.clone(), length: SIXTEENTH.clone(),
times: Times(15), times: (),
}; };
let grid = EventGrid { let grid = EventGrid {
events: vec![], events: vec![
Event { tick: Tick(12), event_type: NoteOn(HiHat) },
Event { tick: Tick(24), event_type: NoteOff(HiHat) },
Event { tick: Tick(24), event_type: NoteOn(HiHat) },
Event { tick: Tick(36), event_type: NoteOff(HiHat) }
],
start: start_time, start: start_time,
end: Tick(192), end: Tick(36),
}; };
assert_eq!(group_to_event_grid(&group, HiHat, &start_time), grid); assert_eq!(group_to_event_grid(&group, HiHat, &start_time), grid);
// assert_eq!( // assert_eq!(
@ -516,26 +624,79 @@ fn cycle_grid(event_grid: EventGrid<Tick>, times: Times) -> EventGrid<Tick> {
EventGrid::empty() EventGrid::empty()
} else { } else {
// FIXME: think about unnecessary cloning // FIXME: think about unnecessary cloning
(0..).take((times.0 - 1) as usize).fold(event_grid.clone(), |acc, _| acc.extend(event_grid.clone())) (0..)
.take((times.0 - 1) as usize)
.fold(event_grid.clone(), |acc, _| acc.extend(event_grid.clone()))
} }
} }
fn concat_grid(event_grid: EventGrid<Tick>, times: Times) -> EventGrid<Tick> {
if times.0 <= 0 {
EventGrid::empty()
} else {
// FIXME: think about unnecessary cloning
(0..)
.take((times.0 - 1) as usize)
.fold(event_grid.clone(), |acc, _| acc.concat(event_grid.clone()))
}
}
#[test]
fn test_concat_grid() {
assert_eq!(
concat_grid(
EventGrid {
events: vec![
Event {
tick: Tick(12),
event_type: NoteOn(HiHat)
},
Event {
tick: Tick(24),
event_type: NoteOff(HiHat)
}
],
start: Tick(12),
end: Tick(24)
},
Times(2)
),
EventGrid { events: vec![Event { tick: Tick(12), event_type: NoteOn(HiHat) }, Event { tick: Tick(24), event_type: NoteOff(HiHat) }, Event { tick: Tick(24), event_type: NoteOn(HiHat) }, Event { tick: Tick(36), event_type: NoteOff(HiHat) }], start: Tick(12), end: Tick(36) }
);
}
#[test] #[test]
fn test_cycle_grid() { fn test_cycle_grid() {
assert_eq!( assert_eq!(
cycle_grid(EventGrid { events: vec![Event { tick: Tick(12), event_type: NoteOn(HiHat) }, Event { tick: Tick(24), event_type: NoteOff(HiHat) }], start: Tick(12), end: Tick(24) }, Times(15)), cycle_grid(
EventGrid::empty() EventGrid {
); events: Vec::new(),
start: Tick(96),
assert_eq!( end: Tick(144)
cycle_grid(EventGrid { events: Vec::new(), start: Tick(96), end: Tick(144) }, Times(2)), },
EventGrid { events: Vec::new(), start: Tick(96), end: Tick(192) } Times(2)
),
EventGrid {
events: Vec::new(),
start: Tick(96),
end: Tick(192)
}
); );
let empty: EventGrid<Tick> = EventGrid::empty(); let empty: EventGrid<Tick> = EventGrid::empty();
assert_eq!(cycle_grid(EventGrid::empty(), Times(2)), empty); assert_eq!(cycle_grid(EventGrid::empty(), Times(2)), empty);
let simple_grid = EventGrid { events: vec![Event { tick: Tick(0), event_type: NoteOn(KickDrum) }, Event { tick: Tick(24), event_type: NoteOff(KickDrum) }], let simple_grid = EventGrid {
events: vec![
Event {
tick: Tick(0),
event_type: NoteOn(KickDrum),
},
Event {
tick: Tick(24),
event_type: NoteOff(KickDrum),
},
],
start: Tick(0), start: Tick(0),
end: Tick(48), end: Tick(48),
}; };
@ -546,17 +707,84 @@ fn test_cycle_grid() {
assert_eq!( assert_eq!(
cycle_grid(simple_grid.clone(), Times(2)), cycle_grid(simple_grid.clone(), Times(2)),
EventGrid::new( EventGrid::new(
vec![Event { tick: Tick(0), event_type: NoteOn(KickDrum) }, Event { tick: Tick(24), event_type: NoteOff(KickDrum) }, Event { tick: Tick(48), event_type: NoteOn(KickDrum) }, Event { tick: Tick(72), event_type: NoteOff(KickDrum) }], vec![
Event {
tick: Tick(0),
event_type: NoteOn(KickDrum)
},
Event {
tick: Tick(24),
event_type: NoteOff(KickDrum)
},
Event {
tick: Tick(48),
event_type: NoteOn(KickDrum)
},
Event {
tick: Tick(72),
event_type: NoteOff(KickDrum)
}
],
Tick(96) Tick(96)
) )
); );
let events = EventGrid::new( let events = EventGrid::new(
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) }], 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),
},
],
Tick(144), Tick(144),
); );
let expected = EventGrid::new( let expected = EventGrid::new(
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(144 + 24), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(144 + 48), event_type: NoteOff(SnareDrum) }, Event { tick: Tick(144 + 96), event_type: NoteOn(SnareDrum) }, Event { tick: Tick(144 + 120), event_type: NoteOff(SnareDrum) }], 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(144 + 24),
event_type: NoteOn(SnareDrum),
},
Event {
tick: Tick(144 + 48),
event_type: NoteOff(SnareDrum),
},
Event {
tick: Tick(144 + 96),
event_type: NoteOn(SnareDrum),
},
Event {
tick: Tick(144 + 120),
event_type: NoteOff(SnareDrum),
},
],
Tick(264), Tick(264),
); );
assert_eq!(cycle_grid(events.clone(), Times(2)), expected); assert_eq!(cycle_grid(events.clone(), Times(2)), expected);
@ -570,22 +798,17 @@ fn groups_to_event_grid(part: Part, groups: &Groups) -> EventGrid<Tick> {
groups.0.iter().for_each(|group| { groups.0.iter().for_each(|group| {
// `group_to_event_grid` 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.
let flattened_group = group_to_event_grid(group, part, &time); let new_grid = group_to_event_grid(group, part, &time);
if part == CrashCymbal { println!("(groups_to_event_grid) GRID: {:?}", grid);
println!("GROUPS: {:?}", groups); println!("(groups_to_event_grid) NEW GRID: {:?}", grid);
println!(
"(groups_to_event_grid) FLATTENED GROUP TIME: {:?} - {:?}",
part, flattened_group
);
}
// Note that using `+` is wrong here as it's messing with timings and it really shouldn't // Note that using `+` is wrong here as it's messing with timings and it really shouldn't
grid = grid.extend(flattened_group); grid = grid.extend(new_grid);
time = grid.end; time = grid.end;
}); });
grid grid
} }
#[derive(Clone, Debug)]
pub(crate) struct EventIterator { pub(crate) struct EventIterator {
kick: Peekable<std::vec::IntoIter<Event<Tick>>>, kick: Peekable<std::vec::IntoIter<Event<Tick>>>,
snare: Peekable<std::vec::IntoIter<Event<Tick>>>, snare: Peekable<std::vec::IntoIter<Event<Tick>>>,
@ -745,35 +968,35 @@ fn merge_into_iterator(
let length_limit = converges_over_bars * time_signature.to_128th(); let length_limit = converges_over_bars * time_signature.to_128th();
println!("LENGTH LIMIT: {}", length_limit); println!("LENGTH LIMIT: {}", length_limit);
let flatten = |part| { let to_event_grid = |part| {
println!("FLATTENING {:?}", part); println!("FLATTENING {:?}", part);
match groups.get(part) { match groups.get(part) {
Some(groups) => { Some(groups) => {
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 = groups_to_event_grid(*part, groups); let event_grid = groups_to_event_grid(*part, groups);
(flattened, times) (event_grid, times)
} }
None => (EventGrid::empty(), 0), None => (EventGrid::empty(), 0),
} }
}; };
let (kick_grid, kick_repeats) = flatten(&KickDrum); let (kick_grid, kick_repeats) = to_event_grid(&KickDrum);
let (snare_grid, snare_repeats) = flatten(&SnareDrum); let (snare_grid, snare_repeats) = to_event_grid(&SnareDrum);
let (hihat_grid, hihat_repeats) = flatten(&HiHat); let (hihat_grid, hihat_repeats) = to_event_grid(&HiHat);
let (crash_grid, crash_repeats) = flatten(&CrashCymbal); let (crash_grid, crash_repeats) = to_event_grid(&CrashCymbal);
println!( // println!(
"CYCLED TO: {:?}", // "CYCLED TO: {:?}",
cycle_grid(crash_grid.clone(), Times(crash_repeats as u16)) // cycle_grid(crash_grid.clone(), Times(crash_repeats as u16))
); // );
EventIterator::new( EventIterator::new(
cycle_grid(kick_grid, Times(kick_repeats as u16)), concat_grid(kick_grid, Times(kick_repeats as u16)),
cycle_grid(snare_grid, Times(snare_repeats as u16)), concat_grid(snare_grid, Times(snare_repeats as u16)),
cycle_grid(hihat_grid, Times(hihat_repeats as u16)), concat_grid(hihat_grid, Times(hihat_repeats as u16)),
cycle_grid(crash_grid, Times(crash_repeats as u16)), concat_grid(crash_grid, Times(crash_repeats as u16)),
time_signature, time_signature,
) )
} }
@ -783,8 +1006,154 @@ fn test_merge_into_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![
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) }]; 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 four_fourth = TimeSignature::from_str("4/4").unwrap();
let flattened_kick_and_snare = merge_into_iterator( let flattened_kick_and_snare = merge_into_iterator(
BTreeMap::from_iter([ BTreeMap::from_iter([
@ -829,7 +1198,7 @@ pub fn create_smf<'a>(
text: &'a str, text: &'a str,
tempo: u16, tempo: u16,
) -> Smf<'a> { ) -> Smf<'a> {
let tracks = create_tracks(groups, time_signature, text, MidiTempo::from_tempo(tempo)); // FIXME let tracks = create_tracks(groups, time_signature, text, MidiTempo::from_tempo(tempo));
// https://majicdesigns.github.io/MD_MIDIFile/page_timing.html // https://majicdesigns.github.io/MD_MIDIFile/page_timing.html
// says " If it is not specified the MIDI default is 48 ticks per quarter note." // says " If it is not specified the MIDI default is 48 ticks per quarter note."
// As it's required in `Header`, let's use the same value. // As it's required in `Header`, let's use the same value.
@ -862,6 +1231,7 @@ fn create_tracks<'a>(
midi_tempo: MidiTempo, midi_tempo: MidiTempo,
) -> Vec<Vec<midly::TrackEvent<'a>>> { ) -> Vec<Vec<midly::TrackEvent<'a>>> {
let events_iter = merge_into_iterator(parts_and_groups, time_signature); let events_iter = merge_into_iterator(parts_and_groups, time_signature);
println!("EVENTS_ITER: {:?}", events_iter.clone());
let events: Vec<Event<Tick>> = events_iter.collect(); let events: Vec<Event<Tick>> = events_iter.collect();
let track_time = match events.last() { let track_time = match events.last() {