4

I have a bunch of stereo MP3s I'd like to convert to mono. What is the best way to do this? I would prefer something that would let be batch process them. I want to keep the quality as close to the original as possible. My files are also in different bitrates, so I don't want to make all files 320kpbs when some are only 128.

Also, is there any quick way to see which files are stereo out of my entire library?

Steve Rathbone
  • 496
  • 3
  • 13
Wil
  • 41
  • 1
  • 2

4 Answers4

5

Converting from stereo to mono will mean re-encoding, so keeping the same bit rate would be meaningless. In fact, converting a 128 kbit/s MP3 -> a new 128 kbit/s MP3 will net you godawfully terrible quality, even if the second one is mono (and therefore requires a lower bit rate for the same subjective quality).

Generally, I would use a Variable Bit Rate (VBR) setting for MP3, which targets a specific quality and lets the encoder set whatever bit rate is required (completely silent audio needs a lower bit rate than whalesong, which needs a lower bit rate than dubstep). From the command-line, ffmpeg can convert audio to mono with the option -ac 1, like so:

ffmpeg -i input.mp3 -c:a libmp3lame -q:a 2 -ac 1 output.mp3

See this page for a guide to using -q:a. Note that the table on that page is aimed at stereo audio; the actual bit rates you'll see will be somewhat lower. Normally, I recommend 3-4, but since you're encoding from MP3s rather than an original CD, you should aim a bit higher.

This can, of course, be automated very easily. On Linux/OSX/other UNIX-like, to convert a directory of MP3s:

for f in *.mp3; do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 -ac 1 mono-"$f"; done

To do so recursively:

find . -type f -name "*.mp3" -exec ffmpeg -i '{}' -c:a libmp3lame -q:a 2 -ac 1 mono-'{}' \;

If you have GNU Parallel and a multi-core machine, you may find this useful:

find . -type f -name "*.mp3" | parallel ffmpeg -i {} -c:a libmp3lame -q:a 2 -ac 1 mono-{}
mlissner
  • 1,202
  • 2
  • 15
  • 19
evilsoup
  • 13,097
  • 3
  • 59
  • 80
3

Well there are several ways, but let me guide you to ones that actually work. You can use Audacity, a free available software for that.

Kindly see this eHow's article on how to convert the MP3 to mono.

slhck
  • 223,558
  • 70
  • 607
  • 592
aibk01
  • 1,266
  • 2
  • 13
  • 23
  • But can I process an entire folder of MP3s like this automatically? – Wil Aug 21 '11 at 07:54
  • 1
    Yes, I also suggest to Cowoon Jet Audio easy interface and fast. – aibk01 Aug 21 '11 at 07:56
  • 1
    For Audacity read this: http://manual.audacityteam.org/man/Batch_Processing – aibk01 Aug 21 '11 at 07:57
  • 4
    [It would be nice](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link only for future reference. Could you outline the steps to perform to convert the MP3 to mono? – slhck Aug 21 '11 at 08:55
  • Yeah, I think Audacity is what I'd check into first. – Daniel R Hicks Sep 13 '13 at 20:22
1

Lame can convert to files to mono using the -m switch, the advantage being preservation of meta tags (I'm not sure if ffmpeg can do that too).

Here is a somewhat complicated example that determines the bitrate of an mp3 before transcoding it with one of the variable bitrate quality options.

cat s2mono.sh
#!/bin/bash

mp3file=$@

mp3size () {
    du -sk "$1" | awk '{print $1 * 8 }'
}
mp3length () {
    id3info "$1" | \
        awk '/=== TLEN/ { if ($NF > 0) { len=int( $NF/1000) }} END {print len}'
}
mp3rate () {
    echo $(( `mp3size "$1"` / `mp3length "$1"` ))
}

bitrate=`mp3rate "$mp3file"`
if [ $bitrate -gt 155 ]; then VBR='-V4'; fi
if [ $bitrate -gt 190 ]; then VBR='-V2'; fi
if [ $bitrate -gt 249 ]; then VBR='-V0'; fi

echo downsampling $mp3file
lame --silent $VBR -m m --mp3input "$mp3file" \
      "$(basename "$mp3file" .mp3 )-mono.mp3"

I ran this on a folder where the total size of all mp3s was 80 MB in stereo format. The resulting mono mp3s consumed only 32 MB.

 find . -iname \*mp3  -print0 |xargs -0 -L1 sh s2mono.sh
 (...)

 du -skc *-mono.mp3| tail -n1
 32376   total

 find . -iname \*mp3  |grep -ve '-mono'  |\
     while read f; do du -sk "$f" ;done  |\
     awk '{ tot+=$1} END{print tot}'
 80112

As for the last part of your question, file will do:

 find /R/audio/muzica/_ripped/wav  -exec file {} \+   |grep Monaural
  • FFmpeg does, indeed, preserve metadata, and it actually uses the LAME library for dealing with MP3s (albeit while using its own syntax rather than the LAME one). – evilsoup Sep 13 '13 at 18:21
1

Building on this answer, you can get a more portable solution (no extra dependencies, no problems with ID3v1 vs ID3v2 tags) just using file and sed. I also filled in a bit more of the bitrate settings.

In this script, you must specify the input and output files on the command line.

#!/bin/bash
#
# Usage: (this script) stereo-input.mp3 mono-output.mp3
#
# concept via https://superuser.com/a/566023/253931
#

# gnu/linux
bitrate=`file "$1" | sed 's/.*, \(.*\)kbps.*/\1/'`

# osx
# bitrate=`afinfo "$1" | grep "bits per second" | sed 's/.*: \(.*\)000 bits per second.*/\1/'`

BR='-V9'
if [ $bitrate -gt  75 ]; then BR='-V8'; fi
if [ $bitrate -gt  90 ]; then BR='-V7'; fi
if [ $bitrate -gt 105 ]; then BR='-V6'; fi
if [ $bitrate -gt 120 ]; then BR='-V5'; fi
if [ $bitrate -gt 145 ]; then BR='-V4'; fi
if [ $bitrate -gt 170 ]; then BR='-V3'; fi
if [ $bitrate -gt 180 ]; then BR='-V2'; fi
if [ $bitrate -gt 215 ]; then BR='-V1'; fi
if [ $bitrate -gt 230 ]; then BR='-V0'; fi
if [ $bitrate -gt 280 ]; then BR='-b320'; fi

echo "mono-izing file with detected bitrate '$bitrate': $1"
lame --silent $BR -m m --mp3input "$1" "$2"
Ian
  • 201
  • 2
  • 4