Skip to content

Instantly share code, notes, and snippets.

@mako34
Created August 14, 2025 10:15
Show Gist options
  • Save mako34/c1a350d3770bf456b30e07f8efe3949c to your computer and use it in GitHub Desktop.
Save mako34/c1a350d3770bf456b30e07f8efe3949c to your computer and use it in GitHub Desktop.
Python normalize video file audio level
#!/usr/bin/env python3
"""
Simple Audio Level Normalizer
Just normalizes video audio to proper voice levels
"""
import subprocess
import sys
from pathlib import Path
def check_ffmpeg():
"""Check if FFmpeg is available"""
try:
subprocess.run(['ffmpeg', '-version'], capture_output=True, check=True)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
print("❌ FFmpeg not found! Please install FFmpeg first.")
return False
def get_current_audio_levels(video_path):
"""Get current peak and mean audio levels"""
print(f"πŸ“Š Analyzing audio levels in: {Path(video_path).name}")
cmd = [
'ffmpeg', '-i', video_path,
'-af', 'volumedetect',
'-vn', '-sn', '-dn',
'-f', 'null', '-'
]
try:
result = subprocess.run(cmd, capture_output=True, text=True)
output = result.stderr
max_volume = None
mean_volume = None
for line in output.split('\n'):
if 'max_volume:' in line:
max_volume = float(line.split('max_volume:')[1].split('dB')[0].strip())
elif 'mean_volume:' in line:
mean_volume = float(line.split('mean_volume:')[1].split('dB')[0].strip())
if max_volume is not None:
print(f" Current peak: {max_volume:.1f} dB")
if mean_volume is not None:
print(f" Current mean: {mean_volume:.1f} dB")
return max_volume, mean_volume
else:
print(" ⚠️ Could not detect audio levels")
return None, None
except Exception as e:
print(f"❌ Error analyzing audio: {e}")
return None, None
def normalize_video_audio(input_path, output_path=None, target_peak=-12):
"""
Normalize video audio to target peak level
Args:
input_path: Path to input video
output_path: Path for output video (optional)
target_peak: Target peak level in dB (default -12 dB for voice)
"""
input_path = Path(input_path)
if not input_path.exists():
print(f"❌ File not found: {input_path}")
return False
# Generate output path if not provided
if output_path is None:
output_path = input_path.parent / f"{input_path.stem}_normalized{input_path.suffix}"
else:
output_path = Path(output_path)
# Get current levels
current_peak, current_mean = get_current_audio_levels(str(input_path))
if current_peak is None:
print("❌ Could not analyze audio levels")
return False
# Calculate needed gain
gain_needed = target_peak - current_peak
print(f"\n🎚️ Audio Normalization:")
print(f" Target peak: {target_peak} dB")
print(f" Gain needed: {gain_needed:+.1f} dB")
if abs(gain_needed) < 1:
print(f" βœ… Audio is already at good levels (within 1 dB)")
print(f" Copying file without changes...")
# Just copy the file
cmd = [
'ffmpeg', '-i', str(input_path),
'-c', 'copy', # Copy streams without re-encoding
'-y',
str(output_path)
]
else:
print(f" πŸ”§ Applying {gain_needed:+.1f} dB gain...")
# Apply volume adjustment
cmd = [
'ffmpeg', '-i', str(input_path),
'-af', f'volume={gain_needed}dB',
'-c:v', 'copy', # Don't re-encode video
'-c:a', 'aac', # Re-encode audio with normalization
'-b:a', '128k', # Good audio quality
'-y',
str(output_path)
]
try:
print("βš™οΈ Processing...")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
# Check file sizes
input_size = input_path.stat().st_size / (1024 * 1024)
output_size = output_path.stat().st_size / (1024 * 1024)
print(f"βœ… Success!")
print(f" Input: {input_size:.1f} MB")
print(f" Output: {output_size:.1f} MB")
print(f" Saved as: {output_path.name}")
# Verify new levels
print(f"\nπŸ” Verifying new audio levels...")
new_peak, new_mean = get_current_audio_levels(str(output_path))
if new_peak is not None:
print(f" New peak: {new_peak:.1f} dB βœ…")
return True
else:
print(f"❌ FFmpeg error: {result.stderr}")
return False
except Exception as e:
print(f"❌ Error processing: {e}")
return False
def main():
if len(sys.argv) < 2:
print("Usage: python audio_normalizer.py input_video.mp4 [output_video.mp4] [target_db]")
print("\nExamples:")
print(" python audio_normalizer.py video.mp4")
print(" python audio_normalizer.py video.mp4 normalized.mp4")
print(" python audio_normalizer.py video.mp4 normalized.mp4 -14")
print("\nTarget levels:")
print(" -12 dB: Standard for voice content (default)")
print(" -14 dB: Good for YouTube/streaming")
print(" -16 dB: Conservative, leaves headroom")
sys.exit(1)
if not check_ffmpeg():
sys.exit(1)
input_video = sys.argv[1]
output_video = sys.argv[2] if len(sys.argv) > 2 else None
target_db = float(sys.argv[3]) if len(sys.argv) > 3 else -12
print("🎬 Simple Audio Normalizer")
print("=" * 30)
success = normalize_video_audio(input_video, output_video, target_db)
if success:
print(f"\nπŸŽ‰ Done! Your video now has properly normalized audio levels.")
else:
print(f"\n❌ Failed to normalize audio.")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment