Skip to content

Instantly share code, notes, and snippets.

@mkasberg
Created April 9, 2022 19:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkasberg/cbc9a74807b3f7d9ba28fb0a6cd462c9 to your computer and use it in GitHub Desktop.
Save mkasberg/cbc9a74807b3f7d9ba28fb0a6cd462c9 to your computer and use it in GitHub Desktop.
FFmpeg loudnorm filter - dual pass loudness normalization example - http://k.ylo.ph/2016/04/04/loudnorm.html
#!/usr/bin/env ruby
require 'optparse'
require 'json'
metadata = {}
TARGET_I = "-16"
TARGET_TP = "-1.5"
TARGET_LRA = "11"
SAMPLE_RATE = "44100"
BITRATE = "128k"
summary = nil
optparse = OptionParser.new do |opts|
summary = opts
opts.banner = "Normalize audio loudness."
opts.banner = "Usage: loudnorm.rb [options] INFILE OUTFILE"
opts.on('-h', '--help', 'Display help') do
puts opts
exit
end
opts.on('--title TITLE', String, "Write title to output metadata") do |t|
metadata[:title] = t
end
opts.on('--artist ARTIST', String, "Write artist to output metadata") do |a|
metadata[:artist] = a
end
opts.on('--album ALBUM', String, "Write album to output metadata") do |a|
metadata[:album] = a
end
end.parse!
if ARGV.length != 2
puts summary
exit
end
infile = ARGV.first
outfile = ARGV.last
# Run the first pass.
ff_args = [
"ffmpeg",
"-hide_banner",
"-i",
infile,
"-af",
"loudnorm=I=%s:TP=%s:LRA=%s:print_format=json" % [TARGET_I, TARGET_TP, TARGET_LRA],
"-f",
"null",
"-"
]
first_pass_out = IO.popen(ff_args, err: [:child, :out])
measured = JSON.parse(first_pass_out.readlines.last(12).join)
first_pass_out.close
loudnorm_string =
"loudnorm=I=%s:TP=%s:LRA=%s:measured_I=%s:measured_TP=%s:measured_LRA=%s:measured_thresh=%s:offset=%s:linear=true:print_format=summary" %
[TARGET_I, TARGET_TP, TARGET_LRA, measured['input_i'], measured['input_tp'], measured['input_lra'], measured['input_thresh'], measured['target_offset']]
ff_args = [
"ffmpeg",
"-y",
"-hide_banner",
"-i",
infile,
"-af",
loudnorm_string,
"-ar",
SAMPLE_RATE,
"-b:a",
BITRATE,
"-ac",
"1",
"-write_xing",
"0"
]
if metadata[:title]
ff_args << "-metadata"
ff_args << "title=%s" % metadata[:title]
end
if metadata[:artist]
ff_args << "-metadata"
ff_args << "artist=%s" % metadata[:artist]
end
if metadata[:album]
ff_args << "-metadata"
ff_args << "album=%s" % metadata[:album]
end
ff_args << outfile
exec(*ff_args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment