← back to AgentAbrams
media/audio_mixer.py
74 lines
#!/usr/bin/env python3
"""
audio_mixer.py — Mix intro + voice + outro with loudness normalization.
Uses ffmpeg for broadcast-ready audio levels.
Usage:
python3 media/audio_mixer.py <voice.mp3> <output.mp3>
"""
import subprocess
import sys
from pathlib import Path
INTRO = "assets/intro.mp3"
OUTRO = "assets/outro.mp3"
def mix_audio(voice_file: str, output_file: str):
has_intro = Path(INTRO).exists()
has_outro = Path(OUTRO).exists()
Path(output_file).parent.mkdir(parents=True, exist_ok=True)
if has_intro and has_outro:
# Full mix: intro + normalized voice + outro
cmd = [
"ffmpeg", "-y",
"-i", INTRO,
"-i", voice_file,
"-i", OUTRO,
"-filter_complex",
"[1:a]loudnorm=I=-16:TP=-1.5:LRA=11[voice];"
"[0:a][voice][2:a]concat=n=3:v=0:a=1[aout]",
"-map", "[aout]",
"-c:a", "libmp3lame", "-b:a", "192k",
output_file,
]
elif has_intro:
cmd = [
"ffmpeg", "-y",
"-i", INTRO, "-i", voice_file,
"-filter_complex",
"[1:a]loudnorm=I=-16:TP=-1.5:LRA=11[voice];"
"[0:a][voice]concat=n=2:v=0:a=1[aout]",
"-map", "[aout]",
"-c:a", "libmp3lame", "-b:a", "192k",
output_file,
]
else:
# Voice only with normalization
cmd = [
"ffmpeg", "-y",
"-i", voice_file,
"-af", "loudnorm=I=-16:TP=-1.5:LRA=11",
"-c:a", "libmp3lame", "-b:a", "192k",
output_file,
]
print(f"Mixing audio → {output_file}")
subprocess.run(cmd, check=True)
print(f"Audio mixed: {output_file}")
def main():
if len(sys.argv) < 3:
print("Usage: audio_mixer.py <voice.mp3> <output.mp3>", file=sys.stderr)
sys.exit(2)
mix_audio(sys.argv[1], sys.argv[2])
if __name__ == "__main__":
main()