Skip to content

Instantly share code, notes, and snippets.

@njh
Last active December 18, 2021 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save njh/f03c9f9ee2dcdf463c69bcd3500e72ba to your computer and use it in GitHub Desktop.
Save njh/f03c9f9ee2dcdf463c69bcd3500e72ba to your computer and use it in GitHub Desktop.
Script to normalise a WAV file's loudness to specific LUFS using ffmpeg
#!/usr/bin/env ruby
#
# Script to normalise an audio file's loudness using ffmpeg
#
# Usage: normalise-loudness.rb <input.wav> <output.wav>
#
# License: https://unlicense.org/
#
# Requires the 'json' ruby gem:
#
# gem install json
#
require 'open3'
require 'json'
I="-18" # Integrated loudness target (LUFS)
TP="-2.0" # Maximum true peak (dB)
LRA="10" # Loudness range target (LU)
def loudnorm_analyse(src)
cmd = [
'ffmpeg',
'-i', src,
'-af', "loudnorm=I=#{I}:TP=#{TP}:LRA=#{LRA}:print_format=json",
'-f', 'null', '-'
]
stdout, stderr, status = Open3.capture3(*cmd)
raise "ffmpeg error: #{stderr}" unless status.success?
log, json = stderr.split(/\[Parsed_loudnorm_\d+ @ \w+\]\s*/)
JSON.parse(json, :symbolize_names => true)
end
def loudnorm_normalise(src, dest, params)
loudnorm_params = {
'I' => I,
'TP' => TP,
'LRA' => LRA,
'measured_I' => params[:input_i],
'measured_LRA' => params[:input_lra],
'measured_TP' => params[:input_tp],
'measured_thresh' => params[:input_thresh],
'offset' => params[:target_offset],
'linear' => 'true',
'print_format' => 'summary'
}.to_a.map {|k,v| "#{k}=#{v}"}.join(':')
cmd = [
'ffmpeg',
'-i', src,
'-af', "loudnorm=#{loudnorm_params}",
'-ar', '48k',
dest
]
stdout, stderr, status = Open3.capture3(*cmd)
raise "ffmpeg error: #{stderr}" unless status.success?
log, summary = stderr.split(/\[Parsed_loudnorm_\d+ @ \w+\]\s*/)
return summary
end
if ARGV.size < 1
$stderr.puts "Usage: normalise-loudness.rb <input.wav> [<output.wav]"
exit(-1)
end
input_filepath, output_filepath = ARGV
if output_filepath.nil?
output_filepath = input_filepath.sub(/\.\w+$/, '-normalised.wav')
end
if File.exist?(output_filepath)
$stderr.puts "ERROR: Output file already exists"
exit(-1)
end
unless File.exist?(input_filepath)
$stderr.puts "ERROR: Input file does not exist"
exit(-1)
end
params = loudnorm_analyse(input_filepath)
result = loudnorm_normalise(input_filepath, output_filepath, params)
puts result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment