mirror of
https://github.com/dredozubov/polyrhythmix.git
synced 2024-12-22 14:25:29 +00:00
WIP
This commit is contained in:
parent
9ad78242c5
commit
94a8340659
3 changed files with 499 additions and 134 deletions
|
@ -104,6 +104,7 @@ fn main() {
|
|||
|
||||
let mut groups = BTreeMap::new();
|
||||
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(hihat, Part::HiHat, &mut groups);
|
||||
validate_and_parse_part(crash, Part::CrashCymbal, &mut groups);
|
||||
|
|
104
src/dsl/dsl.rs
104
src/dsl/dsl.rs
|
@ -272,9 +272,9 @@ 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<Times> = GroupOrNote::SingleNote(Note::Hit);
|
||||
#[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)]
|
||||
pub(crate) static ONCE: &Times = &Times(1);
|
||||
|
@ -288,8 +288,8 @@ pub(crate) static THRICE: &Times = &Times(3);
|
|||
pub struct Times(pub u16);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum GroupOrNote {
|
||||
SingleGroup(Group<GroupOrNote>),
|
||||
pub enum GroupOrNote<T> {
|
||||
SingleGroup(Group<GroupOrNote<T>, T>),
|
||||
SingleNote(Note),
|
||||
}
|
||||
|
||||
|
@ -299,13 +299,13 @@ use GroupOrNote::*;
|
|||
/// `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)]
|
||||
pub struct Group<T> {
|
||||
pub struct Group<T, R> {
|
||||
pub notes: Vec<T>,
|
||||
pub length: Length,
|
||||
pub times: Times,
|
||||
pub times: R,
|
||||
}
|
||||
|
||||
impl<T> Group<T> {
|
||||
impl<T> Group<T, Times> {
|
||||
pub fn empty() -> Self {
|
||||
Group {
|
||||
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 {
|
||||
let mut acc = 0;
|
||||
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 {
|
||||
let mut acc = 0;
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,10 +382,10 @@ fn test_known_length_group() {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Groups(pub Vec<Group<Note>>);
|
||||
pub struct Groups(pub Vec<Group<Note, ()>>);
|
||||
|
||||
impl IntoIterator for Groups {
|
||||
type Item = Group<Note>;
|
||||
type Item = Group<Note, ()>;
|
||||
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
|
@ -394,8 +394,8 @@ impl IntoIterator for Groups {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Group<Note>> for Groups {
|
||||
fn from_iter<T: IntoIterator<Item = Group<Note>>>(iter: T) -> Self {
|
||||
impl FromIterator<Group<Note, ()>> for Groups {
|
||||
fn from_iter<T: IntoIterator<Item = Group<Note, ()>>>(iter: T) -> Self {
|
||||
Self(Vec::from_iter(iter))
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ fn test_known_length_groups() {
|
|||
let groups = Groups(vec![Group {
|
||||
notes: vec![Hit, Hit, Rest, Hit, Rest, Hit, Hit, Rest],
|
||||
length: SIXTEENTH.clone(),
|
||||
times: Times(1),
|
||||
times: (),
|
||||
}]);
|
||||
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)
|
||||
}
|
||||
|
||||
fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
|
||||
fn group(input: &str) -> IResult<&str, Group<GroupOrNote<Times>, Times>> {
|
||||
let repeated_syntax = map(
|
||||
tuple((
|
||||
times,
|
||||
char(','),
|
||||
length,
|
||||
many1(alt((
|
||||
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}),
|
||||
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}),
|
||||
map_res(note, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleNote(x))}),
|
||||
map_res(delimited_group, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleGroup(x))}),
|
||||
))),
|
||||
)),
|
||||
|(t, _, l, n)| (t, l, n),
|
||||
|
@ -503,8 +503,8 @@ fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
|
|||
tuple((
|
||||
length,
|
||||
many1(alt((
|
||||
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}),
|
||||
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}),
|
||||
map_res(note, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleNote(x))}),
|
||||
map_res(delimited_group, |x| -> Result<GroupOrNote<Times>, &str> { Ok(SingleGroup(x))}),
|
||||
))),
|
||||
)), |(l, vn)| (Times(1), l, vn));
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -538,30 +538,31 @@ pub fn groups(input: &str) -> IResult<&str, Groups> {
|
|||
|
||||
pub fn flatten_groups<I>(input_groups: I) -> Groups
|
||||
where
|
||||
I: IntoIterator<Item = Group<GroupOrNote>>,
|
||||
I: IntoIterator<Item = Group<GroupOrNote<Times>, Times>>,
|
||||
{
|
||||
let mut out = Vec::new();
|
||||
input_groups.into_iter().for_each(|g| {
|
||||
let flattened = flatten_group(g).0;
|
||||
out.extend(flattened);
|
||||
});
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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();
|
||||
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 {
|
||||
SingleGroup(group) => {
|
||||
let isolated_group = Group {
|
||||
notes: note_group.clone(),
|
||||
length: input.length,
|
||||
times: Times(1),
|
||||
times: (),
|
||||
};
|
||||
out_groups.push(isolated_group);
|
||||
note_group.clear();
|
||||
|
@ -575,30 +576,23 @@ fn flatten_group_(input: &Group<GroupOrNote>, out_groups: &mut Vec<Group<Note>>)
|
|||
if !note_group.is_empty() {
|
||||
let isolated_group = Group {
|
||||
notes: note_group.clone(),
|
||||
length: input.length,
|
||||
times: input.times,
|
||||
length: group.length,
|
||||
times: (),
|
||||
};
|
||||
out_groups.push(isolated_group);
|
||||
}
|
||||
Groups(
|
||||
out_groups
|
||||
.iter()
|
||||
.cloned()
|
||||
.cycle()
|
||||
.take(out_groups.len() * (input.times.0 as usize))
|
||||
.collect(),
|
||||
)
|
||||
Groups(out_groups.iter().cloned().collect())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatten_group() {
|
||||
let output = Groups(vec![
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
|
||||
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
|
||||
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
|
||||
Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
|
||||
Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
|
||||
Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
|
||||
Group { notes: vec![Hit], length: *SIXTEENTH, times: () },
|
||||
Group { notes: vec![Rest, Hit, Rest, Hit], length: *EIGHTH, times: () },
|
||||
]);
|
||||
// basically it's 3,16x(2,8-x)
|
||||
let input = Group {
|
||||
|
@ -641,23 +635,23 @@ fn test_parse_groups() {
|
|||
Group {
|
||||
notes: vec![Hit, Rest],
|
||||
length: *EIGHTH,
|
||||
times: Times(1)
|
||||
times: ()
|
||||
},
|
||||
Group {
|
||||
notes: vec![Hit, Hit],
|
||||
notes: vec![Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit, Hit],
|
||||
length: *EIGHTH,
|
||||
times: Times(7)
|
||||
times: ()
|
||||
}
|
||||
])
|
||||
))
|
||||
);
|
||||
// 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"),
|
||||
Err(Err::Error(nom::error::make_error(
|
||||
"(7,8xx",
|
||||
nom::error::ErrorKind::Eof
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
528
src/midi/core.rs
528
src/midi/core.rs
|
@ -17,6 +17,7 @@ use crate::dsl::dsl::{
|
|||
};
|
||||
use crate::midi::time::TimeSignature;
|
||||
use GroupOrNote::*;
|
||||
use Note::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
static BAR_LIMIT: u32 = 1000;
|
||||
|
@ -199,7 +200,7 @@ impl EventGrid<Tick> {
|
|||
} else {
|
||||
match events.first() {
|
||||
Some(x) => x.tick,
|
||||
None => Tick(0)
|
||||
None => Tick(0),
|
||||
}
|
||||
};
|
||||
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`
|
||||
/// 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 `unsafe_extend`.
|
||||
impl EventGrid<Tick> {
|
||||
fn extend(&self, other: EventGrid<Tick>) -> EventGrid<Tick> {
|
||||
// FIXME: get rid of unnecessary cloning
|
||||
|
@ -257,8 +238,53 @@ impl EventGrid<Tick> {
|
|||
});
|
||||
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()}
|
||||
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]
|
||||
|
@ -283,19 +309,86 @@ fn test_extend_event_grid() {
|
|||
assert_eq!(
|
||||
simple_grid.clone().extend(simple_grid.clone()),
|
||||
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),
|
||||
end: Tick(96)
|
||||
}
|
||||
);
|
||||
|
||||
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),
|
||||
end: Tick(144),
|
||||
};
|
||||
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),
|
||||
end: Tick(264),
|
||||
};
|
||||
|
@ -308,14 +401,26 @@ fn test_extend_event_grid() {
|
|||
],
|
||||
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));
|
||||
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!(
|
||||
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,
|
||||
length,
|
||||
times,
|
||||
}: &Group<Note>,
|
||||
}: &Group<Note, ()>,
|
||||
part: Part,
|
||||
start: &Tick,
|
||||
) -> EventGrid<Tick> {
|
||||
|
@ -482,23 +587,26 @@ fn group_to_event_grid(
|
|||
}
|
||||
};
|
||||
});
|
||||
println!("GRID before cycling: {:?}", grid);
|
||||
// FIXME: this one fails. Either fix the cycle_grid and underlying operations (best) or reimplement a hack here(worst)
|
||||
cycle_grid(grid, *times)
|
||||
grid
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_to_event_grid() {
|
||||
let start_time = Tick(12);
|
||||
let group = Group {
|
||||
notes: vec![Note::Hit],
|
||||
notes: vec![Hit, Hit],
|
||||
length: SIXTEENTH.clone(),
|
||||
times: Times(15),
|
||||
times: (),
|
||||
};
|
||||
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,
|
||||
end: Tick(192),
|
||||
end: Tick(36),
|
||||
};
|
||||
assert_eq!(group_to_event_grid(&group, HiHat, &start_time), grid);
|
||||
// assert_eq!(
|
||||
|
@ -516,26 +624,79 @@ fn cycle_grid(event_grid: EventGrid<Tick>, times: Times) -> EventGrid<Tick> {
|
|||
EventGrid::empty()
|
||||
} else {
|
||||
// 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]
|
||||
fn test_cycle_grid() {
|
||||
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)),
|
||||
EventGrid::empty()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
cycle_grid(EventGrid { events: Vec::new(), start: Tick(96), end: Tick(144) }, Times(2)),
|
||||
EventGrid { events: Vec::new(), start: Tick(96), end: Tick(192) }
|
||||
cycle_grid(
|
||||
EventGrid {
|
||||
events: Vec::new(),
|
||||
start: Tick(96),
|
||||
end: Tick(144)
|
||||
},
|
||||
Times(2)
|
||||
),
|
||||
EventGrid {
|
||||
events: Vec::new(),
|
||||
start: Tick(96),
|
||||
end: Tick(192)
|
||||
}
|
||||
);
|
||||
|
||||
let empty: EventGrid<Tick> = EventGrid::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),
|
||||
end: Tick(48),
|
||||
};
|
||||
|
@ -546,17 +707,84 @@ fn test_cycle_grid() {
|
|||
assert_eq!(
|
||||
cycle_grid(simple_grid.clone(), Times(2)),
|
||||
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)
|
||||
)
|
||||
);
|
||||
|
||||
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),
|
||||
);
|
||||
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),
|
||||
);
|
||||
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| {
|
||||
// `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.
|
||||
let flattened_group = group_to_event_grid(group, part, &time);
|
||||
if part == CrashCymbal {
|
||||
println!("GROUPS: {:?}", groups);
|
||||
println!(
|
||||
"(groups_to_event_grid) FLATTENED GROUP TIME: {:?} - {:?}",
|
||||
part, flattened_group
|
||||
);
|
||||
}
|
||||
|
||||
let new_grid = group_to_event_grid(group, part, &time);
|
||||
println!("(groups_to_event_grid) GRID: {:?}", grid);
|
||||
println!("(groups_to_event_grid) NEW GRID: {:?}", grid);
|
||||
// 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;
|
||||
});
|
||||
grid
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct EventIterator {
|
||||
kick: 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();
|
||||
println!("LENGTH LIMIT: {}", length_limit);
|
||||
|
||||
let flatten = |part| {
|
||||
let to_event_grid = |part| {
|
||||
println!("FLATTENING {:?}", part);
|
||||
match groups.get(part) {
|
||||
Some(groups) => {
|
||||
let length_128th = length_map.get(part).unwrap();
|
||||
let times = length_limit / length_128th;
|
||||
println!("TIMES: {}", times);
|
||||
let flattened = groups_to_event_grid(*part, groups);
|
||||
(flattened, times)
|
||||
let event_grid = groups_to_event_grid(*part, groups);
|
||||
(event_grid, times)
|
||||
}
|
||||
None => (EventGrid::empty(), 0),
|
||||
}
|
||||
};
|
||||
|
||||
let (kick_grid, kick_repeats) = flatten(&KickDrum);
|
||||
let (snare_grid, snare_repeats) = flatten(&SnareDrum);
|
||||
let (hihat_grid, hihat_repeats) = flatten(&HiHat);
|
||||
let (crash_grid, crash_repeats) = flatten(&CrashCymbal);
|
||||
let (kick_grid, kick_repeats) = to_event_grid(&KickDrum);
|
||||
let (snare_grid, snare_repeats) = to_event_grid(&SnareDrum);
|
||||
let (hihat_grid, hihat_repeats) = to_event_grid(&HiHat);
|
||||
let (crash_grid, crash_repeats) = to_event_grid(&CrashCymbal);
|
||||
|
||||
println!(
|
||||
"CYCLED TO: {:?}",
|
||||
cycle_grid(crash_grid.clone(), Times(crash_repeats as u16))
|
||||
);
|
||||
// println!(
|
||||
// "CYCLED TO: {:?}",
|
||||
// cycle_grid(crash_grid.clone(), Times(crash_repeats as u16))
|
||||
// );
|
||||
|
||||
EventIterator::new(
|
||||
cycle_grid(kick_grid, Times(kick_repeats as u16)),
|
||||
cycle_grid(snare_grid, Times(snare_repeats as u16)),
|
||||
cycle_grid(hihat_grid, Times(hihat_repeats as u16)),
|
||||
cycle_grid(crash_grid, Times(crash_repeats as u16)),
|
||||
concat_grid(kick_grid, Times(kick_repeats as u16)),
|
||||
concat_grid(snare_grid, Times(snare_repeats as u16)),
|
||||
concat_grid(hihat_grid, Times(hihat_repeats as u16)),
|
||||
concat_grid(crash_grid, Times(crash_repeats as u16)),
|
||||
time_signature,
|
||||
)
|
||||
}
|
||||
|
@ -783,8 +1006,154 @@ fn test_merge_into_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 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 = merge_into_iterator(
|
||||
BTreeMap::from_iter([
|
||||
|
@ -829,10 +1198,10 @@ pub fn create_smf<'a>(
|
|||
text: &'a str,
|
||||
tempo: u16,
|
||||
) -> Smf<'a> {
|
||||
let tracks = create_tracks(groups, time_signature, text, MidiTempo::from_tempo(tempo)); // FIXME
|
||||
// https://majicdesigns.github.io/MD_MIDIFile/page_timing.html
|
||||
// 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.
|
||||
let tracks = create_tracks(groups, time_signature, text, MidiTempo::from_tempo(tempo));
|
||||
// https://majicdesigns.github.io/MD_MIDIFile/page_timing.html
|
||||
// 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.
|
||||
let metrical = midly::Timing::Metrical(TICKS_PER_QUARTER_NOTE.into());
|
||||
Smf {
|
||||
header: Header {
|
||||
|
@ -862,6 +1231,7 @@ fn create_tracks<'a>(
|
|||
midi_tempo: MidiTempo,
|
||||
) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
||||
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 track_time = match events.last() {
|
||||
|
|
Loading…
Reference in a new issue