diff --git a/src/dsl/dsl.rs b/src/dsl/dsl.rs index b8b82cb..04e5bff 100644 --- a/src/dsl/dsl.rs +++ b/src/dsl/dsl.rs @@ -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 { + pub fn from_num(n: u16) -> Result { 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 { + 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 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())) } } } diff --git a/src/midi/core.rs b/src/midi/core.rs index 830be4e..8db3556 100644 --- a/src/midi/core.rs +++ b/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 { impl PartialOrd for Event where T: PartialOrd + Ord, - Event: Ord + Event: Ord, { fn partial_cmp(&self, other: &Self) -> Option { 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 = 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 { let candidates: BTreeMap> = [ - (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::>>(); + let flattened_snare = flatten_and_merge( + HashMap::from_iter([(SnareDrum, groups("8-x--x-").unwrap().1)]), + four_fourth + ).collect::>>(); + 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::>>(); + + 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, time_signature: TimeSignature) -> Smf<'a> { let tracks = create_tracks(groups, time_signature); // FIXME @@ -812,7 +855,8 @@ fn create_tracks<'a>( ) -> Vec>> { //FIXME: unhardcode time signature let events_iter = flatten_and_merge(parts_and_groups, time_signature); - let events : Vec> = events_iter.collect(); + let events: Vec> = 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] -} +} \ No newline at end of file diff --git a/src/midi/time.rs b/src/midi/time.rs index 12ee071..217c8b5 100644 --- a/src/midi/time.rs +++ b/src/midi/time.rs @@ -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 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>(&self, multiple: I) -> Result { 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));