| View previous topic :: View next topic |
| Author |
Message |
Akkara Administrator


Joined: 28 Mar 2006 Posts: 3715 Location: &akkara
|
Posted: Thu Apr 19, 2007 9:28 am Post subject: [Script] Convert flac to (almost) anything |
|
|
I have been ripping CDs into the lossless flac format to have the original music preserved intact and available to encode to whatever new audio formats become popular as the years go by.
Which raises the question of how to maintain a mirror database of music encoded in whatever format one's portable music player requires - even if the player supports flac, a high bit-rate lossy format might be preferable to fit more music into it, and it would be nice to automatically make mp3's or oggs or whatever as you rip new flacs, and automatically update them as you notice and fix tagging errors.
This script is what I'm currently using to do the job. It is an outgrowth of various ideas and tidbits I had found in these forums along with my own coding to solve these common problems. I'm sharing it here because it might be helpful to someone else, and to return something to the community.
It is a longish script so it'll be put in a followup post. (If there's a better way to make these things available please let me know!)
Requirements
Needs flac, metaflac, lame (only if you want to encode to mp3), faac (only if encoding to aac), oggenc (only if encoding to ogg).
Installation
To install, copy the code in my 2nd post below into a file named /usr/local/bin/flac2any and mark it executable. Then make the following symlinks. As root: | Code: | cd /usr/local/bin
chmod +x flac2any
ln -s flac2any flac2ogg
ln -s flac2any flac2mp3
ln -s flac2any flac2aac |
Use
This script examines its name to know what conversion to perform. (That's why the symlinks when installing it.)
As usual, --help gives a short usage reminder:
To encode a flac file to ogg: This makes file.ogg in the current directory. flac2mp3 and flac2aac works similarly in this and subsequent examples. (Note, however, that flac2aac makes m4a files)
To encode a flac file to ogg but give it a specific name: | Code: | | flac2ogg -o newname.ogg file.flac |
To encode a bunch of flac files and put the ogg files in a new directory: | Code: | | flac2ogg -dir /place/for/ogg/files *.flac |
Adding the -r flag causes it to recursively descend into subdirectories in search for flac files, mirroring the subdirectory structure in the .ogg destination: | Code: | | flac2ogg -r -dir /place/for/ogg/files * | or | Code: | | flac2ogg -r -dir /place/for/ogg/files /main/flac/collection/. |
Giving the -u flag turns on update mode: if the .ogg is already present, it will only re-encode if the .flac file is newer. This is useful when new music is added to your collection or tags changed.
Finally, there's the -n "no, don't do it" flag. It prints out what would be done without actually doing anything. This is good if you just want to see what would be done (like if you use the -u flag, you can see what's been updated since last time).
But -n is also very useful in conjection with this parallel-shell script if you have a multi-core machine, to keep all the cores busy with encoding: | Code: | | time flac2aac -r -n -u --quality 180 -dir /your/aac/mirror /your/flac/files/* | nice -20 parallel-sh -v |
Anyway, here it is. Oh, and I appreciate comments, if you notice a better way to do something, or something I overlooked, please let us know! |
|
| Back to top |
|
 |
Akkara Administrator


Joined: 28 Mar 2006 Posts: 3715 Location: &akkara
|
Posted: Thu Apr 19, 2007 9:29 am Post subject: |
|
|
The script:
| Code: | #!/bin/bash
#-------------------------------------------------------------------------------
# This script converts flac files to mp3, ogg, or aac.
#
# Written by Akkara based on ideas from supermihi and tkdfighter
# Reference: http://forums.gentoo.org/viewtopic-t-314704.html
# http://forums.gentoo.org/viewtopic-p-4016618.html
#
# Known Bugs:
# - If the script is interrupted (ctrl-C) the file being encoded is left
# in a partially-done state. A subsequent invocation with --update
# will incorrectly skip this file, thinking it is current.
#
# - There is no way I know of to put the aac encoder into a 'quiet' mode
# so currently its output is redirected to /dev/null. But that means
# any encoder errors are also not seen.
#
# - mp3 tags only support genre chosen from a small set of official genres.
# If the flac's genre is not in this set, encoding will quietly fail.
# Ideally flac->mp3 should examine the genre and if not in the accepted
# set, map it to something like "Other" before encoding. For future work.
THIS=`basename $0`
# Encoders
OGG="/usr/bin/oggenc"
AAC="/usr/bin/faac"
MP3="/usr/bin/lame"
# flac decoder options:
# -d decode
# -s silent
# -o - send output to stdout
FLACOPTS="-d -s -o -";
FLAC="/usr/bin/flac"
METAFLAC="/usr/bin/metaflac"
# Tags to extract
ALLTAGS="ARTIST ALBUM TITLE DISCNUMBER TRACKNUMBER GENRE YEAR DATE"
# sed expression to enclose its input in single-quotes, surrounding any single
# quotes in the input with double quotes.
QUOTING_EXPR="-e s;';'"'"'"'"'"'"';g -e s;.*;'&';"
QUOTEQUOTES="sed $QUOTING_EXPR"
# Examine this program's name to determine which conversion to perform
#
# Variables are set according to what our encoder expects:
# EXTN is the output file extension
# ENCODE is the encoder command to use.
# ENCOPTS is the options and command-line to pass the encoder.
# A # character tells where to put the tag-setting options.
# A @ character tells where to put the output filename. Due to
# a limitation in the script, # must occur before @.
# TAG_* is the encoder option that sets the named tag.
# TAG_DISK supports two special values for encoding to formats that do
# not have a disc-number tag.
# +TRACK+ indicates that disc-numbers should be combined
# with the track number. For example a flac
# tagged as disc 2 track 3 can be encoded as an
# ogg tagged with track 203
# +ALBUM+ indicates that disc-numbers should be appended
# to the album-name as "(Disc N)". This option
# is necessary when encoding to mp3 because mp3
# has a maximum limit on track numbers of 255,
# which makes the previous option unusable on
# collections of more than two discs.
#
case "$THIS" in
*ogg)
EXTN="ogg"
ENCODE="$OGG"
ENCOPTS="-Q # -o @ -" # -Q quiet
OPT_QUALITY="--quality"
TAG_DISC="+TRACK+"
TAG_TRACK="--tracknum"
TAG_TITLE="--title"
TAG_ALBUM="--album"
TAG_ARTIST="--artist"
TAG_DATE="--date"
TAG_GENRE="--genre"
TAG_COMMENT="--comment"
;;
*aac)
EXTN="m4a"
ENCODE="$AAC"
ENCOPTS="-w # -o @ - 2>/dev/null" # -w wrap AAC data in MP4 container.
OPT_QUALITY="-q"
TAG_DISC="--disc"
TAG_TRACK="--track"
TAG_TITLE="--title"
TAG_ALBUM="--album"
TAG_ARTIST="--artist"
TAG_DATE="--year"
TAG_GENRE="--genre"
TAG_COMMENT="--comment"
# (also supports --writer --compilation --cover-art )
;;
*mp3)
EXTN="mp3"
ENCODE="$MP3"
ENCOPTS="--silent # - @"
OPT_QUALITY="-V"
TAG_DISC="+ALBUM+"
TAG_TRACK="--tn"
TAG_TITLE="--tt"
TAG_ALBUM="--tl"
TAG_ARTIST="--ta"
TAG_DATE="--ty"
TAG_GENRE="--tg"
TAG_COMMENT="--tc"
;;
*)
echo "$THIS: Unknown conversion" >&2
exit 1
;;
esac
if [[ "$1" == "" ]]; then
echo "Usage: $THIS [--help] [--quality Q] [-dir D] [-u] [-r] [-n] file1.flac [file2.flac...]" >&2
exit 0
fi
if [[ ! -x "$ENCODE" ]]; then
echo "$THIS: Encoder $ENCODER is not installed" >&2
exit 2
fi
if [[ ! -x "$FLAC" ]]; then
echo "$THIS: Flac decoder $FLAC is not installed" >&2
exit 2
fi
if [[ ! -x "$METAFLAC" ]]; then
echo "$THIS: Flac tags extractor $METAFLAC is not installed" >&2
exit 2
fi
ENC1="$ENCODE "`echo "$ENCOPTS" | sed 's;\(.*[^ ]\) *# *\(.*[^ ]\) *@ *\(.*\);\1;'`
ENC2=`echo "$ENCOPTS" | sed 's;\(.*[^ ]\) *# *\(.*[^ ]\) *@ *\(.*\);\2;'`
ENC3=`echo "$ENCOPTS" | sed 's;\(.*[^ ]\) *# *\(.*[^ ]\) *@ *\(.*\);\3;'`
UPDATE="false"
DEBUG="false"
DOIT="eval"
VERBOSE="false"
RECURSIVE="false"
RECURSE="$0"
QUALITY=""
DESTFILE=""
DESTDIR=""
MAKE_DESTDIR="false"
SUCCESS="true"
#
# Parse command-line options
#
while :; do case "$1" in
--help)
echo "Usage: `basename $0` [options] file1.flac [file2.flac...]" >&2
echo >&2
echo " Converts audio files from flac format to $EXTN. Resulting file(s) are written" >&2
echo " to the current directory with .$EXTN replacing .flac in the filename." >&2
echo " (** Note: due to technical limitations, any options (especially -o and -odir)" >&2
echo " must be given before the filename(s) to which they apply.)" >&2
echo >&2
echo " Options:" >&2
echo " -o dest Place ogg output in dest."
echo " -dir dest Place output files(s) in directory dest." >&2
echo " -r Recurse into subdirectories." >&2
echo " -n Show what would be done but don't do anything." >&2
echo " -u Rewrite an existing ogg only if the flac file is newer." >&2
echo " -v Verbose. Gives more detail of what's happening." >&2
echo " --quality Q Encode with quality Q (its meaning depends on encoder)" >&2
echo " --encopts O Pass additional options to encoder. Example, -encopts "'"-B 192"'
echo " --help Display this message" >&2
exit 0
;;
-o)
DESTFILE="$2"
shift 2
;;
-dir)
DESTDIR="$2"
if [[ ! -d "$DESTDIR" ]]; then
MAKE_DESTDIR=true
fi
shift 2
;;
-n)
RECURSE="$RECURSE -n"
DOIT="echo"
shift 1
;;
-r)
RECURSE="$RECURSE -r"
RECURSIVE="true"
shift 1
;;
-v)
RECURSE="$RECURSE -v"
VERBOSE="true"
shift 1
;;
--quality)
RECURSE="$RECURSE --quality $2"
QUALITY="$OPT_QUALITY $2"
shift 2
;;
--encopts)
RECURSE="$RECURSE --encopts '$2'"
ENC1="$ENC1 $2"
shift 2
;;
-u)
RECURSE="$RECURSE -u"
UPDATE="true"
shift 1
;;
--debug)
RECURSE="$RECURSE --debug"
DEBUG="true"
VERBOSE="true"
shift 1
;;
"") # No more args - done
break
;;
*)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# process a file
#
IN="$1"
shift 1
OUT="$DESTFILE"
DESTFILE="" # DESTFILE must be unset for subsequent loops
if [[ ! -r "$IN" ]]; then
echo Cannot read "$IN" >&2
SUCCESS=false
elif [[ -d "$IN" ]]; then
if $RECURSIVE; then
NEWDEST=`basename "$IN"`
if [[ "$DESTDIR" != "" ]]; then
NEWDEST="$DESTDIR/$NEWDEST"
fi
$VERBOSE && echo "Entering directory:" "$IN"
$RECURSE -dir "$NEWDEST" "$IN"/* || SUCCESS="false"
$VERBOSE && echo "Leaving directory:" "$IN"
else
echo "Skipping directory:" "$IN" >&2
fi
elif [[ `dd bs=4 count=1 if="$IN" 2>/dev/null` != "fLaC" ]]; then
echo "Skipping non-flac file:" "$IN" >&2
else
if [[ "$OUT" == "" ]]; then
OUT=`basename "$IN" .flac`.$EXTN
fi
if [[ "$DESTDIR" != "" ]]; then
OUT="$DESTDIR/$OUT"
if $MAKE_DESTDIR; then
MAKE_DESTDIR=false
$VERBOSE && echo "Making directory:" "$DESTDIR" >&2
CMD="mkdir -p "`echo "$DESTDIR" | $QUOTEQUOTES`
$DOIT "$CMD"
fi
fi
if [[ "$UPDATE" == "true" && "$IN" -ot "$OUT" ]]; then
$VERBOSE && echo "Destination is newer, skipping:" "$IN" >&2
continue
fi
$VERBOSE && echo "Processing: " "$IN" >&2
# Extract meta-tags. Ensure all variables corresponding to
# tags that are not present get assigned to "". Also wrap the tag
# values in single quotes to prevent script-injection via the eval.
MD5SUM=`metaflac --show-md5sum "$IN" | sed 's;.*:\([0-9a-fA-F]*\)$;\1;'`
for tag in $ALLTAGS ; do
settag=`$METAFLAC --no-utf8-convert --show-tag=$tag "$IN" | \
sed -e "s;^$tag=;;" $QUOTING_EXPR -e "s;^;$tag=;"`
$DEBUG && echo "$settag"
eval "$tag=''"
eval "$settag"
done
if $DEBUG; then
echo "$IN" >&2
echo " Outfile: $OUT" >&2
echo " Tags:" >&2
echo " Artist: $ARTIST" >&2
echo " Album: $ALBUM" >&2
echo " Title: $TITLE" >&2
echo " Disc: $DISCNUMBER" >&2
echo " Track: $TRACKNUMBER" >&2
echo " Genre: $GENRE" >&2
echo " Year: $YEAR" >&2
echo " Date: $DATE" >&2
fi
# Process discnumber for fileformats that don't support that tag
if [[ $DISCNUMBER != "" ]]; then
if [[ "$TAG_DISC" == "+TRACK+" ]]; then
TRACKNUMBER=$DISCNUMBER`echo "000$TRACKNUMBER" | sed 's/0*\(..\)$/\1/'`
DISCNUMBER=""
elif [[ "$TAG_DISC" == "+ALBUM+" ]]; then
ALBUM="$ALBUM (Disc $DISCNUMBER)"
DISCNUMBER=""
fi
fi
# Assemble tag options.
TAGS=""
if [[ $ARTIST != "" ]]; then
TAGS="$TAGS $TAG_ARTIST "`echo $ARTIST | $QUOTEQUOTES`
fi
if [[ $ALBUM != "" ]]; then
TAGS="$TAGS $TAG_ALBUM "`echo $ALBUM | $QUOTEQUOTES`
fi
if [[ $DISCNUMBER != "" ]]; then
TAGS="$TAGS $TAG_DISC "`echo $DISCNUMBER | $QUOTEQUOTES`
fi
if [[ $TRACKNUMBER != "" ]]; then
TAGS="$TAGS $TAG_TRACK "`echo $TRACKNUMBER | $QUOTEQUOTES`
fi
if [[ $TITLE != "" ]]; then
TAGS="$TAGS $TAG_TITLE "`echo $TITLE | $QUOTEQUOTES`
fi
# Some flacs are tagged with DATE, others with YEAR. Pick one.
if [[ $DATE != "" ]]; then
TAGS="$TAGS $TAG_DATE "`echo $DATE | $QUOTEQUOTES`
elif [[ $YEAR != "" ]]; then
TAGS="$TAGS $TAG_DATE "`echo $YEAR | $QUOTEQUOTES`
fi
if [[ $GENRE != "" ]]; then
TAGS="$TAGS $TAG_GENRE "`echo $GENRE | $QUOTEQUOTES`
fi
if [[ $COMMENT != "" ]]; then
TAGS="$TAGS $TAG_COMMENT "`echo $COMMENT | $QUOTEQUOTES`
fi
$DEBUG && echo " Tagline: $TAGS" >&2
QUOTE_IN=`echo "$IN" | $QUOTEQUOTES`
QUOTE_OUT=`echo "$OUT" | $QUOTEQUOTES`
$DOIT "$FLAC $FLACOPTS $QUOTE_IN | $ENC1 $QUALITY $TAGS $ENC2 $QUOTE_OUT $ENC3" || SUCCESS="false"
fi
#
# end process a file
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;;
esac done
$SUCCESS
exit $? |
|
|
| Back to top |
|
 |
faceman Apprentice


Joined: 10 Jan 2005 Posts: 200 Location: inter terram et caelo
|
Posted: Thu May 03, 2007 4:17 pm Post subject: |
|
|
If you use mp3s, you could also use mp3fs. _________________ www.impressusart.com |
|
| Back to top |
|
 |
PraetorZero Apprentice


Joined: 11 Dec 2004 Posts: 236 Location: /home
|
Posted: Sat Jun 02, 2007 1:42 am Post subject: |
|
|
| Perhaps this should be moved to Tips & Tricks? Awesome script, I've been using it when adding files to my wife's ipod via gtkpod. |
|
| Back to top |
|
 |
Dirk.R.Gently Guru


Joined: 29 Jan 2007 Posts: 546 Location: Titan
|
Posted: Tue Aug 21, 2007 11:51 pm Post subject: |
|
|
Tips and Tricks sure. I think this needs to be in portage! Freakin' awesome! To an average lay person, I tried to convert flac to ogg, how does this convert, using oggenc? I tried previously to use oggenc without success:
| Code: | | oggenc in.flac -q 6 -o out.ogg |
and got:
| Code: | | ERROR: Input file "in.flac" is not a supported format |
Actually this is a bit strange, I've seen it work on other sites, but with your script it works. Also it could be useful to name the dependencies in your script, i.e. vorbis-tools... _________________ • Helpful Linux Tidbits |
|
| Back to top |
|
 |
.brum n00b

Joined: 02 Sep 2007 Posts: 1
|
Posted: Sun Sep 02, 2007 3:56 pm Post subject: Re: [Script] Convert flac to (almost) anything |
|
|
Hi,
Thank you for sharing this with us, it is appreciated. I have tried the script to convert to aac and gotten it basically to work as it should. There are, however, two questions:
(1) The resulting m4a -files seem not to have a track number at all. When running the script with -v -n switches, tracknumber does not show up. I verified that the FLACs do have a track number, and that they've converted correctly when previously using Foobar2000. Any idea what I could check?
(2) This script uses the faac encoder, but as far as I understand, Nero Digital's encoder is supposed to produce better audio quality. Previously one needed to use the windows version via wine, but now there's a native Linux version. I tried just changing the encoder reference, and got the script to pass the information to neroAacEnc, but then came errors complaining about the tag data being unknown parameters. Perhaps the windows version via wine would work, but uinfortunately I'm not good enough with scripting. Any thoughts?
Rgds,
.brum |
|
| Back to top |
|
 |
nuke n00b


Joined: 14 Sep 2003 Posts: 30
|
Posted: Sun Dec 09, 2007 8:31 pm Post subject: |
|
|
Nifty script, and written very maintainably. Thanks!
I did find that the regex you provide resulted in one more level of quoting than was necessary, and I've also got a few pathologically tagged files, so I modified it slightly:
| Code: |
--- flac2any 2007/12/09 19:27:40 1.1
+++ flac2any 2007/12/09 20:13:54
@@ -44,7 +44,7 @@ ALLTAGS="ARTIST ALBUM TITLE DISCNUMBER T
# sed expression to enclose its input in single-quotes, surrounding any single
# quotes in the input with double quotes.
-QUOTING_EXPR="-e s;';'"'"'"'"'"'"';g -e s;.*;'&';"
+QUOTING_EXPR="-e s;^'\(.*\)'$;\1; -e s;';'"'"'"'"'"'"';g -e s;\`;; -e s;.*;'&';"
QUOTEQUOTES="sed $QUOTING_EXPR"
|
|
|
| Back to top |
|
 |
Zucca Apprentice


Joined: 14 Jun 2007 Posts: 201 Location: Helsinki, Finland
|
Posted: Wed Feb 11, 2009 3:28 pm Post subject: |
|
|
| Dirk.R.Gently wrote: | Tips and Tricks sure. I think this needs to be in portage! Freakin' awesome! To an average lay person, I tried to convert flac to ogg, how does this convert, using oggenc? I tried previously to use oggenc without success:
| Code: | | oggenc in.flac -q 6 -o out.ogg |
and got:
| Code: | | ERROR: Input file "in.flac" is not a supported format |
Actually this is a bit strange, I've seen it work on other sites, but with your script it works. Also it could be useful to name the dependencies in your script, i.e. vorbis-tools... | Try piping: flac <opts> | oggenc <opts>
(I haven't read oggenc man pages, so I'm not sure if this works.)
Also ffmpeg could do the thing... _________________ Threading support for your bash scripts. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|