#!/bin/bash # -*-shell-script-*- # Converts CD tracks to MP3 files using cdda2wav(1) and lame(1). # Copyright (C) 2005 Ernest N. Mamikonyan # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Current known issues: # *) I don't know how to deal with CD-Extra and CD-Text as I don't have any CDs # with these extensions. # some defaults device=/dev/cdrom # default CDROM device force=false # don't overwrite files without prompting quiet=false # produce progress output to_keep=false # keep the temporary WAV and info files to_number=false # don't number output files # enable colors but only when output is a tty if [[ -t 2 ]]; then ec='\e[31m' # error color (red) wc='\e[33m' # warning color (yellow) sc='\e[32m' # success color (green) nc='\e[39m' # normal color fi error() { builtin echo -n "${0##*/}: $ec$1" >&2 [[ "$2" ]] && builtin echo " - exiting...$nc" >&2 && exit $2 builtin echo "$nc" >&2 } warn() { echo "${0##*/}: $wc$@$nc" >&2; } usage() { echo "\ Usage: ${0##*/} [OPTIONS] [-] [TRACK | RANGE ...] Convert audio CD tracks to MP3 files using cdda2wav(1) and lame(1) -A use variable bitrate when encoding MP3 files -C SERV contact SERV for CDDB table lookups -D DEV use DEV as the CDROM device -f never prompt before overwriting existent files -h display this help message and exit -k keep the intermediate .wav and .inf files -n number the output files instead of using the title of the song -o DIR put output files in DIR -q suppress all diagnostic output and warnings -S SPD set the speed of the CDROM device to SPD -T DIR use DIR to store intermediate files -V display version information and exit " >&2 exit $1 } to_clobber() { [[ -e "$1" ]] || return 0 if $force; then warn "$1 exists - overwriting..."; return 0 else read -n 1 -p "$1 exists - overwrite? " < /dev/tty if [[ "$REPLY" != [Yy] ]]; then [[ "$REPLY" ]] && builtin echo \\bNo. >&2 || builtin echo No. >&2 return 1 fi builtin echo \\bYes! >&2 return 0 fi } convert() { local track="${9%.wav}" [[ "$track" == *0? ]] && track=${track#*0} to_clobber "${10}" || return echo -n "Track ${track#*_} ==> ${10##*/}:\e[70G" local -r error=$(lame "$@" 2>&1) if [[ $? != 0 || ! -f "${10}" ]]; then echo " ${ec}failed$nc\e[K" [[ "$error" ]] && error "$error" else echo " ${sc}done$nc\e[K" fi } mkdir() { command mkdir -- "$1" || error "can't make directory $1" 2; } shopt -s expand_aliases nullglob xpg_echo while getopts :AC:D:fhkno:qS:T:V option; do case $option in A) lame_f='--vbr-new';; C) cdda2wav_f="$cdda2wav_f cddbp-server=$OPTARG";; D) device="$OPTARG";; f) force=true;; h) usage 0;; k) to_keep=true;; n) to_number=true;; o) [[ "$OPTARG" == /* ]] && outdir="$OPTARG" || outdir="$PWD/$OPTARG";; q) quiet=true;; S) cdda2wav_f="$cdda2wav_f -S $OPTARG";; T) tmpdir="$OPTARG";; V) echo $'\ cd2mp3 version 1.2, Copyright © 2005 Ernest N. Mamikonyan. cd2mp3 comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; see the source for details. ' exit 0 ;; :) error "the \`-$OPTARG' option requires an argument"; usage 1;; *) error "\`-$OPTARG' is not a valid option"; usage 1;; esac done shift $((OPTIND-1)) $quiet && echo() { :; } || echo() { builtin echo "$@" >&2; } alias cdda2wav="cdda2wav -B -D $device -I cooked_ioctl -L 0 -q -x $cdda2wav_f" if [[ "$tmpdir" ]]; then [[ -d "$tmpdir" ]] || mkdir "$tmpdir" else tmpdir="$PWD/$(mktemp -d ${0##*/}.XXXXXX)" [[ $? == 0 ]] || error "can't create temporary directory" 2 if $to_keep; then trap 'warn "intermediate files are in $tmpdir, as requested"' EXIT trap 'warn "intermediate files are in $tmpdir, as requested"; exit 1' \ INT TERM else trap 'rm -rf -- "$tmpdir"' EXIT trap 'rm -rf -- "$tmpdir"; exit 1' INT TERM fi fi cd "$tmpdir" || error "can't change directory to $tmpdir" 2 echo "reading from CDROM device, $device, with cdda2wav(1)..." (($#)) || cdda2wav track for arg; do case "$arg" in [0-9]*-[0-9]*) cdda2wav -t"${arg//-/+}" track;; [0-9]*-) cdda2wav -t+"${arg%-*}" track;; -[0-9]*) cdda2wav -t1+"${arg#*-}" track;; [0-9]*) [[ "$arg" == ?? ]] || arg="0$arg" cdda2wav -t"$arg+$arg" track && rename . _$arg. track.{inf,wav};; *) error 'argument must be a number or a range'; usage 1;; esac done if [[ -z "$(builtin echo track_??.wav)" ]]; then error "cdda2wav(1) did not produce any files" 2 fi if [[ -r audio.cddb ]]; then OIFS="$IFS" IFS=$'\n' lines=($(< audio.cddb)) IFS="$OIFS" for line in "${lines[@]}"; do case "$line" in DYEAR=*) readonly year="${line#*=}";; DGENRE=*) readonly genre="${line#*=}"; break;; esac done alias lame="lame -htmj --quiet --ty '$year' --tg '$genre' $lame_f" else to_number=true alias lame="lame -htmj --quiet $lame_f" warn audio.cddb is missing or unreadable - using track numbers for filenames fi [[ -d "${outdir:=$OLDPWD}" ]] || mkdir "$outdir" for file in track_??.wav; do inf=${file%.wav}.inf # reset these from the previous iteration artist= title= track= if [[ -r $inf ]]; then OIFS="$IFS" IFS=$'\n' lines=($(< "$inf")) IFS="$OIFS" for line in "${lines[@]}"; do case "$line" in Performer=*) artist="${line#*\'}" artist="${artist%\'}";; Albumtitle=*) cdtitle="${line#*\'}" cdtitle="${cdtitle%\'}";; Tracktitle=*) title="${line#*\'}" title="${title%\'}";; Tracknumber=*) track="${line#*=}" track="${track:1}";; esac done else warn "$inf is missing or unreadable due to an error in cdda2wav(1)" fi if $to_number; then [[ $track == ?? ]] && out=$track.mp3 || out=0$track.mp3 else out="${title//\//-}.mp3" fi # last chance to catch empty output filenames [[ "$out" == .mp3 ]] && out=${file%.wav}.mp3 convert --tl "$cdtitle" --ta "$artist" --tn "$track" --tt "$title" $file "$outdir/$out" done