How to resample MP3 audio files on Linux using LAME

August 10, 2008 by
Filed under: bash, HowTo, lame, linux, mp3, Ubuntu 

If you're like me, you're not willing to shell out several hundred dollars to buy an 80GB iPOD to carry and store your music collection. In my case, I chose the 4GB Sansa e260 as my music player. Having ripped my music at high bitrates for improved quality, I soon became dissatisfied with the capacity of my player. At that point, I decided to do some experimenting with LAME's different encoding options in order to determine what settings gave me the minimum file size while providing acceptable sound quality. For me, LAME's variable bit rate preset 5 provides a good compromise between sound quality and file size.

After determining my optimal file quality, I basically had two choices:

  1. Rip all of my CD's using these new settings, or
  2. Figure out a way to re-encode my existing files to the new bitrate.

Well, it turns out that LAME provides an easy option to resample mp3's without having to convert back to .wav first.

I'm using Ubuntu Linux, so these instructions should work for most Debian based Linux Distro's. The first step is to make sure that you have the required packages installed on your system. The packages you'll need for this process are lame and python-mutagen (which contains mid3v2). You can add them using one of the available graphical package managers, or from the terminal using apt-get.

Affiliate Link
sudo apt-get install lame python-mutagen

The LAME program doesn't provide a graphical interface, so we'll have to work in the terminal. Here's the basic command to resample a song.

lame -V5 --vbr-new --resample 44.1 song.mp3 song-resampled.mp3

This command does a great job of resampling and likely shrinking your mp3 file, but there are two drawbacks:

  1. Due to a bug (or missing feature) in the LAME code, the id3 tags are not copied into the resampled file. This means that it will show up in your player as Unknown Song by Unknown Artist.
  2. It's a pain to type this command hundreds of times to resample all of your music.

Because of the two problems above, I decided to write a script to automate the process. I actually ended up writing two scripts. The first script, mp3shrink, acts as the main program. It reads all of the mp3 files in a directory and feeds them to the second script, cptag, for resampling and copying the id3 tags.

I suggest placing the scripts in your private bin directory(~/bin). If you don't have one, just create it with:

cd
mkdir bin

So, here's the mp3shrink script. Copy the text and paste it into a text editor and save it as /home/myID/bin/mp3shrink.

#!/bin/bash
#
#mp3shrink - A script to resample all mp3 files in a
# directory.  This script calls the cptag script which
# must also be in the user's path. cptag depends upon
# lame and mid3v2 (mid3v2 can be found in the
# python-mutagen package).
#
# It is suggested that both the mp3shink and cptag
# scripts be placed in the user's private bin (~/bin).
######################################################

# List mp3's in current directory.
ls *.mp3 > mp3_list
ls *.MP3 >> mp3_list

# Parse the mp3_list and replace spaces with escaped spaces.
sed -i 's: :\\ :g' mp3_list

# Check if resample directory exists and create it if it doesn't.
if
   test -e ./resample
then
   echo "resample directory/file already exists - delete it? (Y/n)"
   read reply
   if
     [ "$reply" != "n" ]
   then
     rm -r resample
     mkdir resample
   else
     exit
   fi
else
   mkdir resample
fi

# Resample each mp3 and write tags using the cptag script
cat mp3_list |while read song
do
   echo "$song"
   cptag "$song"
done

#clean up
if
   test -e mp3_list
then
   rm mp3_list
fi
if
   test -e tag2.txt
then
   rm tag2.txt
fi
exit

OK, here's cptag. Paste the following text and save as /home/myID/bin/cptag.

#!/bin/bash
#
#cptag - A script to resample mp3 files with LAME and
#        copy id3v2 tags from the old file to the new one.
#
#####################

# Read id3 tags and write to file
mid3v2 -l "$1" > tag2.txt

# Resample music file

lame -V5 --vbr-new --resample 44.1 "$1" "resample/$1"

# Set value of variable 'title'
if
   grep TIT2= tag2.txt > /dev/null  #Test if title tag exists
then
   title=`grep TIT2= tag2.txt | sed "s:TIT2=::"`
   echo $title
else
   echo "Title tag does not exist."
fi

# Set value of variable 'album'
if
   grep TALB= tag2.txt > /dev/null  #Test if album tag exists
then
   album=`grep TALB= tag2.txt | sed "s:TALB=::"`
   echo $album
else
   echo "Album tag does not exist."
fi

# Set value of variable 'artist'
if
   grep TPE1= tag2.txt > /dev/null  #Test if artist tag exists
then
   artist=`grep TPE1= tag2.txt | sed "s:TPE1=::"`
   echo $artist
