diff --git a/.vscode/settings.json b/.vscode/settings.json index 3ddccaa..431f0a6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "./Cargo.toml", "./Cargo.toml", "./Cargo.toml", + "./Cargo.toml", "./Cargo.toml" ], "docwriter.style": "RustDoc" diff --git a/src/bin/main.rs b/src/bin/main.rs index 6602bd8..fbde342 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::process::exit; use poly::dsl::dsl; -use poly::midi; -use poly::midi::core::{Part, create_smf, TimeSignature}; +use poly::midi::core::{Part, create_smf}; +use poly::midi::time::TimeSignature; use clap::*; diff --git a/src/dsl/dsl.rs b/src/dsl/dsl.rs index 7027340..3d384d9 100644 --- a/src/dsl/dsl.rs +++ b/src/dsl/dsl.rs @@ -10,6 +10,12 @@ use nom::branch::alt; 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)] pub enum BasicLength { Whole, @@ -21,6 +27,20 @@ pub enum BasicLength { 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 { /// Unsafe method, so it should only be used from `add`. fn from_num(n: u16) -> Self { @@ -87,6 +107,18 @@ pub enum ModdedLength { 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)] pub enum Length { Simple(ModdedLength), @@ -94,21 +126,15 @@ pub enum Length { Triplet(ModdedLength) } -// impl Length { -// fn from_group(group: Group) -> Self { -// let mut numerator = 0; -// for x in group.notes { -// match x { -// crate::dsl::dsl::GroupOrNote::SingleGroup(g) => { -// todo!() -// }, -// crate::dsl::dsl::GroupOrNote::SingleNote(_) => { -// numerator = numerator + 1; -// }, -// } -// } -// } -// } +impl KnownLength for Length { + fn to_128th(&self) -> u32 { + match self { + Length::Simple(ml) => ml.to_128th(), + Length::Tied(ml1, ml2) => ml1.to_128th() + ml2.to_128th(), + Length::Triplet(ml) => ml.to_128th() * 2 / 3 + } + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Note { @@ -117,6 +143,7 @@ pub enum Note { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] pub struct Times(pub u16); #[derive(Debug, Clone, PartialEq, Eq)] @@ -132,6 +159,20 @@ pub struct Group { 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 { type Target = Vec; @@ -141,61 +182,61 @@ impl std::ops::Deref for Group { } #[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)] -static HALF : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half)); +pub static HALF : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Half)); #[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)] -static EIGHTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth)); +pub static EIGHTH : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::Eighth)); #[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)] -static THIRTY_SECOND : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond)); +pub static THIRTY_SECOND : &Length = &Length::Simple(ModdedLength::Plain(BasicLength::ThirtySecond)); #[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)] -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)] -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)] -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)] -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)] -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)] -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)] -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)] -static WHOLE_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Whole)); +pub static WHOLE_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Whole)); #[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)] -static FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Fourth)); +pub static FOURTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Fourth)); #[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)] -static SIXTEENTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth)); +pub static SIXTEENTH_TRIPLET : &Length = &Length::Triplet(ModdedLength::Plain(BasicLength::Sixteenth)); #[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)] -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)] -static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit); +pub static HIT : GroupOrNote = GroupOrNote::SingleNote(Note::Hit); #[allow(dead_code)] -static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest); +pub static REST : GroupOrNote = GroupOrNote::SingleNote(Note::Rest); #[allow(dead_code)] -static ONCE : &Times = &Times(1); +pub static ONCE : &Times = &Times(1); #[allow(dead_code)] -static TWICE: &Times = &Times(2); +pub static TWICE: &Times = &Times(2); #[allow(dead_code)] -static THRICE : &Times = &Times(3); +pub static THRICE : &Times = &Times(3); fn hit(input: &str) -> IResult<&str, Note> { diff --git a/src/midi/core.rs b/src/midi/core.rs index 0a65356..fdd7b3e 100644 --- a/src/midi/core.rs +++ b/src/midi/core.rs @@ -15,22 +15,10 @@ use crate::dsl::dsl::{ group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Length, ModdedLength, Note, Times, }; +use crate::midi::time::{TimeSignature}; // Typically used as number of ticks since the beginning of the track. -#[derive( - Debug, - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - derive_more::Add, - derive_more::Sub, - derive_more::Mul, - derive_more::Rem, - derive_more::Display, -)] +#[derive(Debug, Clone, Copy, PartialEq,Eq,PartialOrd,Ord,derive_more::Add, derive_more::Sub, derive_more::Mul, derive_more::Rem,derive_more::Display)] #[repr(transparent)] pub struct Tick(pub u128); @@ -46,12 +34,23 @@ fn test_add_tick() { #[repr(transparent)] pub struct Delta(pub u128); -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)] pub enum EventType { NoteOn(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 { fn is_note_on(&self) -> bool { 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 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, - ) -> 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)] pub enum Part { 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 { tick: T, event_type: EventType, } +impl Ord for Event +where + T: Ord +{ + fn cmp(&self, other: &Event) -> 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. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct EventGrid { events: Vec>, length: Tick, @@ -247,16 +134,7 @@ impl EventGrid { } } -// impl Iterator for EventGrid { -// type Item = Event; - -// fn next(&mut self) -> Option { -// let e = self.events.iter().next(); -// e.map(|x| *x ) -// } -// } - -impl + Clone + Ord> Add for EventGrid { +impl + Clone + Ord + std::fmt::Debug> Add for EventGrid { type Output = EventGrid; fn add(mut self, other: EventGrid) -> EventGrid { @@ -269,7 +147,9 @@ impl + Clone + Ord> Add for EventGrid { }) .collect(); 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 } @@ -395,7 +275,7 @@ impl EventGrid { } impl EventGrid { - /// Converts a sorted `EventGrid` + /// Converts a single-track(!!!!) sorted `EventGrid` fn to_delta(&self) -> EventGrid { let mut time = Tick(0); let mut delta_grid = EventGrid::new(); @@ -416,7 +296,7 @@ static TICKS_PER_QUARTER_NOTE: u16 = 48; impl BasicLength { /// `BasicLength` to MIDI Ticks - fn to_ticks(&self) -> Tick { + pub fn to_ticks(&self) -> Tick { match self { BasicLength::Whole => Tick((TICKS_PER_QUARTER_NOTE * 4) 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 { BasicLength::Whole => 1, 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) } @@ -695,6 +578,7 @@ impl Iterator for EventIterator { fn next(&mut self) -> Option { println!("============"); println!("self.time: {}", self.time); + println!("self.kick: {:?}", self.kick.peek()); let mut min_part = Part::KickDrum; let mut min_tick = self.limit; let mut min_event: Event = Event { @@ -716,19 +600,6 @@ impl Iterator for EventIterator { Some(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 { println!("e.tick = self.time"); min_part = p; @@ -748,6 +619,7 @@ impl Iterator for EventIterator { None => continue, } } + println!("<<< min_event: {:?}", min_event); let mut group_length: Tick; @@ -781,7 +653,7 @@ impl Iterator for EventIterator { "min_event.tick ({}) = self.time ({})", min_event.tick, self.time ); - Tick(self.time.0 + min_event.tick.0) + self.time + min_event.tick } else { println!( "min_event.tick ({}) <> self.time ({})", @@ -833,21 +705,56 @@ impl Iterator for EventIterator { #[test] fn test_event_iterator_impl() { let empty = EventGrid::new(); - let flat_kick = flatten_group( + let kick1 = flatten_group( &group_or_delimited_group("(4x-)").unwrap().1, Part::KickDrum, &mut Tick(0), ); - let snare = flatten_group( + let snare1 = flatten_group( &group_or_delimited_group("4-x").unwrap().1, Part::SnareDrum, &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!( EventIterator::new( - flat_kick.clone(), - snare.clone(), + kick2.clone(), + snare2.clone(), + empty.clone(), + empty.clone(), + Tick(96) + ) + .into_iter() + .map(|x| { x.0 }) + .collect::>>(), + 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(), Tick(96) @@ -877,7 +784,7 @@ fn test_event_iterator_impl() { assert_eq!( EventIterator::new( - flat_kick.clone(), + kick1.clone(), empty.clone(), empty.clone(), empty.clone(), @@ -899,7 +806,7 @@ fn test_event_iterator_impl() { ); assert_eq!( EventIterator::new( - flat_kick.clone(), + kick1.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. pub fn create_smf<'a>(groups: HashMap>, 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 // 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. @@ -984,11 +891,12 @@ fn create_tracks<'a>( panic!("Result has no midi notes") } }; - let event_grid = EventGrid { + let event_grid_tick = EventGrid { events, 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 midi_tempo = MidiTempo::from_tempo(Tempo(130)).0; // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) }); diff --git a/src/midi/mod.rs b/src/midi/mod.rs index 689cad3..cd13853 100644 --- a/src/midi/mod.rs +++ b/src/midi/mod.rs @@ -1 +1,2 @@ -pub mod core; \ No newline at end of file +pub mod core; +pub mod time; \ No newline at end of file diff --git a/src/midi/time.rs b/src/midi/time.rs new file mode 100644 index 0000000..4708d4a --- /dev/null +++ b/src/midi/time.rs @@ -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 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, + ) -> 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(&self, over: T) -> Result { + 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)) + ); +}