diff --git a/core/waveform.py b/core/waveform.py index bb697b9..b973a71 100644 --- a/core/waveform.py +++ b/core/waveform.py @@ -5,6 +5,20 @@ import numpy as np from core.paths import _bin +def x_to_t(x: float, width: float, view_start: float, view_dur: float) -> float: + """Map a pixel x in [0,width] to a time in [view_start, view_start+view_dur].""" + if width <= 0 or view_dur <= 0: + return view_start + return view_start + (x / width) * view_dur + + +def t_to_x(t: float, width: float, view_start: float, view_dur: float) -> int: + """Map a time to a pixel x in [0,width] (rounded).""" + if width <= 0 or view_dur <= 0: + return 0 + return int(round((t - view_start) / view_dur * width)) + + def peaks(samples, buckets: int = 128) -> list[float]: """Reduce a 1-D sample array to *buckets* normalized peak magnitudes (0..1).""" if samples is None or len(samples) == 0: diff --git a/tests/test_utils.py b/tests/test_utils.py index fc9946f..a9c1ac6 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -607,3 +607,20 @@ def test_load_region_samples_bad_path_returns_empty(): out = load_region_samples("/no/such/file.mp4", 0.0, 1.0) assert isinstance(out, np.ndarray) assert out.size == 0 + + +def test_time_pixel_roundtrip(): + from core.waveform import t_to_x, x_to_t + assert x_to_t(0, 400, 10.0, 4.0) == 10.0 + assert x_to_t(400, 400, 10.0, 4.0) == 14.0 + assert x_to_t(200, 400, 10.0, 4.0) == 12.0 + assert t_to_x(12.0, 400, 10.0, 4.0) == 200 + for x in (0, 37, 200, 399): + assert abs(t_to_x(x_to_t(x, 400, 10.0, 4.0), 400, 10.0, 4.0) - x) <= 1 + + +def test_time_pixel_guards(): + from core.waveform import t_to_x, x_to_t + assert x_to_t(50, 0, 10.0, 4.0) == 10.0 # zero width -> view_start + assert x_to_t(50, 400, 10.0, 0.0) == 10.0 # zero span -> view_start + assert t_to_x(12.0, 400, 10.0, 0.0) == 0 # zero span -> 0