mp3-o-matic.sh

A [pseudo] multithreaded WAV to MP3 encoder for Linux & UNIX.

Purpose

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.

Features

  • Pseudo-multithreaded encoding – encodes one file per CPU core, so your system will always be used as efficiently as possible.
  • Simple operation – Requires no arguments to function (though it optionally accepts <path to '.wav' file(s) or directory>).
  • High-quality output – the default encoder arguments result in an MP3 that most ears will find indistinguishable from the original.
  • Case-insensitive – doesn't care if the source files are called '.wav', '.WAV', '.Wav', etc.

Requirements

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.

Installation

Once the requirements are met, you simply need to place the script someplace in your path. There are two ways to accomplish this:

  1. Copy and paste the code into a blank file on your system, then make it executable.
  2. Download the script directly to your hard drive, then make it executable.

In either case, you will probably need root privileges first, e.g.:

 su -

…or:

sudo su -

1. The copy & paste method

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

2. Download the script directly

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

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/

Advanced Usage Cases

Show how long and/or how much resources transcoding took

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.

Transcoding multiple directories at once

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.

The Code

#!/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
1) If you run Debian, use debian-multimedia.org
2) Exit code '0'
3) Legally purchased as lossless WAV from magnatune.com
4) An interactive process viewer for Linux
scripts/mp3-o-matic.txt · Last modified: 2012/01/22 17:32 (external edit)
Back to top
CC Attribution-Noncommercial-Share Alike 3.0 Unported
This server powered by Debian Linux Valid CSS Driven by DokuWiki This site works best with Firefox Recent changes RSS feed Valid XHTML 1.0