feat(audio): ffmpeg production pass — loop/loudnorm builders, runner, build script

Pure arg builders (audio_ops) + thin runner (audio_run) + build_audio_media.py.
Produces the 5 normalized soundtrack loops + a synthesized pink-noise bed under
the gitignored sample_media/audio tree. 6 tests pass (white-noise integration
runs against bundled imageio_ffmpeg).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-26 07:41:34 -07:00
parent 062a283de4
commit 39fb9108db
4 changed files with 226 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
"""Unit tests for the pure audio ffmpeg arg builders (no ffmpeg run), plus an
opt-in integration test that actually synthesizes a noise bed when ffmpeg is
present."""
import shutil
import pytest
from tools.pipeline.audio_ops import audio_loop_args, loudnorm_args, white_noise_args
def test_loop_args_mirror_the_video_crossfade_recipe():
args = audio_loop_args("in.mp3", "out.mp3", duration=30.0, overlap=2.0, ff="FF")
assert args[0] == "FF"
joined = " ".join(args)
# tail crossfades over head, then concats the middle — the audio analogue of
# crossfade_loop_args. Output length = duration - overlap.
assert "acrossfade=d=2.0" in joined
assert "atrim=0:2.0" in joined # head
assert "atrim=28.0:30.0" in joined # tail (d-overlap : d)
assert "concat=n=2:v=0:a=1" in joined
assert "-map" in args and "[out]" in args
assert "-q:a" in args and "4" in args
def test_loop_args_reject_overlap_past_half():
with pytest.raises(ValueError):
audio_loop_args("in.mp3", "out.mp3", duration=10.0, overlap=5.0)
def test_loudnorm_args_carry_the_locked_targets():
args = loudnorm_args("in.mp3", "out.mp3", ff="FF")
joined = " ".join(args)
assert "loudnorm=I=-18.0:TP=-1.5:LRA=11.0" in joined
assert args[0] == "FF" and args[-1] == "out.mp3"
def test_white_noise_args_are_pink_and_clean():
args = white_noise_args("noise.mp3", duration=60.0, color="pink", ff="FF")
joined = " ".join(args)
assert "anoisesrc=color=pink" in joined
assert "-t" in args and "60.0" in args
assert args[-1] == "noise.mp3"
def test_white_noise_rejects_unknown_color():
with pytest.raises(ValueError):
white_noise_args("noise.mp3", color="ultraviolet")
def _have_ffmpeg() -> bool:
if shutil.which("ffmpeg"):
return True
try:
import imageio_ffmpeg # noqa: F401
return True
except Exception:
return False
@pytest.mark.skipif(not _have_ffmpeg(), reason="no ffmpeg available")
def test_generate_white_noise_writes_a_playable_loop(tmp_path):
from tools.pipeline.audio_run import generate_white_noise
out = generate_white_noise(tmp_path / "pink.mp3", duration=2.0)
assert out.exists() and out.stat().st_size > 0