rusty_daw_core/atomic/
atomic_time.rs

1use std::sync::atomic::{AtomicU64, Ordering};
2
3use crate::MusicalTime;
4
5/// Simple atomic `MusicalTime` variable with relaxed ordering.
6pub struct AtomicMusicalTime {
7    atomic: AtomicU64,
8}
9
10#[inline]
11fn u32x2_to_u64(v1: u32, v2: u32) -> u64 {
12    let v1_bytes: [u8; 4] = v1.to_ne_bytes();
13    let v2_bytes: [u8; 4] = v2.to_ne_bytes();
14    let bytes: [u8; 8] = [
15        v1_bytes[0],
16        v1_bytes[1],
17        v1_bytes[2],
18        v1_bytes[3],
19        v2_bytes[0],
20        v2_bytes[1],
21        v2_bytes[2],
22        v2_bytes[3],
23    ];
24
25    u64::from_ne_bytes(bytes)
26}
27
28#[inline]
29fn u64_to_u32x2(v: u64) -> (u32, u32) {
30    let bytes: [u8; 8] = v.to_ne_bytes();
31    let v1_bytes: [u8; 4] = [bytes[0], bytes[1], bytes[2], bytes[3]];
32    let v2_bytes: [u8; 4] = [bytes[4], bytes[5], bytes[6], bytes[7]];
33
34    (u32::from_ne_bytes(v1_bytes), u32::from_ne_bytes(v2_bytes))
35}
36
37impl AtomicMusicalTime {
38    /// New atomic musical time with initial value `value`.
39    pub fn new(musical_time: MusicalTime) -> AtomicMusicalTime {
40        AtomicMusicalTime {
41            atomic: AtomicU64::new(u32x2_to_u64(
42                musical_time.beats(),
43                musical_time.super_beats(),
44            )),
45        }
46    }
47
48    /// Get the current value of the atomic musical time.
49    pub fn get(&self) -> MusicalTime {
50        let (beats, super_beats) = u64_to_u32x2(self.atomic.load(Ordering::Relaxed));
51        MusicalTime::new(beats, super_beats)
52    }
53
54    /// Set the value of the atomic musical time to `musical_time`.
55    pub fn set(&self, musical_time: MusicalTime) {
56        self.atomic.store(
57            u32x2_to_u64(musical_time.beats(), musical_time.super_beats()),
58            Ordering::Relaxed,
59        )
60    }
61}
62
63impl Default for AtomicMusicalTime {
64    fn default() -> Self {
65        AtomicMusicalTime::new(MusicalTime::default())
66    }
67}
68
69impl std::fmt::Debug for AtomicMusicalTime {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        std::fmt::Debug::fmt(&self.get(), f)
72    }
73}
74
75impl From<MusicalTime> for AtomicMusicalTime {
76    fn from(value: MusicalTime) -> Self {
77        AtomicMusicalTime::new(value)
78    }
79}
80
81impl From<AtomicMusicalTime> for MusicalTime {
82    fn from(value: AtomicMusicalTime) -> Self {
83        value.get()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_atomic_musical_time() {
93        let musical_time_1 = MusicalTime::new(4578749, 12390);
94        let musical_time_2 = MusicalTime::new(5720495, 45781);
95
96        let atomic_musical_time = AtomicMusicalTime::new(musical_time_1);
97
98        assert_eq!(atomic_musical_time.get(), musical_time_1);
99
100        atomic_musical_time.set(musical_time_2);
101
102        std::thread::sleep(std::time::Duration::from_millis(1));
103
104        assert_eq!(atomic_musical_time.get(), musical_time_2);
105    }
106}