Skip to main content

speech_prep/
time.rs

1//! Time types for audio processing.
2
3use std::time::{Duration, Instant};
4
5/// Duration in the audio pipeline. Alias for `std::time::Duration`.
6pub type AudioDuration = Duration;
7
8/// Monotonic instant for measuring elapsed time.
9pub type AudioInstant = Instant;
10
11/// Timestamp as nanoseconds from the start of an audio stream.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
13pub struct AudioTimestamp(u64);
14
15impl AudioTimestamp {
16    pub const ZERO: Self = Self(0);
17    pub const EPOCH: Self = Self(0);
18
19    pub fn from_secs(secs: f64) -> Self {
20        Self((secs * 1_000_000_000.0) as u64)
21    }
22
23    pub fn from_nanos(nanos: u64) -> Self {
24        Self(nanos)
25    }
26
27    pub fn from_samples(samples: u64, sample_rate: u32) -> Self {
28        if sample_rate == 0 {
29            return Self::ZERO;
30        }
31        Self(samples * 1_000_000_000 / sample_rate as u64)
32    }
33
34    pub fn as_secs(&self) -> f64 {
35        self.0 as f64 / 1_000_000_000.0
36    }
37
38    pub fn as_millis(&self) -> f64 {
39        self.0 as f64 / 1_000_000.0
40    }
41
42    pub fn nanos(&self) -> u64 {
43        self.0
44    }
45
46    pub fn add_duration(&self, d: Duration) -> Self {
47        Self(self.0.saturating_add(d.as_nanos() as u64))
48    }
49
50    pub fn duration_since(&self, earlier: Self) -> Option<Duration> {
51        self.0.checked_sub(earlier.0).map(Duration::from_nanos)
52    }
53}
54
55impl std::ops::Add<Duration> for AudioTimestamp {
56    type Output = Self;
57    fn add(self, rhs: Duration) -> Self {
58        self.add_duration(rhs)
59    }
60}
61
62impl std::ops::Sub for AudioTimestamp {
63    type Output = Duration;
64    fn sub(self, rhs: Self) -> Duration {
65        Duration::from_nanos(self.0.saturating_sub(rhs.0))
66    }
67}
68
69impl std::fmt::Display for AudioTimestamp {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        write!(f, "{:.3}s", self.as_secs())
72    }
73}
74
75/// Range validation helper.
76pub fn validate_in_range<T: PartialOrd + std::fmt::Display>(
77    value: T,
78    min: T,
79    max: T,
80    name: &str,
81) -> crate::error::Result<()> {
82    if value < min || value > max {
83        return Err(crate::error::Error::config(format!(
84            "{name} = {value} is outside valid range [{min}, {max}]"
85        )));
86    }
87    Ok(())
88}