Lame - How to re-encode all 320kbps mp3 to 192kbps mp3

Solution 1:

lame is perfectly suited to this task, but I'm going to use ffmpeg and ffprobe for this answer, because I know them like the back of my hand and because they can be generalised to more than just MP3s. First of all:

sudo apt-get install ffmpeg

There is no tool that I am aware of that can read media files and then over-write the input straight away: you need to use an intermediate file. For a single file, you could do:

ffmpeg -i file.mp3 -c:a libmp3lame -b:a 192k temp.mp3
mv temp.mp3 file.mp3

You could combine these into a single line:

ffmpeg -i file.mp3 -c:a libmp3lame -b:a 192k temp.mp3 && mv temp.mp3 file.mp3

the && there means that the mv command won't be executed unless ffmpeg exits with a status of 0 (which means success).

To check that what bit rate a file has, you can use ffprobe:

ffprobe -show_streams -select_streams a:0 -v quiet file.mp3 | grep -F 'bit_rate=320000'

-show_streams tells ffprobe to show information about individual streams; -select_streams tells it which ones to select, and a:0 means 'the first audio stream (this is important for MP3 files in the case of cover art, which is stored as a video stream). The pipe (|) takes the standard output of ffprobe and feeds it to grep. grep will only print those lines that match a given pattern -- in this case, lines that contain the string bit_rate=320000. If you run this on a 320k kbps MP3, you'll get a line like this:

bit_rate=32000

If you run it on anything with a different bit rate, you won't get any output at all; grep will fail to make a match, and will exit with a status of 1. This means that you can chain that command with the ffmpeg command:

ffprobe -show_streams -select_streams a:0 -v quiet file.mp3 | grep -F 'bit_rate=320000' && ffmpeg -i file.mp3 -c:a libmp3lame -b:a 192k temp.mp3 && mv temp.mp3 file.mp3

Or, a bit more readably:

ffprobe -show_streams -select_streams a:0 -v quiet file.mp3 | grep -F 'bit_rate=320000' &&
ffmpeg -i file.mp3 -c:a libmp3lame -b:a 192k temp.mp3 &&
mv temp.mp3 file.mp3

That will only act on 320 kbps MP3s. Try it with a couple of test files.

The next step is to get this working with multiple files. There are two standard ways of doing this: a for loop, and the find command. The following will act on every MP3 in a directory:

for f in *.mp3; do 
ffprobe -show_streams -select_streams a:0 "$f" | grep -F 'bit_rate=320000' &&
ffmpeg -y -i "$f" -c:a libmp3lame -b:a 192k /tmp/temp.mp3 && mv /tmp/temp.mp3 "$f"
done

This will not go into subdirectories; in order to do so, you have to set the globstar shell option:

shopt -s globstar
for f in **/*.mp3; do
ffprobe -show_streams -select_streams a:0 "$f" | grep -F 'bit_rate=320000' &&
ffmpeg -y -i "$f" -c:a libmp3lame -b:a 192k /tmp/temp.mp3 && mv /tmp/temp.mp3 "$f"
done

With find:

find . -name '*.mp3' -exec sh -c 'ffprobe -show_streams -select_streams a:0 "$0" | grep -F "bit_rate=320000" &&
ffmpeg -y -i "$0" -c:a libmp3lame -b:a 192k /tmp/temp.mp3 && mv /tmp/temp.mp3 "$0"' '{}' \;

All of these will run strictly sequentially -- they'll only convert one file at a time. Your processor is almost certainly capable of more than that, though; to speed things up, you could use GNU parallel:

sudo apt-get install parallel
shopt -s globstar
parallel 'ffprobe -show_streams -select_streams a:0 {} | grep -F "bit_rate=320000" &&
ffmpeg -y -i {} -c:a libmp3lame -b:a 192k {.}.temp.mp3 && mv {.}.temp.mp3 {}' ::: **/*.mp3

Or:

find . -name '*.mp3' | parallel 'ffprobe -show_streams -select_streams a:0 {} | grep -F "bit_rate=320000" &&
ffmpeg -y -i {} -c:a libmp3lame -b:a 192k {.}.temp.mp3 && mv {.}.temp.mp3 {}' 

Solution 2:

Lame is one of the best you can find to do this task

You can use the command lame -b 192 input.mp3 output.mp3

im not good with piping commands but you can use exiftool to get the bit rate of the mp3 file

exiftool -AudioBitrate File.mp3 

but you still need a way to pipe the commands of finding mp3 file, checking the bitrate and converting...