mirror of
https://github.com/cjfranko/NTP-Timeturner.git
synced 2025-11-08 18:32:02 +00:00
fix: Account for drop-frame LTC in time calculation
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
parent
d13ffdc057
commit
22dc01e80f
4 changed files with 14 additions and 8 deletions
|
|
@ -242,6 +242,7 @@ mod tests {
|
||||||
minutes: 2,
|
minutes: 2,
|
||||||
seconds: 3,
|
seconds: 3,
|
||||||
frames: 4,
|
frames: 4,
|
||||||
|
is_drop_frame: false,
|
||||||
frame_rate: Ratio::new(25, 1),
|
frame_rate: Ratio::new(25, 1),
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ pub fn start_serial_thread(
|
||||||
|
|
||||||
let reader = std::io::BufReader::new(port);
|
let reader = std::io::BufReader::new(port);
|
||||||
let re = Regex::new(
|
let re = Regex::new(
|
||||||
r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})[:;](\d{2})\s+\|\s+([\d.]+)fps",
|
r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})([:;])(\d{2})\s+\|\s+([\d.]+)fps",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -60,11 +60,12 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use crate::sync_logic::LtcState;
|
use crate::sync_logic::LtcState;
|
||||||
|
use num_rational::Ratio;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
fn get_ltc_regex() -> Regex {
|
fn get_ltc_regex() -> Regex {
|
||||||
Regex::new(
|
Regex::new(
|
||||||
r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})[:;](\d{2})\s+\|\s+([\d.]+)fps",
|
r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})([:;])(\d{2})\s+\|\s+([\d.]+)fps",
|
||||||
).unwrap()
|
).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +120,7 @@ mod tests {
|
||||||
assert_eq!(st.free_count, 1);
|
assert_eq!(st.free_count, 1);
|
||||||
let received_frame = rx.try_recv().unwrap();
|
let received_frame = rx.try_recv().unwrap();
|
||||||
assert_eq!(received_frame.status, "FREE");
|
assert_eq!(received_frame.status, "FREE");
|
||||||
assert_eq!(received_frame.frame_rate, 29.97);
|
assert_eq!(received_frame.frame_rate, Ratio::new(30000, 1001));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ pub struct LtcFrame {
|
||||||
pub minutes: u32,
|
pub minutes: u32,
|
||||||
pub seconds: u32,
|
pub seconds: u32,
|
||||||
pub frames: u32,
|
pub frames: u32,
|
||||||
|
pub is_drop_frame: bool,
|
||||||
pub frame_rate: Ratio<i64>,
|
pub frame_rate: Ratio<i64>,
|
||||||
pub timestamp: DateTime<Utc>, // arrival stamp
|
pub timestamp: DateTime<Utc>, // arrival stamp
|
||||||
}
|
}
|
||||||
|
|
@ -35,8 +36,9 @@ impl LtcFrame {
|
||||||
hours: caps[2].parse().ok()?,
|
hours: caps[2].parse().ok()?,
|
||||||
minutes: caps[3].parse().ok()?,
|
minutes: caps[3].parse().ok()?,
|
||||||
seconds: caps[4].parse().ok()?,
|
seconds: caps[4].parse().ok()?,
|
||||||
frames: caps[5].parse().ok()?,
|
is_drop_frame: &caps[5] == ";",
|
||||||
frame_rate: get_frame_rate_ratio(&caps[6])?,
|
frames: caps[6].parse().ok()?,
|
||||||
|
frame_rate: get_frame_rate_ratio(&caps[7])?,
|
||||||
timestamp,
|
timestamp,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -205,6 +207,7 @@ mod tests {
|
||||||
minutes: m,
|
minutes: m,
|
||||||
seconds: s,
|
seconds: s,
|
||||||
frames: 0,
|
frames: 0,
|
||||||
|
is_drop_frame: false,
|
||||||
frame_rate: Ratio::new(25, 1),
|
frame_rate: Ratio::new(25, 1),
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,10 @@ pub fn calculate_target_time(frame: &LtcFrame, config: &Config) -> DateTime<Loca
|
||||||
let total_duration_secs =
|
let total_duration_secs =
|
||||||
Ratio::new(timecode_secs, 1) + Ratio::new(frame.frames as i64, 1) / frame.frame_rate;
|
Ratio::new(timecode_secs, 1) + Ratio::new(frame.frames as i64, 1) / frame.frame_rate;
|
||||||
|
|
||||||
// For fractional frame rates (23.98, 29.97), timecode runs slower than wall clock.
|
// For non-drop-frame fractional rates (23.98, 29.97), timecode runs slower than wall clock.
|
||||||
// We need to scale the timecode duration up to get wall clock time.
|
// We need to scale the timecode duration up to get wall clock time.
|
||||||
// The scaling factor is 1001/1000.
|
// The scaling factor is 1001/1000. For drop-frame, this isn't necessary.
|
||||||
let scaled_duration_secs = if *frame.frame_rate.denom() == 1001 {
|
let scaled_duration_secs = if *frame.frame_rate.denom() == 1001 && !frame.is_drop_frame {
|
||||||
total_duration_secs * Ratio::new(1001, 1000)
|
total_duration_secs * Ratio::new(1001, 1000)
|
||||||
} else {
|
} else {
|
||||||
total_duration_secs
|
total_duration_secs
|
||||||
|
|
@ -196,6 +196,7 @@ mod tests {
|
||||||
minutes: m,
|
minutes: m,
|
||||||
seconds: s,
|
seconds: s,
|
||||||
frames: f,
|
frames: f,
|
||||||
|
is_drop_frame: false,
|
||||||
frame_rate: Ratio::new(25, 1),
|
frame_rate: Ratio::new(25, 1),
|
||||||
timestamp: Utc::now(),
|
timestamp: Utc::now(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue