feat: core/waveform — peak reduction + ffmpeg region decode

This commit is contained in:
2026-07-02 14:51:47 +02:00
parent 8e03b97742
commit 4c5c4276c1
2 changed files with 61 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
import subprocess
import numpy as np
from core.paths import _bin
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:
return [0.0] * buckets
a = np.abs(np.asarray(samples, dtype="float32"))
idx = np.linspace(0, len(a), buckets + 1).astype(int)
out = [float(a[idx[i]:idx[i + 1]].max()) if idx[i + 1] > idx[i] else 0.0
for i in range(buckets)]
m = max(out) or 1.0
return [v / m for v in out]
def load_region_samples(path: str, start: float, duration: float,
sr: int = 8000) -> np.ndarray:
"""Decode a [start, start+duration] mono slice via ffmpeg for waveform
preview (low sample rate). Returns a float32 numpy array, empty on failure."""
cmd = [
_bin("ffmpeg"), "-ss", str(start), "-i", path, "-t", str(duration),
"-vn", "-ac", "1", "-ar", str(sr), "-f", "f32le",
"-loglevel", "error", "pipe:1",
]
try:
proc = subprocess.run(cmd, capture_output=True, timeout=60)
except Exception:
return np.zeros(0, dtype="float32")
if proc.returncode != 0 or not proc.stdout:
return np.zeros(0, dtype="float32")
return np.frombuffer(proc.stdout, dtype="float32")
+26
View File
@@ -540,3 +540,29 @@ def test_audio_extract_ltx2_duration():
duration=frames / fps)
assert "-t" in cmd
assert cmd[cmd.index("-t") + 1] == str(frames / fps)
# --- waveform peak reduction + region decode ---
def test_peaks_downsamples_to_bucket_count():
from core.waveform import peaks
import numpy as np
samples = np.sin(np.linspace(0, 100, 10000)).astype("float32")
p = peaks(samples, buckets=64)
assert len(p) == 64
assert all(0.0 <= v <= 1.0 for v in p)
def test_peaks_empty_returns_zeros():
from core.waveform import peaks
assert peaks(None, buckets=16) == [0.0] * 16
import numpy as np
assert peaks(np.zeros(0, dtype="float32"), buckets=8) == [0.0] * 8
def test_load_region_samples_bad_path_returns_empty():
from core.waveform import load_region_samples
import numpy as np
out = load_region_samples("/no/such/file.mp4", 0.0, 1.0)
assert isinstance(out, np.ndarray)
assert out.size == 0