A [pseudo] multithreaded WAV to MP3 encoder for Linux & UNIX.
It seems there are a lot of scripts out there with the aim of easily encoding raw PCM '.wav' files to MP3s. I couldn't find any that met my requirements, so I wrote mp3-o-matic.sh to meet my needs. I hope you find it useful as well.
| Application | Information |
|---|---|
| bash | The Bourne Again SHell, available in most if not every distribution of Linux and UNIX (though not always installed by default). |
| lame (or compatible) | e.g. lame, twolame, toolame, etc. Usually included in your distribution's repositories.1) If not, see http://lame.sourceforge.net/ |
| normalize-audio | Optional; this little app can losslessly normalize a raw PCM '.wav' file to nominal values before we encode it to an MP3. |
Once the requirements are met, you simply need to place the script someplace in your path. There are two ways to accomplish this:
In either case, you will probably need root privileges first, e.g.:
su -
…or:
sudo su -
If you will be copying and pasting the script, use your favorite text editor to create the file in question. In this example, I'll use vim:
vim /usr/local/bin/mp3-o-matic.sh
…then paste in the code on this page, save, and exit. Finally, make the resulting file executable:
chmod 755 /usr/local/bin/mp3-o-matic.sh
Alternately, you could skip the text editor and just grab the file directly:
wget http://tuxhelp.org/pub/scripts/mp3-o-matic.sh -O /usr/local/bin/mp3-o-matic.sh && chmod 755 /usr/local/bin/mp3-o-matic.sh
Or the same, but with curl instead of wget:
curl http://tuxhelp.org/pub/scripts/mp3-o-matic.sh > /usr/local/bin/mp3-o-matic.sh && chmod 755 /usr/local/bin/mp3-o-matic.sh
Usage is easy; just run mp3-o-matic.sh from within the directory containing your WAV files. If the processes completes uneventfully, it will exit silently.2) Freshly encoded MP3 files should appear in your present working directory.
Alternately, you may specify the path to a single WAV file, a list of WAV files, or a directory containing one or more WAV files. For example:
flac-distiller.sh /home/chris/music/My-PCM-Album/
In this example, I will encode the album “Bach Violin Concertos” by Lara St. John,3) which is in my common/Temp directory. Notice the path here is relative; it could be absolute, a list of files to be encoded, or left off entirely (if the WAV files are in my present working directory).
I would like to see how long the whole process took, and I'd like to see a visual representation of my system resource usage during transcoding. To accomplish these goals, I could call my script from the 'time' utility, then pipe it through htop:4)
time mp3-o-matic.sh common/Temp/Lara\ St\ John/Bach\ Violin\ Concertos/ | htop
…while the files are encoding, I'd see the lovely, color-coded htop system monitor in action:
After transcoding finished, htop would automatically exit and I'd be shown the output from 'time':
real 0m37.308s user 2m11.568s sys 0m1.763s
So in this example, transcoding took 2 minutes and 11 seconds of CPU time, but only 37 seconds of actual time to complete.
Suppose you'd like to transcode the WAV files in several directories without having to specify each one by name. We could accomplish this with a simple 'for' loop:
for d in $(ls) ; do mp3-o-matic.sh $d ; done
If we wanted to know how long the whole process took, we could prefix the whole thing with the 'time' utility:
time `for d in $(ls) ; do mp3-o-matic.sh $d ; done`
…or alternately, show how long it took to encode each individual directory:
for d in $(ls) ; do echo "$d took:" && time mp3-o-matic.sh $d && echo "" ; done
Ahh, the power of UNIX.
#!/bin/bash ######################################################### # A [pseudo] multithreaded WAV to MP3 encoder # ######################################################### # By Christopher A. Wadge, 09/04/2010 # # # # http://tuxhelp.org/scripts/mp3-o-matic # # # # Licensed under the GPL version 3. A copy of the GPL # # version 3 is included with this script. If the file, # # COPYING, is not included, you can find the GPL # # version 3 at the following URL online: # # # # http://www.gnu.org/licenses/gpl-3.0.html # ######################################################### # This script's name: PROGRAM_NAME="mp3-o-matic.sh" # Date of last revision: PROGRAM_DATE="12/30/11" ## VARIABLES ## # The following are pre-determined variables that are not answered by the script. ##### ## Executable Paths ## # lame/twolame/toolame binary locale: MP3ENCODER="/usr/bin/lame" # normalize-audio binary locale: NORMAUDIO="/usr/bin/normalize-audio" ## Encoder Variables ## # Nice priority level (19 to -20, 19 being the lowest): PROCNICE="10" # You can append additional values to the $MP3ENCODER encoding process if you wish: XTRAOPTS="--vbr-new -h -V 0" # Whether we should normalize the volume level of the original file before encoding: NORMALIZE="false" # Max number of encoder threads to use (leave blank for auto-detection): THREADMAX="" ## !!! Attention Users: Editing below this line is not advised unless you really know what you're doing. ## FUNCTIONS ## # Define each function that we will call in scripting later ##### Error () { echo "[FATAL] Unfortunately we've encountered an unrecoverable error. Now quitting." exit 1 } Print_Help () { echo "" echo "==== $PROGRAM_NAME ($PROGRAM_DATE) ====" echo "" echo "Description: A multi-threaded front-end for popular MP3 encoders." echo "" echo "Usage: $0 <path to '.wav' file(s) or directory>" echo " You may also specify a wildcard, e.g. '*.wav'." echo " Sans arguments, it will search the current directory." echo "" echo "Dependencies: - At least one of: 'lame', 'twolame', or 'toolame'" echo " - The Bourne Again SHell (aka 'BASH')" echo " + Optional: 'normalize-audio'" echo "" exit 1 } Detect_Threads () { if [ -z $THREADMAX ] ; then if [ `uname -a | grep -c Linux` = 1 ] ; then THREADMAX=`cat /proc/cpuinfo | grep -c processor` elif [ `uname -a | egrep -c '(BSD|Darwin)'` = 1 ] ; then THREADMAX=`sysctl -a | grep hw.ncpu | grep -v "=" | cut -d " " -f2` fi elif (( "$THREADMAX" >= "1" )) ; then THREADMAX="$THREADMAX" else echo "[WARNING] Unable to detect maximum supported CPU threads; falling back to 1 thread to be safe." echo " You can specify the thread count manually in the 'VARIABLES' section of this script." THREADMAX="1" fi } Sanity_Check () { if [ ! -e /bin/bash ] ; then echo "[ERROR] It doesn't appear that you have the Bourne Again SHell (aka 'BASH')!" echo " The [over-hyped] 'DASH' shell is too primitive to interpret this script." echo " Please use your package manager to install 'bash' and try again." NOTSANE=1 fi if [ ! -e $MP3ENCODER ] ; then echo "[ERROR] The MP3 Encoder binary is not in the expected location: '$MP3ENCODER'" echo " If no lame-compatible encoder is installed, try installing one with your package manager." echo " Otherwise, you can correct the path by editing the VARIABLES section of this script." NOTSANE=1 fi if [ " $NORMALIZE " = " true " ] ; then if [ ! -e $NORMAUDIO ] ; then echo "[WARNING] The normalize-audio binary is not in the expected location: '$NORMAUDIO'" echo " This is a non-critical error. However, normalization is currently enabled." echo " If you no longer wish to see this error, set the 'NORMALIZE' variable to 'false'." NORMALIZE="false" fi fi if [ ! -z $NOTSANE ] ; then echo "[ERROR] Missing dependencies prevent this script from proceeding!" Error fi } MP3_Encode () { for file; do [ -r "$file" ] || { echo '[ERROR] Unable to read file: \"$file\"' >&1 ; Error ; } FILEOUT=$(echo "$file" | sed s'/[.][wW][aA][vV]//') if [ " $NORMALIZE " = " true " ] ; then $NORMAUDIO --quiet "$file" || echo "[WARNING] Normalization failed for $file" fi $MP3ENCODER --quiet $XTRAOPTS \ "$file" "$FILEOUT".mp3 || { echo "[ERROR] Transcoding failed for '$file'" >&1 ; Error ; } ; done } ## SCRIPTING ## # Here's where we actually do all the work ##### if [ " $1 " = " --help " ] ; then Print_Help fi Sanity_Check Detect_Threads export MP3ENCODER if [ " $NORMALIZE " = " true " ] ; then export NORMAUDIO fi export NORMALIZE export XTRAOPTS export -f Error export -f MP3_Encode find "${@}" -maxdepth 1 -name '*[.][wW][aA][vV]' -print0 | xargs -0 -n 1 -P $THREADMAX nice -n $PROCNICE bash -c 'MP3_Encode "$@"' -- exit 0