euphony_core/time/
time_context.rs

1use crate::time::{
2    beat::Beat, duration::Duration, measure::Measure, tempo::Tempo, time_signature::TimeSignature,
3};
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Ord, Hash)]
6pub struct TimeContext {
7    pub time_signature: TimeSignature,
8    pub tempo: Tempo,
9}
10
11impl TimeContext {
12    pub fn new<B: Into<Tempo>>(tempo: B) -> Self {
13        Self::default().with_tempo(tempo)
14    }
15
16    pub fn with_time_signature<V: Into<TimeSignature>>(self, time_signature: V) -> Self {
17        Self {
18            time_signature: time_signature.into(),
19            tempo: self.tempo,
20        }
21    }
22
23    pub fn with_tempo<B: Into<Tempo>>(self, tempo: B) -> Self {
24        Self {
25            time_signature: self.time_signature,
26            tempo: tempo.into(),
27        }
28    }
29}
30
31impl core::ops::Mul<Beat> for TimeContext {
32    type Output = Duration;
33
34    fn mul(self, beats: Beat) -> Self::Output {
35        let beat_count = beats / self.time_signature.beat();
36        self.tempo.as_beat_duration() * beat_count
37    }
38}
39
40impl core::ops::Mul<Measure> for TimeContext {
41    type Output = Duration;
42
43    fn mul(self, measures: Measure) -> Self::Output {
44        self.tempo.as_beat_duration() * measures.as_ratio()
45    }
46}
47
48#[test]
49fn mul_beat_test() {
50    assert_eq!(
51        TimeContext::new(120) * Beat(1, 4),
52        Duration::from_millis(500)
53    );
54    assert_eq!(
55        TimeContext::new(120) * Beat(1, 2),
56        Duration::from_millis(1000)
57    );
58    assert_eq!(
59        TimeContext::new(120).with_time_signature((2, 2)) * Beat(1, 2),
60        Duration::from_millis(500)
61    );
62
63    assert_eq!(
64        TimeContext::new(96) * Beat(1, 4),
65        Duration::from_millis(625)
66    );
67    assert!(
68        (TimeContext::new(95) * Beat(1, 4)) - Duration::from_millis(631) < Duration::from_millis(1)
69    );
70}