Fix a number of bugs

This commit is contained in:
Denis Redozubov 2023-06-09 13:54:30 +04:00
parent e4e8c5c402
commit 9e49156acb
3 changed files with 185 additions and 114 deletions

View file

@ -55,16 +55,30 @@ impl KnownLength for BasicLength {
} }
impl BasicLength { impl BasicLength {
/// Unsafe method, so it should only be used from `add`. pub fn from_num(n: u16) -> Result<Self, String> {
fn from_num(n: u16) -> Result<Self, String> {
match n { match n {
1 => Ok(BasicLength::SixtyFourth), 64 => Ok(BasicLength::SixtyFourth),
2 => Ok(BasicLength::ThirtySecond), 32 => Ok(BasicLength::ThirtySecond),
4 => Ok(BasicLength::Sixteenth), 16 => Ok(BasicLength::Sixteenth),
8 => Ok(BasicLength::Eighth), 8 => Ok(BasicLength::Eighth),
16 => Ok(BasicLength::Fourth), 4 => Ok(BasicLength::Fourth),
32 => Ok(BasicLength::Half), 2 => Ok(BasicLength::Half),
64 => Ok(BasicLength::Whole), 1 => Ok(BasicLength::Whole),
e => Err(format!("{} is not a num BasicLength can be constructed from", e))
}
}
/// Private unsafe method, so it should only be used from `add`.
/// Reverses `to_128th`.
fn from_128th(n: u16) -> Result<Self, String> {
match n {
2 => Ok(BasicLength::SixtyFourth),
4 => Ok(BasicLength::ThirtySecond),
8 => Ok(BasicLength::Sixteenth),
16 => Ok(BasicLength::Eighth),
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))
} }
} }
@ -75,33 +89,33 @@ impl Add<BasicLength> for BasicLength {
fn add(self, rhs: BasicLength) -> Length { fn add(self, rhs: BasicLength) -> Length {
let f = |x| match x { let f = |x| match x {
BasicLength::Whole => 64, BasicLength::Whole => 128,
BasicLength::Half => 32, BasicLength::Half => 64,
BasicLength::Fourth => 16, BasicLength::Fourth => 32,
BasicLength::Eighth => 8, BasicLength::Eighth => 16,
BasicLength::Sixteenth => 4, BasicLength::Sixteenth => 8,
BasicLength::ThirtySecond => 2, BasicLength::ThirtySecond => 4,
BasicLength::SixtyFourth => 1, BasicLength::SixtyFourth => 2,
}; };
if self == rhs && self != BasicLength::Whole { if self == rhs && self != BasicLength::Whole {
Length::Simple(ModdedLength::Plain(BasicLength::from_num(f(self) * 2).unwrap())) Length::Simple(ModdedLength::Plain(BasicLength::from_128th(f(self) * 2).unwrap()))
} else { } else {
let n1 : u16 = f(self); let n1 : u16 = f(self);
let n2 = f(rhs); let n2 = f(rhs);
let total = n1 + n2; let total = n1 + n2;
if total > 64 { if total > 128 {
Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_num(total - 64).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_128th(total - 128).unwrap()))
} else if total > 32 { } else if total > 32 {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 32).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 64).unwrap()))
} else if total > 16 { } else if total > 16 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 16).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 32).unwrap()))
} else if total > 8 { } else if total > 8 {
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_num(total - 8).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_128th(total - 16).unwrap()))
} else if total > 4 { } else if total > 4 {
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 4).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 8).unwrap()))
} else { } else {
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 2).unwrap())) Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 4).unwrap()))
} }
} }
} }

View file

