Skip to content

Instantly share code, notes, and snippets.

@kylophone
Last active October 12, 2024 21:56
Show Gist options
  • Save kylophone/84ba07f6205895e65c9634a956bf6d54 to your computer and use it in GitHub Desktop.
Save kylophone/84ba07f6205895e65c9634a956bf6d54 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 'open3'
require 'json'
ffmpeg_bin = '/usr/local/bin/ffmpeg'
target_il = -24.0
target_lra = +11.0
target_tp = -2.0
samplerate = '48k'
if ARGF.argv.count != 2
puts "Usage: #{$PROGRAM_NAME} input.wav output.wav"
exit 1
end
ff_string = "#{ffmpeg_bin} -hide_banner "
ff_string += "-i #{ARGF.argv[0]} "
ff_string += '-af loudnorm='
ff_string += "I=#{target_il}:"
ff_string += "LRA=#{target_lra}:"
ff_string += "tp=#{target_tp}:"
ff_string += 'print_format=json '
ff_string += '-f null -'
_stdin, _stdout, stderr, wait_thr = Open3.popen3(ff_string)
if wait_thr.value.success?
stats = JSON.parse(stderr.read.lines[-12, 12].join)
loudnorm_string = '-af loudnorm='
loudnorm_string += 'print_format=summary:'
loudnorm_string += 'linear=true:'
loudnorm_string += "I=#{target_il}:"
loudnorm_string += "LRA=#{target_lra}:"
loudnorm_string += "tp=#{target_tp}:"
loudnorm_string += "measured_I=#{stats['input_i']}:"
loudnorm_string += "measured_LRA=#{stats['input_lra']}:"
loudnorm_string += "measured_tp=#{stats['input_tp']}:"
loudnorm_string += "measured_thresh=#{stats['input_thresh']}:"
loudnorm_string += "offset=#{stats['target_offset']}"
else
puts stderr.read
exit 1
end
ff_string = "#{ffmpeg_bin} -y -hide_banner "
ff_string += "-i #{ARGF.argv[0]} "
ff_string += "#{loudnorm_string} "
ff_string += "-ar #{samplerate} "
ff_string += ARGF.argv[1].to_s
_stdin, _stdout, stderr, wait_thr = Open3.popen3(ff_string)
if wait_thr.value.success?
puts stderr.read.lines[-12, 12].join
exit 0
else
puts stderr.read
exit 1
end
@Coding-Wolf
Copy link

Hi, thank you very much for the great loudnorm filter!

  1. Is it possible to switch the LRA-Leveler off in order to get a static normalizion processing, that works with fixed gain and limiting?
  2. Would it be possible to get MaxMomentary and MaxShortTerm Loudness into the json log file?

Thank you for your help - Wolfgang

@tcarroll2
Copy link

I cannot get print_format=json to be accepted by ffmpeg. Are you somehow using ffprobe? I see it has the print_format option.

@mmmmna
Copy link

mmmmna commented Aug 19, 2022

Input filenames are truncated when using escaped spaces?

Note: loudness2.rb is merely my edit of loudness.rb to use the actual location for installed ffmpeg (EndeavourOS, Arch); namely /usr/bin/ffmpeg

[mmmmna@home Sia Furler]$ ~/Refile\ OUT/loudness2.rb Sia-[KCRW\ studio]-Breathe\ Me-Downtempo2.flac Sia-[KCRW\ studio]-Breathe\ Me-Downtempo3.flac
Sia-[KCRW: No such file or directory
[mmmmna@home Sia Furler]$

cd to ~\Refile\ OUT\ and running from there makes no difference to failure.

Possibly not an error of your script?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment