audio_clock/
lib.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicUsize, Ordering};
3
4pub struct ClockUpdater {
5    clock: Arc<AtomicUsize>
6}
7
8impl ClockUpdater {
9    pub fn increment(&mut self, frames: usize) {
10        self.clock.store(self.clock.load(Ordering::Relaxed) + frames, Ordering::Release);
11    }
12}
13
14pub struct ClockConsumer {
15    clock: Arc<AtomicUsize>,
16    rate: u32,
17    tempo: f32
18}
19
20impl ClockConsumer {
21    pub fn raw_frames(&self) -> usize {
22        self.clock.load(Ordering::Acquire)
23    }
24    pub fn beat(&self) -> f32 {
25        self.tempo / 60. * (self.raw_frames() as f32 / self.rate as f32)
26    }
27    pub fn beat_duration(&self) -> f32 {
28        self.tempo / 60.
29    }
30}
31
32impl Clone for ClockConsumer {
33    fn clone(&self) -> ClockConsumer {
34        ClockConsumer {
35            rate: self.rate,
36            tempo: self.tempo,
37            clock: self.clock.clone()
38        }
39    }
40}
41
42pub fn audio_clock(tempo: f32, rate: u32) -> (ClockUpdater, ClockConsumer) {
43    let c = Arc::new(AtomicUsize::new(0));
44    (ClockUpdater { clock: c.clone() }, ClockConsumer { clock: c, tempo, rate })
45}
46
47#[cfg(test)]
48mod tests {
49    use audio_clock;
50
51    #[test]
52    fn it_works() {
53        let (mut updater, consumer) = audio_clock(132.0, 44100);
54        updater.increment(128);
55        assert_eq!(consumer.raw_frames(), 128);
56        assert_eq!(consumer.beat_duration(), 132.0 / 60.);
57        assert_eq!(consumer.beat(), consumer.beat_duration() * (consumer.raw_frames() as f32 / 44100. ));
58        updater.increment(64);
59        assert_eq!(consumer.raw_frames(), 128 + 64);
60        assert_eq!(consumer.beat_duration(), 132.0 / 60.);
61        assert_eq!(consumer.beat(), consumer.beat_duration() * (consumer.raw_frames() as f32 / 44100. ));
62        let second_consumer = consumer.clone();
63        updater.increment(64);
64        assert_eq!(consumer.raw_frames(), 128 + 64 + 64);
65        assert_eq!(consumer.raw_frames(), second_consumer.raw_frames());
66        assert_eq!(consumer.beat_duration(), second_consumer.beat_duration());
67        assert_eq!(consumer.beat(), second_consumer.beat());
68    }
69}