else
   echo "Artist tag does not exist."
fi

# Set value of variable 'track'
if
   grep TRCK= tag2.txt > /dev/null  # Test if track tag exists
then
   track=`grep TRCK= tag2.txt | sed "s:TRCK=::"`
   echo $track
else
   echo "Track tag does not exist."
fi

# Set value of variable 'genre'
if
   grep TCON= tag2.txt > /dev/null  # Test if genre tag exists
then
   genre=`grep TCON= tag2.txt | sed "s:TCON=::"`
   echo $genre
else
   echo "Genre tag does not exist."
fi

# Write tags to file
mid3v2 -t "$title" -A "$album" -a "$artist" -T "$track" -g "$genre" "resample/$1"

exit

Now, you'll need to make sure that the files are executable.

cd ~/bin
chmod u+x mp3shrink
chmod u+x cptag

You're now set to resample your music!

Just cd to the directory with your music files and type:

mp3shrink

The script will place your resampled mp3's in a sub-directory called resample.

Comments

15 Responses to “How to resample MP3 audio files on Linux using LAME”

  1. Toby says:

    IFS=$'\n'; find -type f -iname "*.mp3" | while read i; do /home/alexsmith/scripts/mp3shrink.sh "$i" & done

    Be careful when using this, since it will shrink all files in background, easily overloading the CPU.

    What you need is xjobs (from a package manager near you):

    find -type f -iname "*.mp3" | xjobs $HOME/scripts/mp3shrink.sh

    (P.S. you should use ${TMPDIR-/tmp} in place of plain old /tmp, then you can point it somewhere in the same filesystem as the music, to make the final copy stage faster - and to work with systems using e.g. pam_tmpdir)

  2. Elder-Geek says:

    If you are looking for the script above modified to use gStremamer, here it is.
    This script uses gStreamer instead of lame and id3v to re sample mp3s while preserving v1 and v2 tags as well as embedded cover art. It requires gstreamer-tools and there is no need for the cptag script


    #!/bin/bash
    #
    #mp3shrink - A script to resample all mp3 files in a
    # directory. This script depends upon gstremar-tools
    #
    # It is suggested that mp3shink be placed in the
    # user's private bin (~/bin).
    ######################################################

    # List mp3's in current directory.
    ls *.mp3 > mp3_list
    ls *.MP3 >> mp3_list

    # Parse the mp3_list and replace spaces with escaped spaces.
    sed -i 's: :\\ :g' mp3_list

    # Check if resample directory exists and create it if it doesn't.
    if
    test -e ./resample
    then
    echo "resample directory/file already exists - delete it? (Y/n)"
    read reply
    if
    [ "$reply" != "n" ]
    then
    rm -r resample
    mkdir resample
    else
    exit
    fi
    else
    mkdir resample
    fi

    # Resample each mp3 and write tags using the cptag script
    # CBR bitrate bitrate=128
    # VBR quality quality=9

    cat mp3_list |while read song
    do
    echo "$song"
    gst-launch filesrc location= \"$song\" ! decodebin2 ! audioconvert ! lamemp3enc target=bitrate bitrate=128 ! id3v2mux ! filesink location=\"resample/$song\"
    done

    #clean up
    if
    test -e mp3_list
    then
    rm mp3_list
    fi
    if
    test -e tag2.txt
    then
    rm tag2.txt
    fi
    exit

    • Linerd says:

      Thanks for the script. I haven't gotten back into this to rewrite it using gstreamer. It's definitely a cleaner way to go about it. :)

  3. Alex Smith says:

    Hi, guys!

    Thanks a lot for the scripts!

    I found a very nice package which copies id3tags directly in an easier manner.


    sudo apt-get install libid3-tools

    This lib has a nice binary called id3cp, which copies all id3tags from one file to another.

    Thus, the script became simpler, like this:


    #!/bin/bash

    if [ $(file --mime "$1" | grep "audio/mpeg" | wc -l) -eq 0 ]
    then
    echo "Not an mp3 file: $i"
    exit 1
    fi

    echo "Shrinking $1"
    tmp=$(basename "$1")
    lame --silent -v --preset standard "$1" "/tmp/$tmp"
    id3cp "$1" "/tmp/$tmp"
    mv "/tmp/$tmp" "$1"
    echo "Done shrinking $1"

    Note that I modified the script to encode one file at a time, thus making it possible to process multiple files in background with something like this:


    IFS=$'\n'; find -type f -iname "*.mp3" | while read i; do /home/alexsmith/scripts/mp3shrink.sh "$i" & done

    Be careful when using this, since it will shrink all files in background, easily overloading the CPU.

    To shrink a single file, one could just type this:


    ./mp3shrink.sh inputfile.mp3

    After the process, inputfile.mp3 will be shrinked down. Please note that inputfile.mp3 itself will get shrinked. This may not be what you want.

  4. Othmane says:

    Thank you for this great script! :D

  5. Scott says:

    This is fantastic! The only change I made was to add an option to find the track's year. Thanks!

  6. Matt says:

    Thank you for an amazing script. They both worked perfectly the first time. However it doesn't copy the embedded image over. Not a huge deal, but I will see if there is another script that has that feature. Thanks for writing this one.

    • Linerd says:

      You're welcome. This post is pretty old. If I were to do it again I'd probably try something with Gstreamer. It's an audio framework for Linux. In my script above I had to do some work-arounds for a bug in LAME in order to keep some of the tags. Gstreamer tends to do a good job of keeping tags as well as embedded album art. Check out these posts. They won't show exactly how to resample MP3's, but it should give you an idea how to do it. http://tuxtweaks.com/tag/gstreamer/

  7. masat says:

    Nice script Linerd!, just what I was looking for. It worked fine for me after the adds from AAM and Luca. I like to keep the directory structure of my music collection also in my music player, thus I made some minor changes to deal with this.
    1.I used 'find' instead of 'ls' to list files with full path
    2.I add a line to copy the directory structure of the music collection to encode into the resample dir.
    3.Finally, I put check for resample directory first, before listing mp3s, otherwise preexistent files will be listed

    Here is the modified script:

    #!/bin/bash
    #
    #mp3shrink - A script to resample all mp3 files in a
    # directory.  This script calls the cptag script which
    # must also be in the user's path. cptag depends upon
    # lame and mid3v2 (mid3v2 can be found in the
    # python-mutagen package).
    #
    # It is suggested that both the mp3shink and cptag
    # scripts be placed in the user's private bin (~/bin).
    ######################################################
    
    # Check if resample directory exists and create it if it doesn't.
    if
       test -e ./resample
    then
       echo "resample directory/file already exists - delete it? (Y/n)"
       read reply
       if
         [ "$reply" != "n" ]
       then
         rm -r resample
         mkdir resample
       else
         exit
       fi
    else
       mkdir resample
    fi
    
    #Copy directory structure of the music collection to encode into resample directory
    find . -type d | cpio -pvdm ./resample; rm -r ./resample/resample 
    
    # List mp3's in current directory.
    find . -name \*.mp3 > mp3_list
    find . -name \*.MP3 >> mp3_list
    
    # Parse the mp3_list and replace spaces with escaped spaces.
    sed -i 's: :\\ :g' mp3_list
    
    # Resample each mp3 and write tags using the cptag script
    cat mp3_list |while read song
    do
       echo "$song"
       ~/bin/cptag "$song"
    done
    
    #clean up
    if
       test -e mp3_list
    then
       rm mp3_list
    fi
    
    if
       test -e tag2.txt
    then
       rm tag2.txt
    fi
    
    exit
    

    Hope somebody find this post useful as I did with previous comments.

  8. Luca says:

    Hi,
    your script is great! Only a minor flaw i saw is with uncommon characters, such as Norwegian ones:
    with titles like this:

    TIT2=Inn I Evighetens Mørke (Part 1)

    grep returns a message like :
    Binary file matches

    which clutters all tags in the track.

    I have worked around it by adding the "--binary-files=text" to all grep commands in cptag, i.e.:

    # Set value of variable 'title'
    if
    grep --binary-files=text TIT2= tag2.txt > /dev/null #Test if title tag exists
    then
    title=`grep --binary-files=text TIT2= tag2.txt | sed "s:TIT2=::"`
    echo $title
    else
    echo "Title tag does not exist."
    fi

    Hope it helps.

    • Linerd says:

      Thanks for the tip. My scripts usually get to the point where they work for me and then I'm done.

      It looks like grep gets confused by the special characters and thinks the file is a binary file. So your modification forces grep to interpret the file as a text file. Good job figuring that out.

      Thanks for sharing your solution. Hopefully it will help someone else out there.

  9. AAM says:

    Thanks for the useful script. There were two parts that didn't work immediately for me:

    1. the chmod call didn't set the files to executable, so I used the Properties GUI to switch executable on

    2. the mp3shrink script needed cptag to be changed to ~/bin/cptag for it to work.

    But excellent nevertheless!

  10. Gerwin says:

    THE script I was looking for! But too bad the id3 tag is not written at least id3info does not show them ...

  11. queen says:

    Thank you!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>