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
+43
View File
@@ -0,0 +1,43 @@
"""Production pass for the 5 per-altitude soundtracks + the white-noise bed
(audio spec §5.3). The audio analogue of build_pool_manifest.py --media: read the
sourced ambience clips (re-downloadable per docs/audio-candidate-pool.md), make
each a seamless loudness-normalized loop, and synthesize the pink-noise bed.
Media is gitignored; this script is the reproducible record. Outputs land under
simulator/sample_media/audio/<scale>/<name>.loop.mp3 and audio/noise/pink.mp3,
served at /media/audio/... Run: python simulator/build_audio_media.py
"""
from __future__ import annotations
from pathlib import Path
from tools.pipeline.audio_run import generate_white_noise, process_soundtrack
AUDIO = Path(__file__).parent / "sample_media" / "audio"
# scale -> (sourced raw file, production output file), both under audio/<scale>/.
# Sources per docs/audio-candidate-pool.md (the "✓ KEEP" picks).
SOURCES: dict[str, tuple[str, str]] = {
"cosmos": ("pillars.mp3", "pillars.loop.mp3"),
"orbit": ("spaceamb.mp3", "spaceamb.loop.mp3"),
"coast": ("waves.mp3", "waves.loop.mp3"),
"reef": ("soundscape.mp3", "soundscape.loop.mp3"),
"abyss": ("whale.wav", "whale.loop.mp3"),
}
def main() -> None:
for scale, (raw, out) in SOURCES.items():
src = AUDIO / scale / raw
if not src.exists():
print(f" SKIP {scale}: source missing ({src}) — re-source per audio-candidate-pool.md")
continue
dst = process_soundtrack(src, AUDIO / scale / out)
print(f" produced {dst.relative_to(AUDIO.parent)}")
noise = generate_white_noise(AUDIO / "noise" / "pink.mp3")
print(f" produced {noise.relative_to(AUDIO.parent)}")
if __name__ == "__main__":
main()