Fix length measurements

This commit is contained in:
Denis Redozubov 2023-06-06 15:42:24 +04:00
parent a94a2d331a
commit 081188e80a
6 changed files with 415 additions and 237 deletions

View file

@ -9,6 +9,7 @@
"./Cargo.toml", "./Cargo.toml",
"./Cargo.toml", "./Cargo.toml",
"./Cargo.toml", "./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml" "./Cargo.toml"
], ],
"docwriter.style": "RustDoc" "docwriter.style": "RustDoc"

View file

@ -2,8 +2,8 @@ use std::collections::HashMap;
use std::process::exit; use std::process::exit;
use poly::dsl::dsl; use poly::dsl::dsl;
use poly::midi; use poly::midi::core::{Part, create_smf};
use poly::midi::core::{Part, create_smf, TimeSignature}; use poly::midi::time::TimeSignature;
use clap::*; use clap::*;

View file

@ -10,6 +10,12 @@ use nom::branch::alt;
use nom::combinator::{map, map_res}; use nom::combinator::{map, map_res};
/// Allows measurement in 128th notes.
pub trait KnownLength {
fn to_128th(&self) -> u32;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum BasicLength { pub enum BasicLength {
Whole, Whole,
@ -21,6 +27,20 @@ pub enum BasicLength {
SixtyFourth SixtyFourth
} }
impl KnownLength for BasicLength {
fn to_128th(&self) -> u32 {
match self {
BasicLength::Whole => 128,
BasicLength::Half => 64,
BasicLength::Fourth => 32,
BasicLength::Eighth => 16,
BasicLength::Sixteenth => 8,
BasicLength::ThirtySecond => 4,
BasicLength::SixtyFourth => 2,
}
}
}
impl BasicLength { impl BasicLength {
/// Unsafe method, so it should only be used from `add`. /// Unsafe method, so it should only be used from `add`.
fn from_num(n: u16) -> Self { fn from_num(n: u16) -> Self {
@ -87,6 +107,18 @@ pub enum ModdedLength {
Dotted(BasicLength) Dotted(BasicLength)
} }
impl KnownLength for ModdedLength {
fn to_128th(&self) -> u32 {
match self {
ModdedLength::Plain(bl) => bl.to_128th(),
ModdedLength::Dotted(bl) => {
let l = bl.to_128th();
l + l /2
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Length { pub enum Length {
Simple(ModdedLength), Simple(ModdedLength),
@ -94,21 +126,15 @@ pub enum Length {
Triplet(ModdedLength) Triplet(ModdedLength)
} }
// impl Length { impl KnownLength for Length {
// fn from_group(group: Group) -> Self { fn to_128th(&self) -> u32 {
// let mut numerator = 0; match self {
// for x in group.notes { Length::Simple(ml) => ml.to_128th(),
// match x { Length::Tied(ml1, ml2) => ml1.to_128th() + ml2.to_128th(),
// crate::dsl::dsl::GroupOrNote::SingleGroup(g) => { Length::Triplet(ml) => ml.to_128th() * 2 / 3
// todo!() }
// }, }
// crate::dsl::dsl::GroupOrNote::SingleNote(_) => { }
// numerator = numerator + 1;
// },
// }
// }
// }
// }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Note { pub enum Note {
@ -117,6 +143,7 @@ pub enum Note {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct Times(pub u16); pub struct Times(pub u16);
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -132,6 +159,20 @@ pub struct Group {
pub times: Times pub times: Times
} }
impl KnownLength for Group {
fn to_128th(&self) -> u32 {
let mut acc = 0;
let note_length = self.length.to_128th();
for group in self.notes.iter() {
match group {
GroupOrNote::SingleGroup(subgroup) => { acc += subgroup.to_128th(); },
GroupOrNote::SingleNote(_) => { acc += note_length; },
}
};
acc * self.times.0 as u32
}
}
impl std::ops::Deref for Group { impl std::ops::Deref for Group {
type Target = Vec<GroupOrNote>; type Target = Vec<GroupOrNote>;
@ -141,61 +182,61 @@ impl std::ops::Deref for Group {
} }
#[allow(dead_code)] #[allow(dead_code)]
static WHOLE : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Whole)); pub static WHOLE : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Whole));
#[allow(dead_code)] #[allow(dead_code)]
static HALF : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half)); pub static HALF : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half));
#[allow(dead_code)] #[allow(dead_code)]
static FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Fourth)); pub static FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Fourth));
#[allow(dead_code)] #[allow(dead_code)]
static EIGHTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth)); pub static EIGHTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTEENTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Sixteenth)); pub static SIXTEENTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Sixteenth));
#[allow(dead_code)] #[allow(dead_code)]
static THIRTY_SECOND : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond)); pub static THIRTY_SECOND : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTY_FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::SixtyFourth)); pub static SIXTY_FOURTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::SixtyFourth));
#[allow(dead_code)] #[allow(dead_code)]
static WHOLE_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Whole)); pub static WHOLE_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Whole));
#[allow(dead_code)] #[allow(dead_code)]
static HALF_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Half)); pub static HALF_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Half));
#[allow(dead_code)] #[allow(dead_code)]
static FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Fourth)); pub static FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Fourth));
#[allow(dead_code)] #[allow(dead_code)]
static EIGHTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Eighth)); pub static EIGHTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Eighth));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTEENTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Sixteenth)); pub static SIXTEENTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::Sixteenth));
#[allow(dead_code)] #[allow(dead_code)]
static THIRTY_SECOND_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::ThirtySecond)); pub static THIRTY_SECOND_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::ThirtySecond));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTY_FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::SixtyFourth)); pub static SIXTY_FOURTH_DOTTED_TRIPLET : &Length = &Length::Triplet(ModdedLength::Dotted(BasicLength::SixtyFourth));
#[allow(dead_code)] #[allow(dead_code)]
static WHOLE_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Whole)); pub static WHOLE_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Whole));
#[allow(dead_code)] #[allow(dead_code)]
static HALF_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Half)); pub static HALF_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Half));
#[allow(dead_code)] #[allow(dead_code)]
static FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Fourth)); pub static FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Fourth));
#[allow(dead_code)] #[allow(dead_code)]
static EIGHTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Eighth)); pub static EIGHTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Eighth));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTEENTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth)); pub static SIXTEENTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth));
#[allow(dead_code)] #[allow(dead_code)]
static THIRTY_SECOND_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::ThirtySecond)); pub static THIRTY_SECOND_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::ThirtySecond));
#[allow(dead_code)] #[allow(dead_code)]
static SIXTY_FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::SixtyFourth)); pub static SIXTY_FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::SixtyFourth));
#[allow(dead_code)] #[allow(dead_code)]
static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit); pub static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit);
#[allow(dead_code)] #[allow(dead_code)]
static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest); pub static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest);
#[allow(dead_code)] #[allow(dead_code)]
static ONCE : &Times = &Times(1); pub static ONCE : &Times = &Times(1);
#[allow(dead_code)] #[allow(dead_code)]
static TWICE: &Times = &Times(2); pub static TWICE: &Times = &Times(2);
#[allow(dead_code)] #[allow(dead_code)]
static THRICE : &Times = &Times(3); pub static THRICE : &Times = &Times(3);
fn hit(input: &str) -> IResult<&str, Note> { fn hit(input: &str) -> IResult<&str, Note> {

View file

@ -15,22 +15,10 @@ use crate::dsl::dsl::{
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Length, ModdedLength, Note, group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Length, ModdedLength, Note,
Times, Times,
}; };
use crate::midi::time::{TimeSignature};
// Typically used as number of ticks since the beginning of the track. // Typically used as number of ticks since the beginning of the track.
#[derive( #[derive(Debug, Clone, Copy, PartialEq,Eq,PartialOrd,Ord,derive_more::Add, derive_more::Sub, derive_more::Mul, derive_more::Rem,derive_more::Display)]
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
derive_more::Add,
derive_more::Sub,
derive_more::Mul,
derive_more::Rem,
derive_more::Display,
)]
#[repr(transparent)] #[repr(transparent)]
pub struct Tick(pub u128); pub struct Tick(pub u128);
@ -46,12 +34,23 @@ fn test_add_tick() {
#[repr(transparent)] #[repr(transparent)]
pub struct Delta(pub u128); pub struct Delta(pub u128);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub enum EventType { pub enum EventType {
NoteOn(Part), NoteOn(Part),
NoteOff(Part), NoteOff(Part),
} }
impl Ord for EventType {
fn cmp(&self, other: &EventType) -> Ordering {
match (self, other) {
(EventType::NoteOn(a), EventType::NoteOn(b)) => a.cmp(b),
(EventType::NoteOn(_), EventType::NoteOff(_)) => Ordering::Greater,
(EventType::NoteOff(_), EventType::NoteOn(_)) => Ordering::Less,
(EventType::NoteOff(a), EventType::NoteOff(b)) => a.cmp(b)
}
}
}
impl EventType { impl EventType {
fn is_note_on(&self) -> bool { fn is_note_on(&self) -> bool {
match self { match self {
@ -61,144 +60,6 @@ impl EventType {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeSignature {
pub numerator: u8,
pub denominator: BasicLength,
}
impl TimeSignature {
pub fn new(numerator: u8, denominator: BasicLength) -> Self {
Self {
numerator,
denominator,
}
}
}
impl std::ops::Mul<u8> for TimeSignature {
type Output = TimeSignature;
fn mul(self, rhs: u8) -> TimeSignature {
TimeSignature {
numerator: self.numerator * rhs as u8,
denominator: self.denominator,
}
}
}
#[test]
fn test_cmp_time_signature() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let two_secondth = TimeSignature {
numerator: 2,
denominator: BasicLength::Half,
};
assert_eq!(three_sixteenth.cmp(&four_fourth), Ordering::Less);
// weird, but not worth changing
// May implement a new type Ord if it needs to be Equal.
assert_eq!(four_fourth.cmp(&two_secondth), Ordering::Greater);
}
impl TimeSignature {
/// Checks if these two signatures converges for the next 200 bars.
fn converges_with(&self, other: TimeSignature) -> Result<(u32, TimeSignature), String> {
let d: u32 = std::cmp::max(self.denominator, other.denominator)
.to_u8()
.into();
let d1: u32 = self.denominator.to_u8().into();
let d2: u32 = other.denominator.to_u8().into();
let coef1 = d / d1;
let coef2 = d / d2;
let num1: u32 = coef1 * (self.numerator as u32);
let num2: u32 = coef2 * (other.numerator as u32);
let greater_time_signature = self.max(&other);
let f = |max, min| {
let mut res = Err(format!("Not converges over 1000 bars of {:?}", other));
for i in 1..1000 {
if (max * i) % min == 0 {
res = Ok((i, *greater_time_signature));
break;
}
}
res
};
match num1.cmp(&num2) {
std::cmp::Ordering::Less => f(num2, num1),
std::cmp::Ordering::Equal => Ok((1, *greater_time_signature)),
std::cmp::Ordering::Greater => f(num1, num2),
}
}
fn converges(
&self,
time_signatures: Vec<TimeSignature>,
) -> Result<(u32, TimeSignature), String> {
time_signatures
.iter()
.try_fold((1, *self), |(bars, ts), x| match ts.converges_with(*x) {
Ok((new_bars, greater_signature)) => {
if new_bars > bars {
if new_bars % bars == 0 {
Ok((new_bars, greater_signature))
} else {
Err(format!("{:?} don't converge with {:?}", self, x))
}
} else {
if bars % new_bars == 0 {
Ok((bars, greater_signature))
} else {
Err(format!("{:?} don't converge with {:?}", self, x))
}
}
}
Err(e) => Err(e),
})
}
}
#[test]
fn test_converges_with() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
assert_eq!(
three_sixteenth.converges_with(four_fourth),
Ok((3, four_fourth))
);
}
#[test]
fn test_converges() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let three_fourth = TimeSignature {
numerator: 3,
denominator: BasicLength::Fourth,
};
assert_eq!(
three_sixteenth.converges(vec![four_fourth, three_fourth, four_fourth]),
Ok((3, four_fourth))
);
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum Part { pub enum Part {
KickDrum, KickDrum,
@ -219,14 +80,40 @@ impl Part {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub struct Event<T> { pub struct Event<T> {
tick: T, tick: T,
event_type: EventType, event_type: EventType,
} }
impl <T> Ord for Event<T>
where
T: Ord
{
fn cmp(&self, other: &Event<T>) -> Ordering {
if self.tick == other.tick {
self.event_type.cmp(&other.event_type)
} else {
self.tick.cmp(&other.tick)
}
}
}
#[test]
fn test_ord_event_t() {
let first_on = Event{ tick: Tick(0), event_type: EventType::NoteOn(Part::KickDrum)};
let first_off = Event{ tick: Tick(24), event_type: EventType::NoteOff(Part::KickDrum)};
let second_on = Event{ tick: Tick(24), event_type: EventType::NoteOn(Part::KickDrum)};
assert_eq!(first_on.cmp(&first_off), Ordering::Less);
assert_eq!(first_off.cmp(&second_on), Ordering::Less);
let mut vec1 = vec![second_on, first_off, first_on];
vec1.sort_by(|x,y| {x.cmp(y)});
assert_eq!(vec1, vec![first_on, first_off, second_on]);
}
// Events are supposed to be sorted by T at all times. // Events are supposed to be sorted by T at all times.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct EventGrid<T> { pub struct EventGrid<T> {
events: Vec<Event<T>>, events: Vec<Event<T>>,
length: Tick, length: Tick,
@ -247,16 +134,7 @@ impl<T> EventGrid<T> {
} }
} }
// impl <T> Iterator for EventGrid<T> { impl<T: Add<Tick, Output = T> + Clone + Ord + std::fmt::Debug> Add for EventGrid<T> {
// type Item = Event<T>;
// fn next(&mut self) -> Option<Self::Item> {
// let e = self.events.iter().next();
// e.map(|x| *x )
// }
// }
impl<T: Add<Tick, Output = T> + Clone + Ord> Add for EventGrid<T> {
type Output = EventGrid<T>; type Output = EventGrid<T>;
fn add(mut self, other: EventGrid<T>) -> EventGrid<T> { fn add(mut self, other: EventGrid<T>) -> EventGrid<T> {
@ -269,7 +147,9 @@ impl<T: Add<Tick, Output = T> + Clone + Ord> Add for EventGrid<T> {
}) })
.collect(); .collect();
self.events.extend(other_events); self.events.extend(other_events);
self.events.sort(); // I don't know why sort() doesn't work in the same way.
self.events.sort_by(|x,y| { x.cmp(y) });
println!("self.events: {:?}", self.events);
self.length = self.length + other.length; self.length = self.length + other.length;
self self
} }
@ -395,7 +275,7 @@ impl<T> EventGrid<T> {
} }
impl EventGrid<Tick> { impl EventGrid<Tick> {
/// Converts a sorted `EventGrid<Tick>` /// Converts a single-track(!!!!) sorted `EventGrid<Tick>`
fn to_delta(&self) -> EventGrid<Delta> { fn to_delta(&self) -> EventGrid<Delta> {
let mut time = Tick(0); let mut time = Tick(0);
let mut delta_grid = EventGrid::new(); let mut delta_grid = EventGrid::new();
@ -416,7 +296,7 @@ static TICKS_PER_QUARTER_NOTE: u16 = 48;
impl BasicLength { impl BasicLength {
/// `BasicLength` to MIDI Ticks /// `BasicLength` to MIDI Ticks
fn to_ticks(&self) -> Tick { pub fn to_ticks(&self) -> Tick {
match self { match self {
BasicLength::Whole => Tick((TICKS_PER_QUARTER_NOTE * 4) as u128), BasicLength::Whole => Tick((TICKS_PER_QUARTER_NOTE * 4) as u128),
BasicLength::Half => Tick((TICKS_PER_QUARTER_NOTE * 2) as u128), BasicLength::Half => Tick((TICKS_PER_QUARTER_NOTE * 2) as u128),
@ -428,7 +308,8 @@ impl BasicLength {
} }
} }
fn to_u8(&self) -> u8 {
pub fn to_note_length(&self) -> u8 {
match self { match self {
BasicLength::Whole => 1, BasicLength::Whole => 1,
BasicLength::Half => 2, BasicLength::Half => 2,
@ -556,6 +437,8 @@ fn flatten_group(
} }
}; };
}); });
// grid.events.sort() is not the same for some reason
grid.events.sort_by(|x,y| { x.cmp(y) });
cycle_grid(grid, *times) cycle_grid(grid, *times)
} }
@ -695,6 +578,7 @@ impl Iterator for EventIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
println!("============"); println!("============");
println!("self.time: {}", self.time); println!("self.time: {}", self.time);
println!("self.kick: {:?}", self.kick.peek());
let mut min_part = Part::KickDrum; let mut min_part = Part::KickDrum;
let mut min_tick = self.limit; let mut min_tick = self.limit;
let mut min_event: Event<Tick> = Event { let mut min_event: Event<Tick> = Event {
@ -716,19 +600,6 @@ impl Iterator for EventIterator {
Some(e) => { Some(e) => {
println!("{:?}", e); println!("{:?}", e);
// FIXME
// fails with:
//
// self.time: 96
// Event { tick: Tick(0), event_type: NoteOn(KickDrum) }
// e.tick <= min_tick
// Event { tick: Tick(96), event_type: NoteOff(SnareDrum) }
// continue
// Kick
// group_length: 96
// self.time = group_length
// updated self.time: 96
// self.time = self.limit
if e.tick == self.time { if e.tick == self.time {
println!("e.tick = self.time"); println!("e.tick = self.time");
min_part = p; min_part = p;
@ -748,6 +619,7 @@ impl Iterator for EventIterator {
None => continue, None => continue,
} }
} }
println!("<<< min_event: {:?}", min_event);
let mut group_length: Tick; let mut group_length: Tick;
@ -781,7 +653,7 @@ impl Iterator for EventIterator {
"min_event.tick ({}) = self.time ({})", "min_event.tick ({}) = self.time ({})",
min_event.tick, self.time min_event.tick, self.time
); );
Tick(self.time.0 + min_event.tick.0) self.time + min_event.tick
} else { } else {
println!( println!(
"min_event.tick ({}) <> self.time ({})", "min_event.tick ({}) <> self.time ({})",
@ -833,21 +705,56 @@ impl Iterator for EventIterator {
#[test] #[test]
fn test_event_iterator_impl() { fn test_event_iterator_impl() {
let empty = EventGrid::new(); let empty = EventGrid::new();
let flat_kick = flatten_group( let kick1 = flatten_group(
&group_or_delimited_group("(4x-)").unwrap().1, &group_or_delimited_group("(4x-)").unwrap().1,
Part::KickDrum, Part::KickDrum,
&mut Tick(0), &mut Tick(0),
); );
let snare = flatten_group( let snare1 = flatten_group(
&group_or_delimited_group("4-x").unwrap().1, &group_or_delimited_group("4-x").unwrap().1,
Part::SnareDrum, Part::SnareDrum,
&mut Tick(0), &mut Tick(0),
); );
let kick2 = flatten_group(
&group_or_delimited_group("8xxxxxxxx").unwrap().1,
Part::KickDrum,
&mut Tick(0),
);
let snare2 = flatten_group(
&group_or_delimited_group("4-x-x").unwrap().1,
Part::SnareDrum,
&mut Tick(0),
);
assert_eq!( assert_eq!(
EventIterator::new( EventIterator::new(
flat_kick.clone(), kick2.clone(),
snare.clone(), snare2.clone(),
empty.clone(),
empty.clone(),
Tick(96)
)
.into_iter()
.map(|x| { x.0 })
.collect::<Vec<Event<Tick>>>(),
vec![
Event { event_type: EventType::NoteOn(Part::KickDrum), tick: Tick(0) },
Event { event_type: EventType::NoteOff(Part::KickDrum), tick: Tick(24) },
Event { event_type: EventType::NoteOn(Part::KickDrum), tick: Tick(24) },
Event { event_type: EventType::NoteOff(Part::KickDrum), tick: Tick(48) },
Event { event_type: EventType::NoteOn(Part::SnareDrum), tick: Tick(48) },
Event { event_type: EventType::NoteOn(Part::KickDrum), tick: Tick(48) },
Event { event_type: EventType::NoteOff(Part::KickDrum), tick: Tick(72) },
Event { event_type: EventType::NoteOn(Part::KickDrum), tick: Tick(72) },
Event { event_type: EventType::NoteOff(Part::KickDrum), tick: Tick(96) },
Event { event_type: EventType::NoteOn(Part::SnareDrum), tick: Tick(96) }
]
);
assert_eq!(
EventIterator::new(
kick1.clone(),
snare1.clone(),
empty.clone(), empty.clone(),
empty.clone(), empty.clone(),
Tick(96) Tick(96)
@ -877,7 +784,7 @@ fn test_event_iterator_impl() {
assert_eq!( assert_eq!(
EventIterator::new( EventIterator::new(
flat_kick.clone(), kick1.clone(),
empty.clone(), empty.clone(),
empty.clone(), empty.clone(),
empty.clone(), empty.clone(),
@ -899,7 +806,7 @@ fn test_event_iterator_impl() {
); );
assert_eq!( assert_eq!(
EventIterator::new( EventIterator::new(
flat_kick.clone(), kick1.clone(),
empty.clone(), empty.clone(),
empty.clone(), empty.clone(),
empty.clone(), empty.clone(),
@ -949,7 +856,7 @@ fn flatten_and_merge(
// 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, Vec<Group>>, time_signature: TimeSignature) -> Smf<'a> { pub fn create_smf<'a>(groups: HashMap<Part, Vec<Group>>, time_signature: TimeSignature) -> Smf<'a> {
let tracks = vec![]; // create_tracks(groups, time_signature); // FIXME let tracks = create_tracks(groups, time_signature); // FIXME
// 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.
@ -984,11 +891,12 @@ fn create_tracks<'a>(
panic!("Result has no midi notes") panic!("Result has no midi notes")
} }
}; };
let event_grid = EventGrid { let event_grid_tick = EventGrid {
events, events,
length: *time, length: *time,
} };
.to_delta(); println!("event grid in ticks: {:?}", event_grid_tick);
let event_grid = event_grid_tick.to_delta();
let mut drums = Vec::new(); let mut drums = Vec::new();
// let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0; // let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0;
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) }); // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) });

View file

@ -1 +1,2 @@
pub mod core; pub mod core;
pub mod time;

227
src/midi/time.rs Normal file
View file

@ -0,0 +1,227 @@
extern crate derive_more;
use crate::dsl::dsl::{BasicLength, KnownLength, Group, GroupOrNote, Note, FOURTH, Times, EIGHTH};
use std::cmp::Ordering;
use std;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeSignature {
pub numerator: u8,
pub denominator: BasicLength,
}
impl TimeSignature {
pub fn new(numerator: u8, denominator: BasicLength) -> Self {
Self {
numerator,
denominator,
}
}
}
impl std::ops::Mul<u8> for TimeSignature {
type Output = TimeSignature;
fn mul(self, rhs: u8) -> TimeSignature {
TimeSignature {
numerator: self.numerator * rhs as u8,
denominator: self.denominator,
}
}
}
#[test]
fn test_cmp_time_signature() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let two_secondth = TimeSignature {
numerator: 2,
denominator: BasicLength::Half,
};
assert_eq!(three_sixteenth.cmp(&four_fourth), Ordering::Less);
// weird, but not worth changing
// May implement a new type Ord if it needs to be Equal.
assert_eq!(four_fourth.cmp(&two_secondth), Ordering::Greater);
}
impl KnownLength for TimeSignature {
fn to_128th(&self) -> u32 {
self.denominator.to_128th() * self.numerator as u32
}
}
impl TimeSignature {
fn converges_with(&self, other: TimeSignature) -> Result<(u32, TimeSignature), String> {
let d: u32 = std::cmp::max(self.denominator, other.denominator)
.to_note_length()
.into();
let d1: u32 = self.denominator.to_note_length().into();
let d2: u32 = other.denominator.to_note_length().into();
let coef1 = d / d1;
let coef2 = d / d2;
let num1: u32 = coef1 * (self.numerator as u32);
let num2: u32 = coef2 * (other.numerator as u32);
let greater_time_signature = self.max(&other);
let f = |max, min| {
let mut res = Err(format!("Not converges over 1000 bars of {:?}", other));
for i in 1..1000 {
if (max * i) % min == 0 {
res = Ok((i, *greater_time_signature));
break;
}
}
res
};
match num1.cmp(&num2) {
std::cmp::Ordering::Less => f(num2, num1),
std::cmp::Ordering::Equal => Ok((1, *greater_time_signature)),
std::cmp::Ordering::Greater => f(num1, num2),
}
}
/// The function takes a vector of time signatures and tries to find out if they all converge over a finite number of bars.
///
/// Arguments:
///
/// * `time_signatures`: `time_signatures` is a vector of `TimeSignature` structs. The function
/// `converges` takes this vector as input and iterates over it using the `iter()` method. It then
/// uses the `try_fold()` method to fold over the vector and accumulate a result.
///
/// Returns:
///
/// Returns the number of bars to converge + suggested time signature.
/// Returns Err if signatures won't converge.
fn converges(
&self,
time_signatures: Vec<TimeSignature>,
) -> Result<(u32, TimeSignature), String> {
time_signatures
.iter()
.try_fold((1, *self), |(bars, ts), x| match ts.converges_with(*x) {
Ok((new_bars, greater_signature)) => {
if new_bars > bars {
if new_bars % bars == 0 {
Ok((new_bars, greater_signature))
} else {
Err(format!("{:?} don't converge with {:?}", self, x))
}
} else {
if bars % new_bars == 0 {
Ok((bars, greater_signature))
} else {
Err(format!("{:?} don't converge with {:?}", self, x))
}
}
}
Err(e) => Err(e),
})
}
/// Returns number of bars in the specified time signature that it takes to converge with the group.
/// Otherwise returns Err.
fn converges_over<T: KnownLength>(&self, over: T) -> Result<u32, String> {
let bar_len = self.to_128th();
let mut bars = 1;
let group_len = over.to_128th();
let mut out = Err("Do not converge".to_string());
let limit = 1000;
while bars <= limit {
let bars_len = bar_len * bars;
if bars_len % group_len == 0 {
// return
out = Ok(bars);
break
}
if bars == limit {
break;
} else {
bars += 1
}
}
out
}
}
#[test]
fn test_converges_over() {
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let three_fourth_group = Group {
notes: vec![GroupOrNote::SingleNote(Note::Hit)],
length: FOURTH.clone(),
times: Times(3)
};
let thirteen_eights = Group {
notes: vec![GroupOrNote::SingleNote(Note::Hit)],
length: FOURTH.clone(),
times: Times(12)
};
let in_shards_poly = Group {
notes: vec![GroupOrNote::SingleNote(Note::Hit), GroupOrNote::SingleNote(Note::Rest), GroupOrNote::SingleGroup(thirteen_eights)],
length: EIGHTH.clone(),
times: Times(1)
};
assert_eq!(four_fourth.converges_over(three_fourth_group), Ok(3));
assert_eq!(four_fourth.converges_over(in_shards_poly), Ok(13));
}
#[test]
fn test_converges_with() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let thirteen_eights = TimeSignature {
numerator: 13,
denominator: BasicLength::Eighth,
};
assert_eq!(
three_sixteenth.converges_with(four_fourth),
Ok((3, four_fourth))
);
assert_eq!(
thirteen_eights.converges_with(four_fourth),
Ok((15, four_fourth))
)
}
#[test]
fn test_converges() {
let three_sixteenth = TimeSignature {
numerator: 3,
denominator: BasicLength::Sixteenth,
};
let four_fourth = TimeSignature {
numerator: 4,
denominator: BasicLength::Fourth,
};
let three_fourth = TimeSignature {
numerator: 3,
denominator: BasicLength::Fourth,
};
let thirteen_eights = TimeSignature {
numerator: 13,
denominator: BasicLength::Eighth,
};
assert_eq!(
three_sixteenth.converges(vec![four_fourth, three_fourth, four_fourth]),
Ok((3, four_fourth))
);
assert_eq!(
four_fourth.converges(vec![thirteen_eights]),
Ok((15, four_fourth))
);
}