This commit is contained in:
Nathan Rashleigh committed 2026-06-22 22:45:04 +10:00
1 parent d5ef56c3ed
commit 9fbd222b23
2 files changed
+14 -10

No files matched your search

+6 -4
View File
@@ -20,10 +20,12 @@ is an `if TYPE_CHECKING:` block to break a circular type-only reference.
"Don't swallow into None" is a general principle at every level, including call
sites. An operation that fails must **let the exception propagate** — never catch
it and return `None` / an empty / degraded result. BPM/beat analysis is integral:
`_mixxx_analyze` raises rather than returning None, and every `Analysis.analyze`
call site (in `anlz.py`, `cli.py`, `collection/core.py`) lets failures abort the
run (including not catching around `ThreadPoolExecutor` `fut.result()`).
it and return `None` / an empty / degraded result. BPM/beat analysis and waveform
extraction are integral: `_mixxx_analyze` raises rather than returning None,
`_decode_pcm` raises (`RuntimeError`) if ffmpeg is missing or fails to decode
rather than returning an empty array, and every `Analysis.analyze` call site (in
`anlz.py`, `cli.py`, `collection/core.py`) lets failures abort the run (including
not catching around `ThreadPoolExecutor` `fut.result()`).
Reserve `None` returns for *legitimate absence* (e.g. a cache miss in
`Analysis.load`), never for *failure*. The one tolerated catch is a genuinely
+8 -6
View File
@@ -123,11 +123,12 @@ def _project_pqtz(beatgrid: list[float], bpm: float) -> list[Beat]:
def _decode_pcm(path: Path) -> np.ndarray:
"""Decode `path` to a 1D float32 numpy array of mono PCM at SAMPLE_RATE.
Returns an empty array on ffmpeg failure.
Raises `RuntimeError` if ffmpeg is missing or fails to decode — waveform
extraction is integral, so a failure here is fatal rather than swallowed
into an empty array (which would yield a waveform-less ANLZ).
"""
if not shutil.which("ffmpeg"):
logger.warning("ffmpeg not on PATH; cannot extract waveform")
return np.empty(0, dtype=np.float32)
raise RuntimeError("ffmpeg not on PATH; cannot extract waveform")
proc = subprocess.run(
["ffmpeg", "-nostdin", "-v", "error",
"-i", str(path),
@@ -135,9 +136,10 @@ def _decode_pcm(path: Path) -> np.ndarray:
capture_output=True,
)
if proc.returncode != 0:
logger.warning("ffmpeg failed for {}: {}", path.name,
proc.stderr.decode("utf-8", "replace").strip())
return np.empty(0, dtype=np.float32)
raise RuntimeError(
f"ffmpeg failed for {path.name}: "
f"{proc.stderr.decode('utf-8', 'replace').strip()}"
)
return np.frombuffer(proc.stdout, dtype=np.float32)