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:
- Rip all of my CD's using these new settings, or
- 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.
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.
This command does a great job of resampling and likely shrinking your mp3 file, but there are two drawbacks:
- 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.
- 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:
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.
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:
The script will place your resampled mp3's in a sub-directory called resample.
#
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)
#
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
#
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. 🙂
#
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.
#
Thank you for this great script! 😀
#
This is fantastic! The only change I made was to add an option to find the track's year. Thanks!
#
You might be interested in this post showing how to resample using gstreamer. http://wp.me/pB103-sn
#
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.
#
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/
#
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:
Hope somebody find this post useful as I did with previous comments.
#
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.
#
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.
#
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!
#
THE script I was looking for! But too bad the id3 tag is not written at least id3info does not show them ...
#
Thank you!!!