A small shell script to grab audio from a CD and encode/compress it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

456 lines
13 KiB

#!/bin/bash
# === some global setting & configurations for the script ===
umask 000 # create files with all right for anyone
shopt -s nullglob # expand patterns which match no file to a null string
shopt -s extdebug
# --------------------------------------------------------------
# das Verzeichnis in dem dieses script liegt herausfinden
scriptDir=${0%/*}
scriptDir="${scriptDir/#\./${PWD}}"
case "${scriptDir}" in /*);; *) scriptDir="${PWD}/${scriptDir}";; esac
# --------------------------------------------------------------
# include helpers
. ${scriptDir}/shellUtils.sh
# --------------------------------------------------------------
# string definitions
enhUsage=$"usage: $0 [-t(m|f|o|w)] [-p path] [-e encoder] [-c cddbitem] [-h]
[-I interface] [-D device] [-v[v|0]] [-q]
[--help] [--encoding=(m|f|o|w)] [--encoder=(lame|bladeenc)]
[--path=<string>] [--interface=(cooked_ioctl|generic_scsi)]
[--device=<string>]
options:
-h | --help: gives this help
-v: set verbosity level.
-v0 disable all output
-v be more verbose
-vv enables debug
-q: make the script silent. Equivalent to -v0
-t | --encoding: you can specify either m for encoding to mp3
using lame, or f for making lossless encoding using flac,
or o for making ogg/vorbis, or w for uncompressed wav.
Omitting this results in encoding to flac.
mp3s will be placed under a subfolder mp3 and flacs
under a subfolder flac
-p | --path: specifies the path to save the encoded data.
Defaults to the users home directory.
-e | --encoder: specifies the mp3 encoder to use.
valid encoders are actually: lame,bladeenc
Defaults to lame.
-c: specifies the CDDB-Entry to use.
sometimes there is more than 1 entry for a cd in cddb.
Then you can specify wich one to use by this option.
You can checkout all entries using cddb.pl.
-I | --interface: specifies cdda2wav interface to use.
Valid interfaces are generic_scsi and cooked_ioctl.
Please note that cooked_ioctl is not available on all
systems. Defaults to cooked_ioctl if device begins with
/dev else to generic_scsi
-D | --device: specifies device to use with cdda2wav. All values that
are valid for cdda2wav are valid here.
Defaults to /dev/cdrom
This script uses cdda2wav, cddb and various encoders to rip an audio CD."
usage=$"usage: $0 [-t(m|f|o|w)] [-p path] [-e encoder] [-c cddbitem] [-h]
[-I interface] [-D device] [-v[v|0]] [-q]
options:
-h: this help
-v: set verbosity level.
-v0 disable all output
-v be more verbose
-vv enables debug
-q: make the script silent. Equivalent to -v0
-t: you can specify either m for encoding to mp3
using lame, or f for making lossless encoding using flac,
or o for making ogg/vorbis, or w for uncompressed wav.
Omitting this results in encoding to flac.
mp3s will be placed under a subfolder mp3 and flacs
under a subfolder flac
-p: specifies the path to save the encoded data.
Defaults to the users home directory.
-e: specifies the mp3 encoder to use.
valid encoders are actually: lame,bladeenc
Defaults to lame.
-c: specifies the CDDB-Entry to use.
sometimes there is more than 1 entry for a cd in cddb.
Then you can specify wich one to use by this option.
You can checkout all entries using cddb.pl.
-I: specifies cdda2wav interface to use.
Valid interfaces are generic_scsi and cooked_ioctl.
Please note that cooked_ioctl is not available on all
systems. Defaults to cooked_ioctl if device begins with
/dev else to generic_scsi
-D: specifies device to use with cdda2wav. All values that
are valid for cdda2wav are valid here.
Defaults to /dev/cdrom
This script uses cdda2wav, cddb and various encoders to rip an audio CD."
ready=$"done"
# level 1 messages
getCDInfoMsg=$"getting cd info..."
outputDirMsg=$"output to: \$encodingDir"
createXmlMsg=$"create xml file..."
startRipMsg1=$"start ripping cd audio data..."
# level 2 messages
encodeMp3Msg=$"Encode to mp3"
encodeFlacMsg=$"Encode to flac"
encodeOggMsg=$"Encode to ogg"
encodeWavMsg=$"Encode to wav"
startRipMsg2=$"start ripping cd audio data:"
cdInfoMsg=$"DISK:
=====
Tracks: \$dTracks
Length: \$dLength
Index: \$dIndex
Artist: \$dArtist
Title: \$dTitle
Year: \$dYear
Genre: \$dGenre
CDDB: \$cddbId
Text: \$dText
Extra: \$dExtra
TRACKS:
======="
# --------------------------------------------------------------
# --------------------------------------------------------------
# Optionen auswerten (im Moment nur angabe einer alternativen
# Konfigurationsdatei, und vebose). Vorher default-werte setzen.
# Irgendwie hab ich noch Probleme mit -? das scheint nicht zu funzen.
$GETOPT -T >/dev/null 2>&1
if [ $? -eq 4 ]
then
# enhanced getopt
usage="${enhUsage}"
TEMP="`$GETOPT -o "?hv::qt:p:e:c:I:D:" -l "help,encoding:,encoder:,path:,interface:,device:" -- "$@"`"
else
# old getopt
TEMP="`$GETOPT "?hv::qt:p:e:c:I:D:" "$@"`"
fi
test $? -ne 0 && { echo -e "${usage}"; exit 1; } # on error
eval set -- "$TEMP" # set $1,$2,...
taOrder="t"
encodingDir=$HOME
encodingType="f"
encoder="lame"
cddbEntry=1
cddaIf=""
cddaDev="/dev/cdrom"
verbose=1
while true
do
case "$1" in
--)
shift; break;;
-v)
# v has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
if [ -z "$2" ]
then
verbose=2
shift 2
else
case "$2" in
v) verbose=3; shift 2;;
*) verbose="$2"; shift 2;;
esac
fi
;;
-q)
verbose=0
;;
-t|--encoding)
if [ "$2" != "m" -a "$2" != "f" -a \
"$2" != "o" -a "$2" != "w" ]
then
echo -e "$usage"
exit 1
fi
encodingType=$2
;;
-p|--path)
if [ ! \( -d $2 \) ]
then
echo -e "$usage"
exit 1
fi
encodingDir=$2
;;
-e|--encoder)
if [ -z $2 ]
then
echo -e "$usage"
exit 1
fi
encoder=$2
;;
-c)
if [ $2 -lt 1 ]
then
echo -e "$usage"
exit 1
fi
cddbEntry=$2
;;
-I)
if [ "$2" != "generic_scsi" -a \
"$2" != "cooked_ioctl" ]
then
echo -e "$usage"
exit 1
fi
cddaIf=$2
;;
-D)
if [ $2 -lt 1 ]
then
echo -e "$usage"
exit 1
fi
cddaDev=$2
;;
-h|--help|*)
echo "${usage}"
exit 1
;;
esac
done
# --------------------------------------------------------------
if [ -z "${cddaIf}" ]
then
test "${cddaDev%/*}" = "/dev" &&\
cddaIf="cooked_ioctl" ||\
cddaIf="generic_scsi"
fi
# ----------------------------------------------------------------
# ----------------------------------------------------------------
# set encodingDir for used encodingType
case ${encodingType} in
m)
encodingDir="$encodingDir/mp3"
test ${verbose} -ge 2 && echo ${encodeMp3Msg}
;;
f)
encodingDir="$encodingDir/flac"
test ${verbose} -ge 2 && echo ${encodeFlacMsg}
;;
o)
encodingDir="$encodingDir/ogg"
test ${verbose} -ge 2 && echo ${encodeOggMsg}
;;
w)
encodingDir="$encodingDir/wav"
test ${verbose} -ge 2 && echo ${encodeWavMsg}
;;
esac
# ----------------------------------------------------------------
test ${verbose} -ge 1 && echo -n ${getCDInfoMsg}
getCDInfo # gets all info about the CD. Look in shellUtils for more info.
test ${verbose} -ge 1 && echo ${ready}
if [ ${verbose} -ge 2 ]
then
cat <<-EOF
$cdInfoMsg
EOF
i=0
while [ $i -lt ${#tTitle[@]} ]
do
echo -n "${tArtist[$i]} - ${tTitle[$i]} "
echo "([${tStartSec[$i]}-${tEndSec[$i]}] ${tLength[$i]})"
i=$((i+1))
done
fi
encodingDir="${encodingDir}/${dArtist}/${dTitle}"
mkdir -p "${encodingDir}"
test ${verbose} -ge 1 && eval "echo ${outputDirMsg}"
# ----------------------------------------------------------------
# fill xml file with data
test ${verbose} -ge 1 && echo -n "${createXmlMsg}"
xmlFile="${encodingDir}/cdinfo.xml"
xml_dText="`echo "${dText}" | recode utf8..h0`"
xml_dExtra="`echo "${dExtra}" | recode utf8..h0`"
xml_dArtist="`echo "${dArtist}" | recode utf8..h0`"
xml_dTitle="`echo "${dTitle}" | recode utf8..h0`"
cat >"${xmlFile}" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cdInfo SYSTEM \"cdInfo.dtd\">
<cdinfo>
<cdindex>${dIndex}</cdindex>
<cddb>${cddbId}</cddb>
<cd-text>${xml_dText}</cd-text>
<cd-extra>${xml_dExtra}</cd-extra>
<cd-artist>${xml_dArtist}</cd-artist>
<cd-title>${xml_dTitle}</cd-title>
<cd-year>${dYear}</cd-year>
<cd-genre>${dGenre}</cd-genre>
<cd-time>${dLength}</cd-time>
<cd-tracks>${dTracks}</cd-tracks>
<cd-comment></cd-comment>
EOF
i=0
while [ $i -lt ${#tTitle[@]} ]
do
trackNr="`printf %02d $((i+1))`"
xml_tTitle="`echo ${tTitle[$i]} | recode utf8..h0`"
xml_tArtist="`echo ${tArtist[$i]} | recode utf8..h0`"
trackEnd=${tEndSec[$i]}
trackStart=${tStartSec[$i]}
trackLen=$((trackEnd-$trackStart))
cat >>"${xmlFile}" <<EOF
<track>
<track-number>$trackNr</track-number>
<track-time>${tLength[$i]}</track-time>
<track-start-sector>${tStartSec[$i]}</track-start-sector>
<track-length>${trackLen}</track-length>
<track-artist>$xml_tArtist</track-artist>
<track-title>$xml_tTitle</track-title>
<track-comment></track-comment>
</track>
EOF
i=$((i+1))
done
echo "</cdinfo>" >>"${xmlFile}"
test ${verbose} -ge 1 && echo "${ready}"
# ----------------------------------------------------------------
# ----------------------------------------------------------------
# now do the ripping
test ${verbose} -eq 1 && echo -n "${startRipMsg1}"
test ${verbose} -ge 2 && echo "${startRipMsg2}"
i=0
while [ $i -lt ${#tTitle[@]} ]
do
trackNr=$((i+1))
# now that i don't forget it again. I use tr to translate \r to \n
# because sed does't recognise a line with only \r at its end as a line.
# Therefor sed reads until output of cdda2wav ends and does all the
# processing at once, so the percentage is not shown correctly
if [ ${verbose} -ge 2 ]
then
outStream="/dev/stdout"
else
outStream="/dev/null"
fi
case ${encodingType} in
f)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.flac"
outStr="track-$trackNr => ${outFile}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
flac -c -f \
-T artist="${tArtist[$i]}" -T album="${dTitle}" \
-T genre="${dGenre}" -T title="${tTitle[$i]}" \
-T tracknumber="${trackNr}" -T tracknum="${trackNr}" \
-T date="${dYear}" -T comment="" \
-o "${encodingDir}/${outFile}" - #2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
m)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.mp3"
outStr="track-$trackNr => ${outFile}: "
case ${encoder} in
lame)
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
lame -V2 \
--ta "${tArtist[$i]}" --tl "${dTitle}" \
--tg "${dGenre}" --tt "${tTitle[$i]}" \
--tn "${trackNr}" --ty "${dYear}" \
--tc "" \
- "${encodingDir}/${outFile}" 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
bladeenc)
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
bladeenc -progress=0 STDIN \
"${encodingDir}/${outFile}" 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
esac
;;
o)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.ogg"
outStr="track-$trackNr => ${outFile}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
oggenc -a "${tArtist[$i]}" -l "${dTitle}" \
-G "${dGenre}" -t "${tTitle[$i]}" \
-N "${trackNr}" -d "${dYear}" \
-c "" \
-o "${encodingDir}/${outFile}" - 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
w)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.wav"
outStr="track-$trackNr => ${outFile}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - >\
"${encodingDir}/${outFile}"
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
esac
test ${verbose} -ge 2 && echo # do a newline after each file
i=$((i+1))
done
test ${verbose} -eq 1 && echo "${ready}"
# ----------------------------------------------------------------