FFmpeg
Loading...
Searching...
No Matches
normalize.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import argparse
4import logging
5import shlex
6import subprocess
7
8HELP = '''
9Normalize audio input.
10
11The command uses ffprobe to analyze an input file with the ebur128
12filter, and finally run ffmpeg to normalize the input depending on the
13computed adjustment.
14
15ffmpeg encoding arguments can be passed through the extra arguments
16after options, for example as in:
17normalize.py --input input.mp3 --output output.mp3 -- -loglevel debug -y
18'''
19
20logging.basicConfig(format='normalize|%(levelname)s> %(message)s', level=logging.INFO)
21log = logging.getLogger()
22
23
25 argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter
26):
27 pass
28
29
31 parser = argparse.ArgumentParser(description=HELP, formatter_class=Formatter)
32 parser.add_argument('--input', '-i', required=True, help='specify input file')
33 parser.add_argument('--output', '-o', required=True, help='specify output file')
34 parser.add_argument('--dry-run', '-n', help='simulate commands', action='store_true')
35 parser.add_argument('encode_arguments', nargs='*', help='specify encode options used for the actual encoding')
36
37 args = parser.parse_args()
38
39 analysis_cmd = [
40 'ffprobe', '-v', 'error', '-of', 'compact=p=0:nk=1',
41 '-show_entries', 'frame_tags=lavfi.r128.I', '-f', 'lavfi',
42 f"amovie='{args.input}',ebur128=metadata=1"
43 ]
44
45 def _run_command(cmd, dry_run=False):
46 log.info(f"Running command:\n$ {shlex.join(cmd)}")
47 if not dry_run:
48 result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE)
49 return result
50
51 result = _run_command(analysis_cmd)
52
53 loudness = ref = -23
54 for line in result.stdout.splitlines():
55 sline = line.rstrip()
56 if sline:
57 loudness = sline
58
59 adjust = ref - float(loudness)
60 if abs(adjust) < 0.0001:
61 logging.info(f"No normalization needed for '{args.input}'")
62 return
63
64 logging.info(f"Adjusting '{args.input}' by {adjust:.2f}dB...")
65 normalize_cmd = [
66 'ffmpeg', '-i', args.input, '-af', f'volume={adjust:.2f}dB'
67 ] + args.encode_arguments + [args.output]
68
69 _run_command(normalize_cmd, args.dry_run)
70
71
72if __name__ == '__main__':
73 normalize()
#define abs(x)