use std::time::Instant;
#[derive(Debug, Clone)]
pub struct StreamClock {
start: Instant,
sample_rate: u32,
}
impl StreamClock {
pub fn new(sample_rate: u32) -> Self {
Self {
start: Instant::now(),
sample_rate,
}
}
pub fn elapsed_secs(&self) -> f64 {
self.start.elapsed().as_secs_f64()
}
pub fn granule_to_secs(&self, granule: u64) -> f64 {
granule as f64 / self.sample_rate as f64
}
pub fn lead_secs(&self, granule: u64) -> f64 {
self.granule_to_secs(granule) - self.elapsed_secs()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use std::time::Duration;
#[test]
fn test_clock() {
let clock = StreamClock::new(44100);
thread::sleep(std::time::Duration::from_millis(20));
let e = clock.elapsed_secs();
assert!(e >= 0.02);
}
#[test]
fn test_granule_conversions() {
let clock_44k = StreamClock::new(44100);
let clock_48k = StreamClock::new(48000);
let clock_8k = StreamClock::new(8000);
assert_eq!(clock_44k.granule_to_secs(44100), 1.0);
assert_eq!(clock_48k.granule_to_secs(48000), 1.0);
assert_eq!(clock_8k.granule_to_secs(8000), 1.0);
assert!((clock_44k.granule_to_secs(22050) - 0.5).abs() < 0.001);
assert!((clock_48k.granule_to_secs(24000) - 0.5).abs() < 0.001);
let hour_44k = 44100 * 3600;
assert_eq!(clock_44k.granule_to_secs(hour_44k), 3600.0);
}
#[test]
fn test_lead_calculation() {
let clock = StreamClock::new(44100);
assert!(clock.lead_secs(0) < 0.0);
thread::sleep(Duration::from_millis(100)); let elapsed = clock.elapsed_secs();
let granule = (elapsed * 44100.0) as u64;
let lead = clock.lead_secs(granule);
assert!(lead.abs() < 0.05);
let future_granule = granule + 44100; assert!(clock.lead_secs(future_granule) > 0.9); }
#[test]
fn test_extreme_sample_rates() {
let low_clock = StreamClock::new(1000);
assert_eq!(low_clock.granule_to_secs(1000), 1.0);
let high_clock = StreamClock::new(192000);
assert_eq!(high_clock.granule_to_secs(192000), 1.0);
let extreme_clock = StreamClock::new(384000);
assert_eq!(extreme_clock.granule_to_secs(384000), 1.0);
}
}