mirror of
https://github.com/dredozubov/polyrhythmix.git
synced 2024-12-22 14:25:29 +00:00
Fix a number of bugs
This commit is contained in:
parent
e4e8c5c402
commit
9e49156acb
3 changed files with 185 additions and 114 deletions
|
@ -55,16 +55,30 @@ impl KnownLength for BasicLength {
|
|||
}
|
||||
|
||||
impl BasicLength {
|
||||
/// Unsafe method, so it should only be used from `add`.
|
||||
fn from_num(n: u16) -> Result<Self, String> {
|
||||
pub fn from_num(n: u16) -> Result<Self, String> {
|
||||
match n {
|
||||
1 => Ok(BasicLength::SixtyFourth),
|
||||
2 => Ok(BasicLength::ThirtySecond),
|
||||
4 => Ok(BasicLength::Sixteenth),
|
||||
64 => Ok(BasicLength::SixtyFourth),
|
||||
32 => Ok(BasicLength::ThirtySecond),
|
||||
16 => Ok(BasicLength::Sixteenth),
|
||||
8 => Ok(BasicLength::Eighth),
|
||||
16 => Ok(BasicLength::Fourth),
|
||||
32 => Ok(BasicLength::Half),
|
||||
64 => Ok(BasicLength::Whole),
|
||||
4 => Ok(BasicLength::Fourth),
|
||||
2 => Ok(BasicLength::Half),
|
||||
1 => Ok(BasicLength::Whole),
|
||||
e => Err(format!("{} is not a num BasicLength can be constructed from", e))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
}
|
||||
|
@ -75,33 +89,33 @@ impl Add<BasicLength> for BasicLength {
|
|||
|
||||
fn add(self, rhs: BasicLength) -> Length {
|
||||
let f = |x| match x {
|
||||
BasicLength::Whole => 64,
|
||||
BasicLength::Half => 32,
|
||||
BasicLength::Fourth => 16,
|
||||
BasicLength::Eighth => 8,
|
||||
BasicLength::Sixteenth => 4,
|
||||
BasicLength::ThirtySecond => 2,
|
||||
BasicLength::SixtyFourth => 1,
|
||||
BasicLength::Whole => 128,
|
||||
BasicLength::Half => 64,
|
||||
BasicLength::Fourth => 32,
|
||||
BasicLength::Eighth => 16,
|
||||
BasicLength::Sixteenth => 8,
|
||||
BasicLength::ThirtySecond => 4,
|
||||
BasicLength::SixtyFourth => 2,
|
||||
};
|
||||
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 {
|
||||
let n1 : u16 = f(self);
|
||||
let n2 = f(rhs);
|
||||
let total = n1 + n2;
|
||||
|
||||
if total > 64 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_num(total - 64).unwrap()))
|
||||
if total > 128 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Whole), ModdedLength::Plain(BasicLength::from_128th(total - 128).unwrap()))
|
||||
} else if total > 32 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 32).unwrap()))
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 64).unwrap()))
|
||||
} else if total > 16 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 16).unwrap()))
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 32).unwrap()))
|
||||
} else if total > 8 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_num(total - 8).unwrap()))
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Eighth), ModdedLength::Plain(BasicLength::from_128th(total - 16).unwrap()))
|
||||
} else if total > 4 {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_num(total - 4).unwrap()))
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Fourth), ModdedLength::Plain(BasicLength::from_128th(total - 8).unwrap()))
|
||||
} else {
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_num(total - 2).unwrap()))
|
||||
Length::Tied(ModdedLength::Plain(BasicLength::Half), ModdedLength::Plain(BasicLength::from_128th(total - 4).unwrap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
224
src/midi/core.rs
224
src/midi/core.rs
|
@ -1,11 +1,12 @@
|
|||
extern crate derive_more;
|
||||
use std::cmp::Ordering;
|
||||
use std::cmp::Ordering::*;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::iter::Peekable;
|
||||
use std::iter::{Cycle, Take};
|
||||
use std::ops::{Add, Mul};
|
||||
use std::str::FromStr;
|
||||
use std::path::Iter;
|
||||
use std::str::FromStr;
|
||||
use std::time;
|
||||
|
||||
use midly::{
|
||||
|
@ -17,6 +18,8 @@ use crate::dsl::dsl::{
|
|||
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Groups, KnownLength, Length,
|
||||
ModdedLength, Note, Times,
|
||||
};
|
||||
use GroupOrNote::*;
|
||||
use Note::*;
|
||||
use crate::midi::time::TimeSignature;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -64,19 +67,21 @@ pub enum EventType {
|
|||
NoteOff(Part),
|
||||
}
|
||||
|
||||
use EventType::*;
|
||||
|
||||
impl Ord for EventType {
|
||||
fn cmp(&self, other: &EventType) -> Ordering {
|
||||
match (self, other) {
|
||||
(EventType::NoteOn(a), EventType::NoteOn(b)) => a.cmp(b),
|
||||
(EventType::NoteOn(a), EventType::NoteOff(b)) => match a.cmp(b) {
|
||||
Ordering::Equal => Ordering::Greater,
|
||||
ord => ord
|
||||
(NoteOn(a), NoteOn(b)) => a.cmp(b),
|
||||
(NoteOn(a), NoteOff(b)) => match a.cmp(b) {
|
||||
Equal => Greater,
|
||||
ord => ord,
|
||||
},
|
||||
(EventType::NoteOff(a), EventType::NoteOn(b)) => match a.cmp(b) {
|
||||
Ordering::Equal => Ordering::Less,
|
||||
ord => ord
|
||||
(NoteOff(a), NoteOn(b)) => match a.cmp(b) {
|
||||
Equal => Less,
|
||||
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,
|
||||
}
|
||||
|
||||
use Part::*;
|
||||
|
||||
impl Part {
|
||||
// https://computermusicresource.com/GM.Percussion.KeyMap.html
|
||||
fn to_midi_key(&self) -> u7 {
|
||||
match self {
|
||||
Part::KickDrum => u7::from(36),
|
||||
Part::SnareDrum => u7::from(38),
|
||||
Part::HiHat => u7::from(46),
|
||||
Part::CrashCymbal => u7::from(49),
|
||||
KickDrum => u7::from(36),
|
||||
SnareDrum => u7::from(38),
|
||||
HiHat => u7::from(46),
|
||||
CrashCymbal => u7::from(49),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,26 +117,32 @@ pub struct Event<T> {
|
|||
impl<T> PartialOrd for Event<T>
|
||||
where
|
||||
T: PartialOrd + Ord,
|
||||
Event<T>: Ord
|
||||
Event<T>: Ord,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
||||
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 {
|
||||
matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal))
|
||||
matches!(
|
||||
self.partial_cmp(other),
|
||||
Some(Less | Equal)
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
let first_on = Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum),
|
||||
event_type: NoteOn(KickDrum),
|
||||
};
|
||||
let first_off = Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum),
|
||||
event_type: NoteOff(KickDrum),
|
||||
};
|
||||
let second_on = Event {
|
||||
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_off.cmp(&second_on), Ordering::Less);
|
||||
assert_eq!(first_on.cmp(&first_off), Less);
|
||||
assert_eq!(first_off.cmp(&second_on), Less);
|
||||
|
||||
let mut vec1 = vec![second_on, first_off, first_on];
|
||||
let mut vec2 = vec1.clone();
|
||||
|
@ -234,11 +247,11 @@ fn test_arith_event_grids() {
|
|||
events: vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum),
|
||||
event_type: NoteOn(KickDrum),
|
||||
},
|
||||
Event {
|
||||
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),
|
||||
|
@ -247,11 +260,11 @@ fn test_arith_event_grids() {
|
|||
events: vec![
|
||||
Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOn(Part::HiHat),
|
||||
event_type: NoteOn(HiHat),
|
||||
},
|
||||
Event {
|
||||
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),
|
||||
|
@ -260,19 +273,19 @@ fn test_arith_event_grids() {
|
|||
events: vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum),
|
||||
event_type: NoteOn(KickDrum),
|
||||
},
|
||||
Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOn(Part::HiHat),
|
||||
event_type: NoteOn(HiHat),
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOff(Part::KickDrum),
|
||||
event_type: NoteOff(KickDrum),
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOff(Part::HiHat),
|
||||
event_type: NoteOff(HiHat),
|
||||
},
|
||||
],
|
||||
length: Tick(96),
|
||||
|
@ -286,11 +299,11 @@ fn test_add_event_grid() {
|
|||
let empty: EventGrid<Tick> = EventGrid::empty();
|
||||
let kick_on = Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum),
|
||||
event_type: NoteOn(KickDrum),
|
||||
};
|
||||
let kick_off = Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum),
|
||||
event_type: NoteOff(KickDrum),
|
||||
};
|
||||
let simple_grid = EventGrid {
|
||||
events: vec![kick_on, kick_off],
|
||||
|
@ -305,19 +318,19 @@ fn test_add_event_grid() {
|
|||
events: vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(72),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
}
|
||||
],
|
||||
length: Tick(96)
|
||||
|
@ -460,25 +473,25 @@ fn flatten_group(
|
|||
let mut grid = EventGrid::empty();
|
||||
notes.iter().for_each(|entry| {
|
||||
match entry {
|
||||
crate::dsl::dsl::GroupOrNote::SingleGroup(group) => {
|
||||
SingleGroup(group) => {
|
||||
let mut eg = flatten_group(&group, part, time);
|
||||
grid.events.append(&mut eg.events);
|
||||
grid.length = grid.length + eg.length;
|
||||
}
|
||||
crate::dsl::dsl::GroupOrNote::SingleNote(Note::Rest) => {
|
||||
SingleNote(Note::Rest) => {
|
||||
let rest_end = *time + note_length;
|
||||
*time = rest_end;
|
||||
grid.length = rest_end;
|
||||
}
|
||||
crate::dsl::dsl::GroupOrNote::SingleNote(Note::Hit) => {
|
||||
SingleNote(Note::Hit) => {
|
||||
let note_end = *time + note_length;
|
||||
let note_on = Event {
|
||||
tick: *time,
|
||||
event_type: EventType::NoteOn(part),
|
||||
event_type: NoteOn(part),
|
||||
};
|
||||
let note_off = Event {
|
||||
tick: note_end,
|
||||
event_type: EventType::NoteOff(part),
|
||||
event_type: NoteOff(part),
|
||||
};
|
||||
grid.events.push(note_on);
|
||||
grid.events.push(note_off);
|
||||
|
@ -496,26 +509,26 @@ fn test_flatten_group() {
|
|||
assert_eq!(
|
||||
flatten_group(
|
||||
&group_or_delimited_group("(2,8x--)").unwrap().1,
|
||||
Part::KickDrum,
|
||||
KickDrum,
|
||||
&mut Tick(0)
|
||||
),
|
||||
EventGrid {
|
||||
events: vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(72),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(96),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
}
|
||||
],
|
||||
length: Tick(144)
|
||||
|
@ -537,11 +550,11 @@ fn test_cycle_grid() {
|
|||
assert_eq!(cycle_grid(EventGrid::empty(), Times(2)), empty);
|
||||
let kick_on = Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum),
|
||||
event_type: NoteOn(KickDrum),
|
||||
};
|
||||
let kick_off = Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum),
|
||||
event_type: NoteOff(KickDrum),
|
||||
};
|
||||
let simple_grid = EventGrid {
|
||||
events: vec![kick_on, kick_off],
|
||||
|
@ -555,19 +568,19 @@ fn test_cycle_grid() {
|
|||
events: vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(24),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(72),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
}
|
||||
],
|
||||
length: Tick(96)
|
||||
|
@ -621,10 +634,10 @@ impl Iterator for EventIterator {
|
|||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let candidates: BTreeMap<Part, Event<Tick>> = [
|
||||
(Part::KickDrum, self.kick.peek()),
|
||||
(Part::SnareDrum, self.snare.peek()),
|
||||
(Part::HiHat, self.hihat.peek()),
|
||||
(Part::CrashCymbal, self.crash.peek()),
|
||||
(KickDrum, self.kick.peek()),
|
||||
(SnareDrum, self.snare.peek()),
|
||||
(HiHat, self.hihat.peek()),
|
||||
(CrashCymbal, self.crash.peek()),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(p, x)| match x {
|
||||
|
@ -633,17 +646,17 @@ impl Iterator for EventIterator {
|
|||
})
|
||||
.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 {
|
||||
Part::KickDrum => self.kick.next(),
|
||||
Part::SnareDrum => self.snare.next(),
|
||||
Part::HiHat => self.hihat.next(),
|
||||
Part::CrashCymbal => self.crash.next(),
|
||||
KickDrum => self.kick.next(),
|
||||
SnareDrum => self.snare.next(),
|
||||
HiHat => self.hihat.next(),
|
||||
CrashCymbal => self.crash.next(),
|
||||
};
|
||||
Some(*min_event)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,15 +665,15 @@ fn test_event_iterator_impl() {
|
|||
let empty = EventGrid::empty();
|
||||
let kick1 = flatten_group(
|
||||
&group_or_delimited_group("(4x-)").unwrap().1,
|
||||
Part::KickDrum,
|
||||
KickDrum,
|
||||
&mut Tick(0),
|
||||
);
|
||||
let snare1 = flatten_group(
|
||||
&group_or_delimited_group("4-x").unwrap().1,
|
||||
Part::SnareDrum,
|
||||
SnareDrum,
|
||||
&mut Tick(0),
|
||||
);
|
||||
|
||||
|
||||
assert_eq!(
|
||||
EventIterator::new(
|
||||
kick1.clone(),
|
||||
|
@ -674,19 +687,19 @@ fn test_event_iterator_impl() {
|
|||
vec![
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOff(Part::KickDrum)
|
||||
event_type: NoteOff(KickDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(48),
|
||||
event_type: EventType::NoteOn(Part::SnareDrum)
|
||||
event_type: NoteOn(SnareDrum)
|
||||
},
|
||||
Event {
|
||||
tick: Tick(96),
|
||||
event_type: EventType::NoteOff(Part::SnareDrum)
|
||||
event_type: NoteOff(SnareDrum)
|
||||
}
|
||||
]
|
||||
);
|
||||
|
@ -704,11 +717,11 @@ fn test_event_iterator_impl() {
|
|||
[
|
||||
Event {
|
||||
tick: Tick(0),
|
||||
event_type: EventType::NoteOn(Part::KickDrum)
|
||||
event_type: NoteOn(KickDrum)
|
||||
},
|
||||
Event {
|
||||
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
|
||||
.converges(groups.values())
|
||||
.unwrap_or(BAR_LIMIT.clone());
|
||||
println!("Converges over {} bars", converges_over_bars);
|
||||
let length_limit = converges_over_bars * time_signature.to_128th();
|
||||
|
||||
let (kick_grid, kick_repeats) = match groups.get(&Part::KickDrum) {
|
||||
println!("TimeSignature {:?} in 128th: {}", time_signature, time_signature.to_128th());
|
||||
println!("length limit in 128th notes: {}", length_limit);
|
||||
let (kick_grid, kick_repeats) = match groups.get(&KickDrum) {
|
||||
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 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,
|
||||
)
|
||||
}
|
||||
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) => {
|
||||
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 times = length_limit / length_128th;
|
||||
(
|
||||
flatten_groups(Part::SnareDrum, groups),
|
||||
flatten_groups(SnareDrum, groups),
|
||||
number_of_groups * times as usize,
|
||||
)
|
||||
}
|
||||
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) => {
|
||||
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 times = length_limit / length_128th;
|
||||
(
|
||||
flatten_groups(Part::HiHat, groups),
|
||||
flatten_groups(HiHat, groups),
|
||||
number_of_groups * times as usize,
|
||||
)
|
||||
}
|
||||
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) => {
|
||||
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 times = length_limit / length_128th;
|
||||
(
|
||||
flatten_groups(Part::CrashCymbal, groups),
|
||||
flatten_groups(CrashCymbal, groups),
|
||||
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.
|
||||
pub fn create_smf<'a>(groups: HashMap<Part, Groups>, time_signature: TimeSignature) -> Smf<'a> {
|
||||
let tracks = create_tracks(groups, time_signature); // FIXME
|
||||
|
@ -812,7 +855,8 @@ fn create_tracks<'a>(
|
|||
) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
||||
//FIXME: unhardcode 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.
|
||||
let time = match events.last() {
|
||||
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))});
|
||||
for event in event_grid.events {
|
||||
let midi_message = match event.event_type {
|
||||
EventType::NoteOn(part) => MidiMessage::NoteOn {
|
||||
NoteOn(part) => MidiMessage::NoteOn {
|
||||
key: part.to_midi_key(),
|
||||
vel: u7::from(120),
|
||||
},
|
||||
EventType::NoteOff(part) => MidiMessage::NoteOff {
|
||||
NoteOff(part) => MidiMessage::NoteOff {
|
||||
key: part.to_midi_key(),
|
||||
vel: u7::from(0),
|
||||
},
|
||||
|
@ -850,4 +894,4 @@ fn create_tracks<'a>(
|
|||
}
|
||||
|
||||
vec![drums]
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
extern crate derive_more;
|
||||
use crate::dsl::dsl::{BasicLength, Group, GroupOrNote, KnownLength, Note, Times, EIGHTH, FOURTH};
|
||||
use BasicLength::*;
|
||||
use Note::*;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use std;
|
||||
|
@ -18,7 +20,6 @@ impl TimeSignature {
|
|||
denominator,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
type Output = TimeSignature;
|
||||
fn mul(self, rhs: u8) -> TimeSignature {
|
||||
|
@ -77,13 +83,20 @@ fn test_cmp_time_signature() {
|
|||
|
||||
impl KnownLength for TimeSignature {
|
||||
fn to_128th(&self) -> u32 {
|
||||
println!("{}", self.denominator.to_128th());
|
||||
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 {
|
||||
pub fn converges<T: KnownLength, I: IntoIterator<Item = T>>(&self, multiple: I) -> Result<u32, String> {
|
||||
let bar_len = self.to_128th();
|
||||
println!("bar_len: {}", bar_len);
|
||||
let result = multiple
|
||||
.into_iter()
|
||||
.fold(bar_len, |acc, t| lowest_common_divisor(t.to_128th(), acc));
|
||||
|
|
Loading…
Reference in a new issue