euphony_core/time/
time_context.rs1use 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}