///|
/// Monitors audio latency and drift between producer and consumer.
pub(all) struct LatencyMonitor {
mut frames_written : Int
mut ticks_elapsed : Int
mut drift_frames_val : Int
mut underrun_count : Int
mut max_drift : Int
}
///|
/// Create a new latency monitor.
pub fn new_latency_monitor() -> LatencyMonitor {
LatencyMonitor::{
frames_written: 0,
ticks_elapsed: 0,
drift_frames_val: 0,
underrun_count: 0,
max_drift: 0,
}
}
///|
/// Update latency tracking after a tick.
/// frames_this_tick: frames produced this tick.
/// consumed: frames consumed by backend since last update.
pub fn update_latency(
monitor : LatencyMonitor,
frames_this_tick : Int,
consumed : Int,
) -> Unit {
monitor.frames_written = monitor.frames_written + frames_this_tick
monitor.ticks_elapsed = monitor.ticks_elapsed + 1
monitor.drift_frames_val = monitor.drift_frames_val +
frames_this_tick -
consumed
if consumed > frames_this_tick {
monitor.underrun_count = monitor.underrun_count + 1
}
let abs_drift = if monitor.drift_frames_val >= 0 {
monitor.drift_frames_val
} else {
-monitor.drift_frames_val
}
if abs_drift > monitor.max_drift {
monitor.max_drift = abs_drift
}
}
///|
/// Get current drift in frames.
pub fn drift_frames(monitor : LatencyMonitor) -> Int {
monitor.drift_frames_val
}
///|
/// Get current drift in seconds.
pub fn drift_secs(monitor : LatencyMonitor, sample_rate : Int) -> Float {
Float::from_int(monitor.drift_frames_val) / Float::from_int(sample_rate)
}
///|
/// Get underrun count.
pub fn underrun_count(monitor : LatencyMonitor) -> Int {
monitor.underrun_count
}
///|
/// Reset all counters.
pub fn reset_latency_monitor(monitor : LatencyMonitor) -> Unit {
monitor.frames_written = 0
monitor.ticks_elapsed = 0
monitor.drift_frames_val = 0
monitor.underrun_count = 0
monitor.max_drift = 0
}