@ -1,11 +1,12 @@
extern crate derive_more; extern crate derive_more;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::cmp::Ordering::*;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::iter::Peekable; use std::iter::Peekable;
use std::iter::{Cycle, Take}; use std::iter::{Cycle, Take};
use std::ops::{Add, Mul}; use std::ops::{Add, Mul};
use std::str::FromStr;
use std::path::Iter; use std::path::Iter;
use std::str::FromStr;
use std::time; use std::time;
use midly::{ use midly::{
@ -17,6 +18,8 @@ use crate::dsl::dsl::{
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Groups, KnownLength, Length, group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Groups, KnownLength, Length,
ModdedLength, Note, Times, ModdedLength, Note, Times,
}; };
use GroupOrNote::*;
use Note::*;
use crate::midi::time::TimeSignature; use crate::midi::time::TimeSignature;
#[allow(dead_code)] #[allow(dead_code)]
@ -64,19 +67,21 @@ pub enum EventType {
NoteOff(Part), NoteOff(Part),
} }
use EventType::*;
impl Ord for EventType { impl Ord for EventType {
fn cmp(&self, other: &EventType) -> Ordering { fn cmp(&self, other: &EventType) -> Ordering {
match (self, other) { match (self, other) {
(EventType::NoteOn(a), EventType::NoteOn(b)) => a.cmp(b), (NoteOn(a), NoteOn(b)) => a.cmp(b),
(EventType::NoteOn(a), EventType::NoteOff(b)) => match a.cmp(b) { (NoteOn(a), NoteOff(b)) => match a.cmp(b) {
Ordering::Equal => Ordering::Greater, Equal => Greater,
ord => ord ord => ord,
}, },
(EventType::NoteOff(a), EventType::NoteOn(b)) => match a.cmp(b) { (NoteOff(a), NoteOn(b)) => match a.cmp(b) {
Ordering::Equal => Ordering::Less, Equal => Less,
ord => ord ord => ord,
}, },
(EventType::NoteOff(a), EventType::NoteOff(b)) => a.cmp(b), (NoteOff(a), NoteOff(b)) => a.cmp(b),
} }
} }
} }
@ -89,14 +94,16 @@ pub enum Part {
CrashCymbal, CrashCymbal,
} }
use Part::*;
impl Part { impl Part {
// https://computermusicresource.com/GM.Percussion.KeyMap.html // https://computermusicresource.com/GM.Percussion.KeyMap.html
fn to_midi_key(&self) -> u7 { fn to_midi_key(&self) -> u7 {
match self { match self {
Part::KickDrum => u7::from(36), KickDrum => u7::from(36),
Part::SnareDrum => u7::from(38), SnareDrum => u7::from(38),
Part::HiHat => u7::from(46), HiHat => u7::from(46),
Part::CrashCymbal => u7::from(49), CrashCymbal => u7::from(49),
} }
} }
} }
@ -110,26 +117,32 @@ pub struct Event<T> {
impl<T> PartialOrd for Event<T> impl<T> PartialOrd for Event<T>
where where
T: PartialOrd + Ord, T: PartialOrd + Ord,
Event<T>: Ord Event<T>: Ord,
{ {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
fn lt(&self, other: &Self) -> bool { fn lt(&self, other: &Self) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Less)) matches!(self.partial_cmp(other), Some(Less))
} }
fn le(&self, other: &Self) -> bool { fn le(&self, other: &Self) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) matches!(
self.partial_cmp(other),
Some(Less | Equal)
)
} }
fn gt(&self, other: &Self) -> bool { fn gt(&self, other: &Self) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Greater)) matches!(self.partial_cmp(other), Some(Greater))
} }
fn ge(&self, other: &Self) -> bool { fn ge(&self, other: &Self) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Greater | Ordering::Equal)) matches!(
self.partial_cmp(other),
Some(Greater | Equal)
)
} }
} }
@ -150,18 +163,18 @@ where
fn test_ord_event_t() { fn test_ord_event_t() {
let first_on = Event { let first_on = Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}; };
let first_off = Event { let first_off = Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum), event_type: NoteOff(KickDrum),
}; };
let second_on = Event { let second_on = Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}; };
assert_eq!(first_on.cmp(&first_off), Ordering::Less); assert_eq!(first_on.cmp(&first_off), Less);
assert_eq!(first_off.cmp(&second_on), Ordering::Less); assert_eq!(first_off.cmp(&second_on), Less);
let mut vec1 = vec![second_on, first_off, first_on]; let mut vec1 = vec![second_on, first_off, first_on];
let mut vec2 = vec1.clone(); let mut vec2 = vec1.clone();
@ -234,11 +247,11 @@ fn test_arith_event_grids() {
events: vec![ events: vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}, },
Event { Event {
tick: Tick(TICKS_PER_QUARTER_NOTE as u128), tick: Tick(TICKS_PER_QUARTER_NOTE as u128),
event_type: EventType::NoteOff(Part::KickDrum), event_type: NoteOff(KickDrum),
}, },
], ],
length: Tick(TICKS_PER_QUARTER_NOTE as u128), length: Tick(TICKS_PER_QUARTER_NOTE as u128),
@ -247,11 +260,11 @@ fn test_arith_event_grids() {
events: vec![ events: vec![
Event { Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOn(Part::HiHat), event_type: NoteOn(HiHat),
}, },
Event { Event {
tick: Tick(TICKS_PER_QUARTER_NOTE as u128), tick: Tick(TICKS_PER_QUARTER_NOTE as u128),
event_type: EventType::NoteOff(Part::HiHat), event_type: NoteOff(HiHat),
}, },
], ],
length: Tick(TICKS_PER_QUARTER_NOTE as u128), length: Tick(TICKS_PER_QUARTER_NOTE as u128),
@ -260,19 +273,19 @@ fn test_arith_event_grids() {
events: vec![ events: vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}, },
Event { Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOn(Part::HiHat), event_type: NoteOn(HiHat),
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOff(Part::KickDrum), event_type: NoteOff(KickDrum),
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOff(Part::HiHat), event_type: NoteOff(HiHat),
}, },
], ],
length: Tick(96), length: Tick(96),
@ -286,11 +299,11 @@ fn test_add_event_grid() {
let empty: EventGrid<Tick> = EventGrid::empty(); let empty: EventGrid<Tick> = EventGrid::empty();
let kick_on = Event { let kick_on = Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}; };
let kick_off = Event { let kick_off = Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum), event_type: NoteOff(KickDrum),
}; };
let simple_grid = EventGrid { let simple_grid = EventGrid {
events: vec![kick_on, kick_off], events: vec![kick_on, kick_off],
@ -305,19 +318,19 @@ fn test_add_event_grid() {
events: vec![ events: vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(72), tick: Tick(72),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
} }
], ],
length: Tick(96) length: Tick(96)
@ -460,25 +473,25 @@ fn flatten_group(
let mut grid = EventGrid::empty(); let mut grid = EventGrid::empty();
notes.iter().for_each(|entry| { notes.iter().for_each(|entry| {
match entry { match entry {
crate::dsl::dsl::GroupOrNote::SingleGroup(group) => { SingleGroup(group) => {
let mut eg = flatten_group(&group, part, time); let mut eg = flatten_group(&group, part, time);
grid.events.append(&mut eg.events); grid.events.append(&mut eg.events);
grid.length = grid.length + eg.length; grid.length = grid.length + eg.length;
} }
crate::dsl::dsl::GroupOrNote::SingleNote(Note::Rest) => { SingleNote(Note::Rest) => {
let rest_end = *time + note_length; let rest_end = *time + note_length;
*time = rest_end; *time = rest_end;
grid.length = rest_end; grid.length = rest_end;
} }
crate::dsl::dsl::GroupOrNote::SingleNote(Note::Hit) => { SingleNote(Note::Hit) => {
let note_end = *time + note_length; let note_end = *time + note_length;
let note_on = Event { let note_on = Event {
tick: *time, tick: *time,
event_type: EventType::NoteOn(part), event_type: NoteOn(part),
}; };
let note_off = Event { let note_off = Event {
tick: note_end, tick: note_end,
event_type: EventType::NoteOff(part), event_type: NoteOff(part),
}; };
grid.events.push(note_on); grid.events.push(note_on);
grid.events.push(note_off); grid.events.push(note_off);
@ -496,26 +509,26 @@ fn test_flatten_group() {
assert_eq!( assert_eq!(
flatten_group( flatten_group(
&group_or_delimited_group("(2,8x--)").unwrap().1, &group_or_delimited_group("(2,8x--)").unwrap().1,
Part::KickDrum, KickDrum,
&mut Tick(0) &mut Tick(0)
), ),
EventGrid { EventGrid {
events: vec![ events: vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
}, },
Event { Event {
tick: Tick(72), tick: Tick(72),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(96), tick: Tick(96),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
} }
], ],
length: Tick(144) length: Tick(144)
@ -537,11 +550,11 @@ fn test_cycle_grid() {
assert_eq!(cycle_grid(EventGrid::empty(), Times(2)), empty); assert_eq!(cycle_grid(EventGrid::empty(), Times(2)), empty);
let kick_on = Event { let kick_on = Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum), event_type: NoteOn(KickDrum),
}; };
let kick_off = Event { let kick_off = Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum), event_type: NoteOff(KickDrum),
}; };
let simple_grid = EventGrid { let simple_grid = EventGrid {
events: vec![kick_on, kick_off], events: vec![kick_on, kick_off],
@ -555,19 +568,19 @@ fn test_cycle_grid() {
events: vec![ events: vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(24), tick: Tick(24),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(72), tick: Tick(72),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
} }
], ],
length: Tick(96) length: Tick(96)
@ -621,10 +634,10 @@ impl Iterator for EventIterator {
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let candidates: BTreeMap<Part, Event<Tick>> = [ let candidates: BTreeMap<Part, Event<Tick>> = [
(Part::KickDrum, self.kick.peek()), (KickDrum, self.kick.peek()),
(Part::SnareDrum, self.snare.peek()), (SnareDrum, self.snare.peek()),
(Part::HiHat, self.hihat.peek()), (HiHat, self.hihat.peek()),
(Part::CrashCymbal, self.crash.peek()), (CrashCymbal, self.crash.peek()),
] ]
.into_iter() .into_iter()
.filter_map(|(p, x)| match x { .filter_map(|(p, x)| match x {
@ -633,17 +646,17 @@ impl Iterator for EventIterator {
}) })
.collect(); .collect();
if let Some((min_part, min_event)) = candidates.iter().min_by_key(|(_,x)| *x) { if let Some((min_part, min_event)) = candidates.iter().min_by_key(|(_, x)| *x) {
match min_part { match min_part {
Part::KickDrum => self.kick.next(), KickDrum => self.kick.next(),
Part::SnareDrum => self.snare.next(), SnareDrum => self.snare.next(),
Part::HiHat => self.hihat.next(), HiHat => self.hihat.next(),
Part::CrashCymbal => self.crash.next(), CrashCymbal => self.crash.next(),
}; };
Some(*min_event) Some(*min_event)
} else { } else {
None None
} }
} }
} }
@ -652,15 +665,15 @@ fn test_event_iterator_impl() {
let empty = EventGrid::empty(); let empty = EventGrid::empty();
let kick1 = flatten_group( let kick1 = flatten_group(
&group_or_delimited_group("(4x-)").unwrap().1, &group_or_delimited_group("(4x-)").unwrap().1,
Part::KickDrum, KickDrum,
&mut Tick(0), &mut Tick(0),
); );
let snare1 = flatten_group( let snare1 = flatten_group(
&group_or_delimited_group("4-x").unwrap().1, &group_or_delimited_group("4-x").unwrap().1,
Part::SnareDrum, SnareDrum,
&mut Tick(0), &mut Tick(0),
); );
assert_eq!( assert_eq!(
EventIterator::new( EventIterator::new(
kick1.clone(), kick1.clone(),
@ -674,19 +687,19 @@ fn test_event_iterator_impl() {
vec![ vec![
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOn(Part::SnareDrum) event_type: NoteOn(SnareDrum)
}, },
Event { Event {
tick: Tick(96), tick: Tick(96),
event_type: EventType::NoteOff(Part::SnareDrum) event_type: NoteOff(SnareDrum)
} }
] ]
); );
@ -704,11 +717,11 @@ fn test_event_iterator_impl() {
[ [
Event { Event {
tick: Tick(0), tick: Tick(0),
event_type: EventType::NoteOn(Part::KickDrum) event_type: NoteOn(KickDrum)
}, },
Event { Event {
tick: Tick(48), tick: Tick(48),
event_type: EventType::NoteOff(Part::KickDrum) event_type: NoteOff(KickDrum)
} }
] ]
); );
@ -727,52 +740,54 @@ fn flatten_and_merge(
let converges_over_bars = time_signature let converges_over_bars = time_signature
.converges(groups.values()) .converges(groups.values())
.unwrap_or(BAR_LIMIT.clone()); .unwrap_or(BAR_LIMIT.clone());
println!("Converges over {} bars", converges_over_bars);
let length_limit = converges_over_bars * time_signature.to_128th(); let length_limit = converges_over_bars * time_signature.to_128th();
println!("TimeSignature {:?} in 128th: {}", time_signature, time_signature.to_128th());
let (kick_grid, kick_repeats) = match groups.get(&Part::KickDrum) { println!("length limit in 128th notes: {}", length_limit);
let (kick_grid, kick_repeats) = match groups.get(&KickDrum) {
Some(groups) => { Some(groups) => {
let length_128th = length_map.get(&Part::KickDrum).unwrap(); let length_128th = length_map.get(&KickDrum).unwrap();
let number_of_groups = groups.0.len(); let number_of_groups = groups.0.len();
let times = length_limit / length_128th; let times = length_limit / length_128th;
// let iterator = flatten_groups(Part::KickDrum, groups).into_iter().cycle().take(number_of_groups * times as usize).peekable() // let iterator = flatten_groups(KickDrum, groups).into_iter().cycle().take(number_of_groups * times as usize).peekable()
( (
flatten_groups(Part::KickDrum, groups), flatten_groups(KickDrum, groups),
number_of_groups * times as usize, number_of_groups * times as usize,
) )
} }
None => (EventGrid::empty(), 0), None => (EventGrid::empty(), 0),
}; };
let (snare_grid, snare_repeats) = match groups.get(&Part::SnareDrum) { let (snare_grid, snare_repeats) = match groups.get(&SnareDrum) {
Some(groups) => { Some(groups) => {
let length_128th = length_map.get(&Part::SnareDrum).unwrap(); let length_128th = length_map.get(&SnareDrum).unwrap();
let number_of_groups = groups.0.len(); let number_of_groups = groups.0.len();
let times = length_limit / length_128th; let times = length_limit / length_128th;
( (
flatten_groups(Part::SnareDrum, groups), flatten_groups(SnareDrum, groups),
number_of_groups * times as usize, number_of_groups * times as usize,
) )
} }
None => (EventGrid::empty(), 0), None => (EventGrid::empty(), 0),
}; };
let (hihat_grid, hihat_repeats) = match groups.get(&Part::HiHat) { let (hihat_grid, hihat_repeats) = match groups.get(&HiHat) {
Some(groups) => { Some(groups) => {
let length_128th = length_map.get(&Part::HiHat).unwrap(); let length_128th = length_map.get(&HiHat).unwrap();
let number_of_groups = groups.0.len(); let number_of_groups = groups.0.len();
let times = length_limit / length_128th; let times = length_limit / length_128th;
( (
flatten_groups(Part::HiHat, groups), flatten_groups(HiHat, groups),
number_of_groups * times as usize, number_of_groups * times as usize,
) )
} }
None => (EventGrid::empty(), 0), None => (EventGrid::empty(), 0),
}; };
let (crash_grid, crash_repeats) = match groups.get(&Part::CrashCymbal) { let (crash_grid, crash_repeats) = match groups.get(&CrashCymbal) {
Some(groups) => { Some(groups) => {
let length_128th = length_map.get(&Part::CrashCymbal).unwrap(); let length_128th = length_map.get(&CrashCymbal).unwrap();
let number_of_groups = groups.0.len(); let number_of_groups = groups.0.len();
let times = length_limit / length_128th; let times = length_limit / length_128th;
( (
flatten_groups(Part::CrashCymbal, groups), flatten_groups(CrashCymbal, groups),
number_of_groups * times as usize, number_of_groups * times as usize,
) )
} }
@ -788,6 +803,34 @@ fn flatten_and_merge(
) )
} }
#[test]
fn test_flatten_and_merge() {
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), }, ];
let snare_events = [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) }];
let four_fourth = TimeSignature::from_str("4/4").unwrap();
// let kick_event_grid = EventGrid { events, length: Tick(48 * 4) };
let flattened_kick = flatten_and_merge(
HashMap::from_iter([(KickDrum, groups("16xx-x-xx-").unwrap().1)]),
four_fourth
).collect::<Vec<Event<Tick>>>();
let flattened_snare = flatten_and_merge(
HashMap::from_iter([(SnareDrum, groups("8-x--x-").unwrap().1)]),
four_fourth
).collect::<Vec<Event<Tick>>>();
let flattened_kick_and_snare = flatten_and_merge(
HashMap::from_iter([
(KickDrum, groups("16xx-x-xx-").unwrap().1),
(SnareDrum, groups("8-x--x-").unwrap().1)
]),
four_fourth
).collect::<Vec<Event<Tick>>>();
assert_eq!(flattened_kick, kick_events);
assert_eq!(flattened_snare, snare_events);
assert_eq!(flattened_kick.iter().all(|x| flattened_kick_and_snare.contains(x)), true);
}
// The length of a beat is not standard, so in order to fully describe the length of a MIDI tick the MetaMessage::Tempo event should be present. // The length of a beat is not standard, so in order to fully describe the length of a MIDI tick the MetaMessage::Tempo event should be present.
pub fn create_smf<'a>(groups: HashMap<Part, Groups>, time_signature: TimeSignature) -> Smf<'a> { pub fn create_smf<'a>(groups: HashMap<Part, Groups>, time_signature: TimeSignature) -> Smf<'a> {
let tracks = create_tracks(groups, time_signature); // FIXME let tracks = create_tracks(groups, time_signature); // FIXME
@ -812,7 +855,8 @@ fn create_tracks<'a>(
) -> Vec<Vec<midly::TrackEvent<'a>>> { ) -> Vec<Vec<midly::TrackEvent<'a>>> {
//FIXME: unhardcode time signature //FIXME: unhardcode time signature
let events_iter = flatten_and_merge(parts_and_groups, time_signature); let events_iter = flatten_and_merge(parts_and_groups, time_signature);
let events : Vec<Event<Tick>> = events_iter.collect(); let events: Vec<Event<Tick>> = events_iter.collect();
println!("events: {:?}", events);
// Notice this time can be incorrect, but it shouldn't matter. // Notice this time can be incorrect, but it shouldn't matter.
let time = match events.last() { let time = match events.last() {
Some(ev) => ev.tick, Some(ev) => ev.tick,
@ -831,11 +875,11 @@ fn create_tracks<'a>(
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))}); // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))});
for event in event_grid.events { for event in event_grid.events {
let midi_message = match event.event_type { let midi_message = match event.event_type {
EventType::NoteOn(part) => MidiMessage::NoteOn { NoteOn(part) => MidiMessage::NoteOn {
key: part.to_midi_key(), key: part.to_midi_key(),
vel: u7::from(120), vel: u7::from(120),
}, },
EventType::NoteOff(part) => MidiMessage::NoteOff { NoteOff(part) => MidiMessage::NoteOff {
key: part.to_midi_key(), key: part.to_midi_key(),
vel: u7::from(0), vel: u7::from(0),
}, },
@ -850,4 +894,4 @@ fn create_tracks<'a>(
} }
vec![drums] vec![drums]
} }

View file

@ -1,5 +1,7 @@
extern crate derive_more; extern crate derive_more;
use crate::dsl::dsl::{BasicLength, Group, GroupOrNote, KnownLength, Note, Times, EIGHTH, FOURTH}; use crate::dsl::dsl::{BasicLength, Group, GroupOrNote, KnownLength, Note, Times, EIGHTH, FOURTH};
use BasicLength::*;
use Note::*;
use std::cmp::Ordering; use std::cmp::Ordering;
use std; use std;
@ -18,7 +20,6 @@ impl TimeSignature {
denominator, denominator,
} }
} }
} }
impl FromStr for TimeSignature { impl FromStr for TimeSignature {
@ -45,6 +46,11 @@ impl FromStr for TimeSignature {
} }
} }
#[test]
fn test_time_signature_from_str() {
assert_eq!(TimeSignature::from_str("4/4").unwrap(), TimeSignature { numerator: 4, denominator: Fourth });
}
impl std::ops::Mul<u8> for TimeSignature { impl std::ops::Mul<u8> for TimeSignature {
type Output = TimeSignature; type Output = TimeSignature;
fn mul(self, rhs: u8) -> TimeSignature { fn mul(self, rhs: u8) -> TimeSignature {
@ -77,13 +83,20 @@ fn test_cmp_time_signature() {
impl KnownLength for TimeSignature { impl KnownLength for TimeSignature {
fn to_128th(&self) -> u32 { fn to_128th(&self) -> u32 {
println!("{}", self.denominator.to_128th());
self.denominator.to_128th() * self.numerator as u32 self.denominator.to_128th() * self.numerator as u32
} }
} }
#[test]
fn test_time_signature_known_length() {
assert_eq!(TimeSignature{numerator: 4, denominator: Fourth}.to_128th(), 128);
}
impl TimeSignature { impl TimeSignature {
pub fn converges<T: KnownLength, I: IntoIterator<Item = T>>(&self, multiple: I) -> Result<u32, String> { pub fn converges<T: KnownLength, I: IntoIterator<Item = T>>(&self, multiple: I) -> Result<u32, String> {
let bar_len = self.to_128th(); let bar_len = self.to_128th();
println!("bar_len: {}", bar_len);
let result = multiple let result = multiple
.into_iter() .into_iter()
.fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc)); .fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc));