@jbowman's answer above is (at the time of writing this) the only one that truly addresses the OP's main issue, which is preserving the bit rate in the original M4A — neither more nor less — on the resulting MP3. His provided script does exactly that, relying on avprobe
to extract the bit rate from the M4A before doing the actual conversion to MP3.
Sadly, avprobe
comes with the libav
library, which is considered abandonware, since its last stable release was in February 2018 (there have been a few updates in early 2019 on their git).
The good news is that you can replace avprobe
with ffprobe
— after all, it comes with ffmpeg
, so you don't need to add an additional package for that. ffprobe
is, at best, tricky to coerce into the proper format, but, after much googling, I sort of found a solution which does, indeed, extract the correct bit rate (at least for the first stream in the M4A — if you have many, this will probably not work):
ffprobe -v quiet -of flat=s=_ -show_entries format=bit_rate <source filename>
Which should result in something like:
format_bit_rate="324440"
This requires a slightly different (and simpler) way to parse, so I wrote my own script to do that, with a twist: in my case, I have lots of albums on my Mac, some of which are in M4A, and which require converting to MP3 for my low-end car audio player. There are at least a gazillion tools that do that, some even just GUI-based front ends to ffmpeg
but nothing like 'being in control' and do it from the bash
!
So, copy & paste the script below, put it inside a file, add the required chmod +x file-name-chosen-for-the-script
, and let it roll, by invoking it with a single parameter, which is the directory where your collection of M4A files is. Just like @jbowman, I've placed the converted files inside a mp3s/
directory, but with a twist: it adds the album name as an extra subdirectory (basically, the last element of the directory fed to the script) — so everything will be grouped together again by album name :)
#!/usr/bin/env bash
# Takes a directory as parameter and converts everything inside it
# from M4A to MP3, respecting the bitrate, and creating a directory
# for the converted files.
#
# Based on https://superuser.com/a/1211902/127382 by @jbowman (2017)
if [ -d "${1}" ]
then
echo "Doing conversions from directory \"${1}\"..."
else
echo "Source directory not found! Please add it as a parameter, e.g.:"
echo " ${0} path/to/album/containing/mp3/files"
exit 1
fi
# Get the album's name from the first parameter
ALBUM_PATH="${1}"
ALBUM=$()basename "${ALBUM_PATH}")
echo "Attempting to process album \"${ALBUM}\" in source directory
\"${ALBUM_PATH}\"..."
# Create a directory for this run
mkdir -p "mp3s/${ALBUM}"
# Check if mkdir succeeded
if [[ $? -ne 0 ]]
then
echo "Could not create directory mp3s/${ALBUM} for output. Exiting..."
exit 2
fi
# Loop across the filnames in that directory that end in *.m4a, invoke
# ffprobe to extract the bitrate, then use ffmpeg to convert it into MP3
# and place the result inside the mp3s/${ALBUM}/ directory:
for f in "${ALBUM_PATH}"/*.m4a
do
echo "Before ffprobe... testing ${f}"
bitrate=$(ffprobe -v quiet -of flat=s=_ -show_entries format=bit_rate "${f}" | sed 's/[^0-9]*//g')
new_filename=$(basename "${f}" .m4a).mp3
echo "Reading ${f} and writing to mp3s/${ALBUM}/${new_filename} with bitrate ${bitrate}..."
# echo ffmpeg -y -i "${f}" -codec:a libmp3lame -b:a "${bitrate}" -q:a 2 "mp3s/${ALBUM}/${new_filename}"
ffmpeg -y -i "${f}" -codec:a libmp3lame -b:a "${bitrate}" -q:a 2 "mp3s/${ALBUM}/${new_filename}"
done
To-do: allow multiple directories as a command-line parameter, thus allowing a long batch to be run across the entire music library (1000s of songs!) and organise them properly according to their album names. The current script just works for one directory (no globbing directory names, or the results will be unpredictable — that's a fair warning!).
Caveat: some M4As really have a very high bit rate, and ffmpeg
complains a bit about those — after all, the MP3 specs define the maximum bitrate as 320 Kbps, with 192 Kbps (variable bit rate) being in practice the 'best' a human can hear with the kind of lossy compression provided by MP3. Although LAME can (allegedly) go up to 640 Kbps, such MP3s wouldn't be able to be played by ordinary, low-tech devices anyway.
ffmpeg
still does the conversion, though, and caps it at 320 Kbps (as per specs)
Script also available as a gist.
Update: Thanks to @mashuptwice for reviewing & correcting some details on the script (see comments)