music_timer/
music_time.rs

1#![allow(dead_code)]
2
3//!
4//! Data structure that holds music time and logic when advancing beats and beat intervals.
5//!
6
7use super::time_signature::TimeSignature;
8use std::cmp::Ordering;
9
10#[derive(Clone, Copy, Debug, Eq, Ord)]
11/// Data structure that holds music time and logic when advancing beats and beat intervals.
12pub struct MusicTime {
13    bar: u16,
14    beat: u8,
15    beat_interval: u8,
16}
17
18impl MusicTime {
19    /// Create a new `MusicTime`.
20    ///
21    /// # Arguments
22    /// * `bar` - The musical bar.
23    /// * `beat` - The musical beat.
24    /// * `beat` - The musical beat interval, the subdivisions of a beat.
25    ///
26    /// # Example
27    /// ```
28    /// let time = music_timer::music_time::MusicTime::new(1, 1, 1);
29    /// ```
30    pub fn new(bar: u16, beat: u8, beat_interval: u8) -> MusicTime {
31        MusicTime {
32            bar,
33            beat,
34            beat_interval,
35        }
36    }
37
38    /// Get the bar number.
39    pub fn get_bar(&self) -> u16 {
40        self.bar
41    }
42
43    /// Get the beat number.
44    pub fn get_beat(&self) -> u8 {
45        self.beat
46    }
47
48    /// Get the interval between the beat.
49    pub fn get_beat_interval(&self) -> u8 {
50        self.beat_interval
51    }
52
53    /// Advance the beat by 1. The bar number will increase if the beat
54    /// exceeds the `TimeSignature` numerator.
55    ///
56    /// # Arguments
57    /// * `time_signature` - The time signature to constrain the music time by.
58    ///
59    /// # Example
60    /// ```
61    /// use music_timer::{time_signature::TimeSignature, music_time::MusicTime};
62    /// let time_signature = TimeSignature::new(4, 4);
63    /// let mut a = MusicTime::default();
64    /// assert_eq!(a.get_bar() == 1 && a.get_beat() == 1, true);
65    /// a.advance_beat(&time_signature);
66    /// assert_eq!(a.get_bar() == 1 && a.get_beat() == 2, true);
67    /// a.advance_beat(&time_signature);
68    /// assert_eq!(a.get_bar() == 1 && a.get_beat() == 3, true);
69    /// a.advance_beat(&time_signature);
70    /// assert_eq!(a.get_bar() == 1 && a.get_beat() == 4, true);
71    /// a.advance_beat(&time_signature);
72    /// assert_eq!(a.get_bar() == 2 && a.get_beat() == 1, true);
73    /// ```
74    pub fn advance_beat(&mut self, time_signature: &TimeSignature) {
75        if self.beat >= time_signature.get_numerator() {
76            self.beat = 1;
77            self.bar += 1;
78        } else {
79            self.beat += 1;
80        }
81    }
82
83    /// Advance the beat interval by 1. The beat number will increase if the beat interval
84    /// exceeds the the interval resolution of `8`. Then The bar number will increase if the beat
85    /// exceeds the `TimeSignature` numerator.
86    ///
87    /// # Arguments
88    /// * `time_signature` - The time signature to constrain the music time by.
89    ///
90    /// # Example
91    /// ```
92    /// use music_timer::{time_signature::TimeSignature, music_time::MusicTime};
93    /// let time_signature = TimeSignature::new(4, 4);
94    /// let mut a = MusicTime::default();
95    /// assert_eq!(a, MusicTime::new(1, 1, 1));
96    /// a.advance_beat_interval(&time_signature);
97    /// assert_eq!(a, MusicTime::new(1, 1, 2));
98    /// a.advance_beat_interval(&time_signature);
99    /// a.advance_beat_interval(&time_signature);
100    /// a.advance_beat_interval(&time_signature);
101    /// a.advance_beat_interval(&time_signature);
102    /// a.advance_beat_interval(&time_signature);
103    /// a.advance_beat_interval(&time_signature);
104    /// assert_eq!(a, MusicTime::new(1, 1, 8));
105    /// a.advance_beat_interval(&time_signature);
106    /// assert_eq!(a, MusicTime::new(1, 2, 1));
107    /// ```
108    pub fn advance_beat_interval(&mut self, time_signature: &TimeSignature) {
109        const INTERVAL_RESOLUTION: u8 = 16;
110        if self.beat_interval >= INTERVAL_RESOLUTION / 2 {
111            self.beat_interval = 1;
112            self.advance_beat(time_signature);
113        } else {
114            self.beat_interval += 1;
115        }
116    }
117}
118
119impl PartialEq for MusicTime {
120    fn eq(&self, other: &Self) -> bool {
121        self.bar == other.bar
122            && self.beat == other.beat
123            && self.beat_interval == other.beat_interval
124    }
125}
126
127impl PartialOrd for MusicTime {
128    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
129        let other_time_sum = other.bar * 100 + other.beat as u16 * 10 + other.beat_interval as u16;
130        let self_time_sum = self.bar * 100 + self.beat as u16 * 10 + self.beat_interval as u16;
131        self_time_sum.partial_cmp(&other_time_sum)
132    }
133}
134
135impl Default for MusicTime {
136    /// Default is `MusicTime::new(1,1,1)`
137    fn default() -> MusicTime {
138        MusicTime {
139            bar: 1,
140            beat: 1,
141            beat_interval: 1,
142        }
143    }
144}
145
146mod tests {
147    #[test]
148    fn test_order() {
149        use crate::music_time::MusicTime;
150
151        assert_eq!(MusicTime::new(1, 1, 1) < MusicTime::new(2, 1, 1), true);
152        assert_eq!(MusicTime::new(2, 1, 1) > MusicTime::new(1, 1, 1), true);
153        assert_eq!(MusicTime::new(1, 1, 1) <= MusicTime::new(1, 1, 1), true);
154        assert_eq!(MusicTime::new(1, 1, 1) >= MusicTime::new(1, 1, 1), true);
155
156        assert_eq!(MusicTime::new(1, 1, 1) < MusicTime::new(1, 2, 1), true);
157        assert_eq!(MusicTime::new(1, 2, 1) > MusicTime::new(1, 1, 1), true);
158        assert_eq!(MusicTime::new(1, 1, 1) < MusicTime::new(1, 2, 1), true);
159        assert_eq!(MusicTime::new(1, 2, 1) > MusicTime::new(1, 1, 1), true);
160
161        assert_eq!(MusicTime::new(1, 1, 1) < MusicTime::new(1, 1, 2), true);
162        assert_eq!(MusicTime::new(1, 1, 2) > MusicTime::new(1, 1, 1), true);
163        assert_eq!(MusicTime::new(1, 1, 1) < MusicTime::new(1, 1, 2), true);
164        assert_eq!(MusicTime::new(1, 1, 2) > MusicTime::new(1, 1, 1), true);
165    }
166
167    #[test]
168    fn test_equality() {
169        use crate::music_time::MusicTime;
170
171        let a = MusicTime::new(1, 2, 3);
172        let b = MusicTime::new(1, 2, 3);
173        assert_eq!(a == b, true);
174
175        let a = MusicTime::default();
176        let b: MusicTime = Default::default();
177        assert_eq!(a == b, true);
178        assert_eq!(a.get_bar() == 1 && b.get_bar() == 1, true);
179
180        let a = MusicTime::new(2, 1, 1);
181        let b = MusicTime::new(2, 3, 2);
182        assert_eq!(a == b, false);
183    }
184
185    #[test]
186    fn test_advance() {
187        use crate::{music_time::MusicTime, time_signature::TimeSignature};
188
189        let time_signature = TimeSignature::new(4, 4);
190        let mut a = MusicTime::default();
191        assert_eq!(a.get_bar() == 1 && a.get_beat() == 1, true);
192        a.advance_beat(&time_signature);
193        assert_eq!(a.get_bar() == 1 && a.get_beat() == 2, true);
194        a.advance_beat(&time_signature);
195        assert_eq!(a.get_bar() == 1 && a.get_beat() == 3, true);
196        a.advance_beat(&time_signature);
197        assert_eq!(a.get_bar() == 1 && a.get_beat() == 4, true);
198        a.advance_beat(&time_signature);
199        assert_eq!(a.get_bar() == 2 && a.get_beat() == 1, true);
200
201        let time_signature = TimeSignature::new(3, 4);
202        let mut a = MusicTime::default();
203        assert_eq!(a.get_bar() == 1 && a.get_beat() == 1, true);
204        a.advance_beat(&time_signature);
205        assert_eq!(a.get_bar() == 1 && a.get_beat() == 2, true);
206        a.advance_beat(&time_signature);
207        assert_eq!(a.get_bar() == 1 && a.get_beat() == 3, true);
208        a.advance_beat(&time_signature);
209        assert_eq!(a.get_bar() == 2 && a.get_beat() == 1, true);
210        a.advance_beat(&time_signature);
211        assert_eq!(a.get_bar() == 2 && a.get_beat() == 2, true);
212
213        let time_signature = TimeSignature::new(1, 4);
214        let mut a = MusicTime::default();
215        assert_eq!(a.get_bar() == 1 && a.get_beat() == 1, true);
216        a.advance_beat(&time_signature);
217        assert_eq!(a.get_bar() == 2 && a.get_beat() == 1, true);
218        a.advance_beat(&time_signature);
219        assert_eq!(a.get_bar() == 3 && a.get_beat() == 1, true);
220        a.advance_beat(&time_signature);
221        assert_eq!(a.get_bar() == 4 && a.get_beat() == 1, true);
222        a.advance_beat(&time_signature);
223        assert_eq!(a.get_bar() == 5 && a.get_beat() == 1, true);
224    }
225
226    #[test]
227    fn test_advance_beat_interval() {
228        use crate::{music_time::MusicTime, time_signature::TimeSignature};
229        let time_signature = TimeSignature::new(4, 4);
230        let mut a = MusicTime::default();
231        assert_eq!(a, MusicTime::new(1, 1, 1));
232        a.advance_beat_interval(&time_signature);
233        assert_eq!(a, MusicTime::new(1, 1, 2));
234        a.advance_beat_interval(&time_signature);
235        a.advance_beat_interval(&time_signature);
236        a.advance_beat_interval(&time_signature);
237        a.advance_beat_interval(&time_signature);
238        a.advance_beat_interval(&time_signature);
239        a.advance_beat_interval(&time_signature);
240        assert_eq!(a, MusicTime::new(1, 1, 8));
241        a.advance_beat_interval(&time_signature);
242        assert_eq!(a, MusicTime::new(1, 2, 1));
243    }
244
245    #[test]
246    fn test_event_sort() {
247        use crate::music_time::MusicTime;
248
249        let mut events = vec![
250            (MusicTime::new(2, 1, 1), vec![0]),
251            (MusicTime::new(1, 1, 1), vec![0]),
252            (MusicTime::new(4, 1, 1), vec![0]),
253            (MusicTime::new(3, 1, 1), vec![0]),
254            (MusicTime::new(3, 4, 1), vec![0]),
255        ];
256
257        events.sort_by(|a, b| a.0.cmp(&b.0));
258
259        assert_eq!(
260            events,
261            vec![
262                (MusicTime::new(1, 1, 1), vec![0]),
263                (MusicTime::new(2, 1, 1), vec![0]),
264                (MusicTime::new(3, 1, 1), vec![0]),
265                (MusicTime::new(3, 4, 1), vec![0]),
266                (MusicTime::new(4, 1, 1), vec![0]),
267            ]
268        );
269    }
270}