Skip to content

Instantly share code, notes, and snippets.

@Cygon
Last active May 24, 2023 09:14
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 Cygon/eb7b3646b4cdb93c484ce1a4b5544c7d to your computer and use it in GitHub Desktop.
Save Cygon/eb7b3646b4cdb93c484ce1a4b5544c7d to your computer and use it in GitHub Desktop.
Shell script that downmixes and transcodes audio into high-quality AAC tracks
#!/bin/sh
# Converts audio from BluRay or lossless source into high quality
# AAC files with custom stereo downmix parameters
#
# Use like this:
# ./transcode-audio my_movie.mkv ger51 eng51 skip jpn20
#
# Each parameter after the movie name tells the script which kind
# of audio channel to handle.
#
# Dependencies:
# * ffmpeg
# * qaac (working = w/apple's core audio toolkit)
# * wine (to run qaac)
#
# File from which the audio is taken
inputFile="$1"
# Quality, 127 is best, 95 is about equivalent to 320 kbit mp3
#
# Channels | Quality | Expected bitrate
# -----------|---------|-------------------
# 2 | 95 | 160 kbps
# 2 | 127 | 260 kbps
# 5.1 | 95 | 480 kbps
# 5.1 | 127 | 720 kbps
#
qaacStereoQuality=127
qaac5dot1Quality=127
#qaac5dot1Quality=95
# Whether to even encode the 5.1 tracks
#
# If this is false, all 5.1 audio is downmixed to stereo audio.
# And the 5.1 audio tracks are not provided at all
#
want5dot1=true
# Whether to delete the *.flac files
#
# These are created via ffmpeg and contain the processed audio
# tracks before they're transcoded to AAC (using qaac instead of
# ffmpeg's own transcoder due to qaac supposedly being higher quality)
#
# If you want to do some checking and/or processing (i.e. normalize
# volume levels) in Audacity, set this to false.
#
deleteFlacs=false
# Standard downmix formula (also used by ffmpeg with -ac 2),
# this is sourced from ATSC 7.8, but lacking mastering data,
# fixes 'clev' and 'slev' to 0.707. Makes dialogue too quiet:
# -af "pan=stereo|FL<1.0*FL+0.707*FC+0.707*BL|FR<1.0*FR+0.707*FC+0.707*BR"
#
# Nightmode dialogue formula from Doom9. This results in voices at
# levels more typical of traditional stereo recordings, but it's
# mostly just guesswork and some listening tests:
# -af "pan=stereo|FL=FC+0.30*FL+0.30*BL|FR=FC+0.30*FR+0.30*BR"
#
# The middleground between ATSC and decent dialogue volume.
# I don't perceive the dialogue as much quieter than nightmode's,
# but this should yield much better stereo separation:
# -af "pan=stereo|FL=0.85*FC+0.65*FL+0.5*BL|FR=0.85*FC+0.65*FR+0.5*BR"
#
volume350="pan=stereo|FL=2.98*FC+2.28*FL+1.75*BL|FR=2.98*FC+2.28*FR+1.75*BR"
volume325="pan=stereo|FL=2.76*FC+2.11*FL+1.63*BL|FR=2.76*FC+2.11*FR+1.63*BR"
volume300="pan=stereo|FL=2.55*FC+1.95*FL+1.5*BL|FR=2.55*FC+1.95*FR+1.5*BR"
volume250="pan=stereo|FL=2.13*FC+1.63*FL+1.25*BL|FR=2.13*FC+1.63*FR+1.25*BR"
volume200="pan=stereo|FL=1.7*FC+1.3*FL+1.0*BL|FR=1.7*FC+1.3*FR+1.0*BR"
volume100="pan=stereo|FL=0.85*FC+0.65*FL+0.5*BL|FR=0.85*FC+0.65*FR+0.5*BR"
volume90="pan=stereo|FL=0.77*FC+0.59*FL+0.45*BL|FR=0.77*FC+0.59*FR+0.45*BR"
volume80="pan=stereo|FL=0.68*FC+0.52*FL+0.4*BL|FR=0.68*FC+0.52*FR+0.4*BR"
germanStereoDownmixFormula=$volume100
stereoDownmixFormula=$volume100
# -------------------------------------------------------------------
# Figure out where we will get the 2.0 audio files from
# -------------------------------------------------------------------
# Shift the arguments one down, pushing the input filename away
shift
audioTrackIndex=0
# Figure out if we need to downmix the 2.0 channels ourselves or
# if these are provided by the source video/audio container.
#
# If you want the improved downmix formula from this script, just
# say "skip" instead of "xxx20" for the 2.0 channels and they will
# be downmixed from the 5.1 audio tracks
#
if [[ "$@" == *"eng20"* ]]
then
englishStereoNeeded=false
else
englishStereoNeeded=true
fi
if [[ "$@" == *"ger20"* ]]
then
germanStereoNeeded=false
else
germanStereoNeeded=true
fi
if [[ "$@" == *"jpn20"* ]]
then
japaneseStereoNeeded=false
else
japaneseStereoNeeded=true
fi
# -------------------------------------------------------------------
# Do the actual transcoding
# -------------------------------------------------------------------
# For each argument passed on the command line
while test $# -gt 0
do
case "$1" in
skip)
;;
eng51)
if $englishStereoNeeded ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-strict \
-2 \
-af "$stereoDownmixFormula" \
-y \
english-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
english-stereo.flac
if $deleteFlacs ; then
rm english-stereo.flac
fi
fi
if $want5dot1 ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
english-5dot1.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaac5dot1Quality \
--quality 2 \
--no-smart-padding \
--no-dither \
english-5dot1.flac
if $deleteFlacs ; then
rm english-5dot1.flac
fi
fi
;;
eng20)
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
english-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
english-stereo.flac
if $deleteFlacs ; then
rm english-stereo.flac
fi
;;
ger51)
if $germanStereoNeeded ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-strict \
-2 \
-af "$germanStereoDownmixFormula" \
-y \
german-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
german-stereo.flac
if $deleteFlacs ; then
rm german-stereo.flac
fi
fi
if $want5dot1 ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
german-5dot1.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaac5dot1Quality \
--quality 2 \
--no-smart-padding \
--no-dither \
german-5dot1.flac
if $deleteFlacs ; then
rm german-5dot1.flac
fi
fi
;;
ger20)
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
german-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
german-stereo.flac
if $deleteFlacs ; then
rm german-stereo.flac
fi
;;
jpn51)
if $japaneseStereoNeeded ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-strict \
-2 \
-af "$stereoDownmixFormula" \
-y \
japanese-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
japanese-stereo.flac
if $deleteFlacs ; then
rm japanese-stereo.flac
fi
fi
if $want5dot1 ; then
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
japanese-5dot1.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaac5dot1Quality \
--quality 2 \
--no-smart-padding \
--no-dither \
japanese-5dot1.flac
if $deleteFlacs ; then
rm japanese-5dot1.flac
fi
fi
;;
jpn20)
ffmpeg \
-hide_banner \
-i "$inputFile" \
-vn \
-map a:$audioTrackIndex \
-y \
japanese-stereo.flac
wine /opt/qaac-2.72/qaac.exe \
--tvbr $qaacStereoQuality \
--quality 2 \
--no-smart-padding \
--no-dither \
japanese-stereo.flac
if $deleteFlacs ; then
rm japanese-stereo.flac
fi
;;
esac
shift
let "audioTrackIndex = $audioTrackIndex + 1"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment