rosu_map/section/timing_points/control_points/
timing.rs

1use std::{cmp::Ordering, num::NonZeroU32};
2
3#[derive(Clone, Debug, PartialEq)]
4/// The time signature at this control point.
5pub struct TimingPoint {
6    pub time: f64,
7    pub beat_len: f64,
8    pub omit_first_bar_line: bool,
9    pub time_signature: TimeSignature,
10}
11
12impl TimingPoint {
13    pub const DEFAULT_BEAT_LEN: f64 = 60_000.0 / 60.0;
14    pub const DEFAULT_OMIT_FIRST_BAR_LINE: bool = false;
15    pub const DEFAULT_TIME_SIGNATURE: TimeSignature = TimeSignature::new_simple_quadruple();
16
17    pub fn new(
18        time: f64,
19        beat_len: f64,
20        omit_first_bar_line: bool,
21        time_signature: TimeSignature,
22    ) -> Self {
23        Self {
24            time,
25            beat_len: beat_len.clamp(6.0, 60_000.0),
26            omit_first_bar_line,
27            time_signature,
28        }
29    }
30}
31
32impl Default for TimingPoint {
33    fn default() -> Self {
34        Self {
35            time: 0.0,
36            beat_len: Self::DEFAULT_BEAT_LEN,
37            omit_first_bar_line: Self::DEFAULT_OMIT_FIRST_BAR_LINE,
38            time_signature: Self::DEFAULT_TIME_SIGNATURE,
39        }
40    }
41}
42
43impl PartialOrd for TimingPoint {
44    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
45        self.time.partial_cmp(&other.time)
46    }
47}
48
49#[derive(Copy, Clone, Debug, PartialEq, Eq)]
50/// The time signature of a track.
51pub struct TimeSignature {
52    pub numerator: NonZeroU32,
53}
54
55impl TimeSignature {
56    /// Create a new [`TimeSignature`].
57    ///
58    /// # Errors
59    ///
60    /// Returns an error if `numerator` is non-positive.
61    pub fn new(numerator: i32) -> Result<Self, TimeSignatureError> {
62        u32::try_from(numerator)
63            .ok()
64            .and_then(NonZeroU32::new)
65            .map(|numerator| Self { numerator })
66            .ok_or(TimeSignatureError)
67    }
68
69    pub const fn new_simple_triple() -> Self {
70        Self {
71            // SAFETY: 3 != 0
72            numerator: unsafe { NonZeroU32::new_unchecked(3) },
73        }
74    }
75
76    pub const fn new_simple_quadruple() -> Self {
77        Self {
78            // SAFETY: 4 != 0
79            numerator: unsafe { NonZeroU32::new_unchecked(4) },
80        }
81    }
82}
83
84impl TryFrom<i32> for TimeSignature {
85    type Error = TimeSignatureError;
86
87    fn try_from(numerator: i32) -> Result<Self, Self::Error> {
88        Self::new(numerator)
89    }
90}
91
92thiserror! {
93    #[error("invalid time signature, must be positive integer")]
94    /// Error when failing to parse a [`TimeSignature`].
95    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
96    pub struct TimeSignatureError;
97}