euphony_core/time/
time_signature.rs

1use crate::{
2    ratio::Ratio,
3    time::{beat::Beat, measure::Measure},
4};
5use core::convert::TryInto;
6
7#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
8pub struct TimeSignature(pub u64, pub u64);
9
10impl Default for TimeSignature {
11    fn default() -> Self {
12        Self(4, 4)
13    }
14}
15
16impl TimeSignature {
17    pub fn new<T: Into<Self>>(value: T) -> Self {
18        value.into()
19    }
20
21    pub fn beat(&self) -> Beat {
22        Beat(1, self.1)
23    }
24
25    pub fn count(&self) -> u64 {
26        self.0
27    }
28
29    pub fn total_beats(&self) -> Beat {
30        Beat(self.0, self.1)
31    }
32
33    fn as_ratio(self) -> Ratio<u64> {
34        Ratio(self.0, self.1)
35    }
36}
37
38impl core::ops::Mul<Measure> for TimeSignature {
39    type Output = Beat;
40
41    fn mul(self, measure: Measure) -> Self::Output {
42        let count = self.as_ratio() * measure.as_ratio();
43        (count / self.beat().as_ratio()).into()
44    }
45}
46
47#[test]
48fn mul_measure_test() {
49    assert_eq!(TimeSignature(4, 4) * Measure(1, 4), Beat(1, 1));
50    assert_eq!(TimeSignature(4, 4) * Measure(2, 4), Beat(2, 1));
51    assert_eq!(TimeSignature(7, 8) * Measure(2, 1), Beat(14, 1));
52    assert_eq!(TimeSignature(6, 8) * Measure(1, 3), Beat(2, 1));
53    assert_eq!(TimeSignature(6, 8) * Measure(2, 3), Beat(4, 1));
54}
55
56macro_rules! convert {
57    ($ty:ty) => {
58        impl From<($ty, $ty)> for TimeSignature {
59            fn from((n, d): ($ty, $ty)) -> Self {
60                Self(n.try_into().unwrap(), d.try_into().unwrap())
61            }
62        }
63    };
64}
65
66convert!(i8);
67convert!(u8);
68convert!(i16);
69convert!(u16);
70convert!(i32);
71convert!(u32);
72convert!(i64);
73convert!(u64);
74convert!(isize);
75convert!(usize);