feat(analyzer): analyze cuepoint using ffmpeg

- store cue(in|out) as strings
- reraise when executable was not found

BREAKING CHANGE: The analyzer requires 'ffmpeg'. The 'silan' system dependency can be removed.
This commit is contained in:
jo 2022-01-21 09:09:42 +01:00 committed by Kyle Robbertze
parent ceab19271d
commit d93fb44356
5 changed files with 200 additions and 121 deletions

View file

@ -1,6 +1,7 @@
import re
from math import inf
from pathlib import Path
from typing import Optional
from typing import List, Optional, Tuple
from .utils import run_
@ -54,3 +55,56 @@ def compute_replaygain(filepath: Path) -> Optional[float]:
if track_gain_match:
return float(track_gain_match.group(1))
_SILENCE_DETECT_RE = re.compile(
r"\[silencedetect.*\] silence_(start|end): (-?\d+(?:\.\d+)?)(?: \| silence_duration: (\d+(?:\.\d+)?))?"
)
def compute_silences(filepath: Path) -> List[Tuple[float, float]]:
"""
Compute silence will analyse the given audio file and return a list of silences.
"""
cmd = _ffmpeg(
*("-i", filepath),
"-vn",
*("-filter", "highpass=frequency=1000"),
*("-filter", "silencedetect=noise=0.15:duration=1"),
)
starts, ends = [], []
for line in cmd.stderr.splitlines():
match = _SILENCE_DETECT_RE.search(line)
if match is None:
continue
kind = match.group(1)
if kind == "start":
start = float(match.group(2))
start = max(start, 0.0)
starts.append(start)
elif kind == "end":
end = float(match.group(2))
ends.append(end)
# ffmpeg v3 (bionic) does not warn about silence end when the track ends.
# Set the last silence ending to infinity, and clamp it to the track duration before
# using this value.
if len(starts) - 1 == len(ends):
ends.append(inf)
return list(zip(starts, ends))
def probe_duration(filepath: Path) -> float:
"""
Probe duration will probe the given audio file and return the duration.
"""
cmd = _ffprobe(
*("-i", filepath),
*("-show_entries", "format=duration"),
*("-v", "quiet"),
*("-of", "csv=p=0"),
)
return float(cmd.stdout.strip("\n"))