Forums

Skip to content

Advanced search
  • Quick links
    • Unanswered topics
    • Active topics
    • Search
  • FAQ
  • Login
  • Register
  • Board index Assistance Multimedia
  • Search

[Script] Convert flac to (almost) anything

Help with creation, editing, or playback of sounds, images, or video. Amarok, audacious, mplayer, grip, cdparanoia and anything else that makes a sound or plays a video.
Post Reply
Advanced search
8 posts • Page 1 of 1
Author
Message
Akkara
Bodhisattva
Bodhisattva
User avatar
Posts: 6702
Joined: Tue Mar 28, 2006 12:27 pm
Location: &akkara

[Script] Convert flac to (almost) anything

  • Quote

Post by Akkara » Thu Apr 19, 2007 9:28 am

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: Select all

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:

Code: Select all

flac2ogg --help
To encode a flac file to ogg:

Code: Select all

flac2ogg file.flac
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: Select all

flac2ogg -o newname.ogg file.flac
To encode a bunch of flac files and put the ogg files in a new directory:

Code: Select all

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: Select all

flac2ogg -r -dir /place/for/ogg/files *
or

Code: Select all

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: Select all

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!
Top
Akkara
Bodhisattva
Bodhisattva
User avatar
Posts: 6702
Joined: Tue Mar 28, 2006 12:27 pm
Location: &akkara

  • Quote

Post by Akkara » Thu Apr 19, 2007 9:29 am

The script:

Code: Select all

#!/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 $?
Top
faceman
Apprentice
Apprentice
User avatar
Posts: 200
Joined: Mon Jan 10, 2005 9:09 pm
Location: inter terram et caelo
Contact:
Contact faceman
Website

  • Quote

Post by faceman » Thu May 03, 2007 4:17 pm

If you use mp3s, you could also use mp3fs.
www.impressusart.com
Top
PraetorZero
Apprentice
Apprentice
User avatar
Posts: 239
Joined: Sat Dec 11, 2004 4:18 am
Location: /home

  • Quote

Post by PraetorZero » Sat Jun 02, 2007 1:42 am

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.
Top
Dirk.R.Gently
Guru
Guru
User avatar
Posts: 546
Joined: Mon Jan 29, 2007 1:56 am
Location: Titan
Contact:
Contact Dirk.R.Gently
Website

  • Quote

Post by Dirk.R.Gently » Tue Aug 21, 2007 11:51 pm

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: Select all

oggenc in.flac -q 6 -o out.ogg
and got:

Code: Select all

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
Top
.brum
n00b
n00b
Posts: 1
Joined: Sun Sep 02, 2007 3:28 pm

Re: [Script] Convert flac to (almost) anything

  • Quote

Post by .brum » Sun Sep 02, 2007 3:56 pm

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
Top
nuke
n00b
n00b
User avatar
Posts: 30
Joined: Sun Sep 14, 2003 1:48 am

  • Quote

Post by nuke » Sun Dec 09, 2007 8:31 pm

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: Select all

--- 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"                                                                                                    
                                                                                                                                    
                                                                                                                                    
Top
Zucca
Administrator
Administrator
User avatar
Posts: 4698
Joined: Thu Jun 14, 2007 10:31 pm
Location: Rasi, Finland
Contact:
Contact Zucca
Website

  • Quote

Post by Zucca » Wed Feb 11, 2009 3:28 pm

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: Select all

oggenc in.flac -q 6 -o out.ogg
and got:

Code: Select all

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...
..: Zucca :..

Code: Select all

init=/sbin/openrc-init
-systemd -logind -elogind seatd
I am NaN! I am a man!
Top
Post Reply

8 posts • Page 1 of 1

Return to “Multimedia”

Jump to
  • Assistance
  • ↳   News & Announcements
  • ↳   Frequently Asked Questions
  • ↳   Installing Gentoo
  • ↳   Multimedia
  • ↳   Desktop Environments
  • ↳   Networking & Security
  • ↳   Kernel & Hardware
  • ↳   Portage & Programming
  • ↳   Gamers & Players
  • ↳   Other Things Gentoo
  • ↳   Unsupported Software
  • Discussion & Documentation
  • ↳   Documentation, Tips & Tricks
  • ↳   Gentoo Chat
  • ↳   Gentoo Forums Feedback
  • ↳   Duplicate Threads
  • International Gentoo Users
  • ↳   中文 (Chinese)
  • ↳   Dutch
  • ↳   Finnish
  • ↳   French
  • ↳   Deutsches Forum (German)
  • ↳   Diskussionsforum
  • ↳   Deutsche Dokumentation
  • ↳   Greek
  • ↳   Forum italiano (Italian)
  • ↳   Forum di discussione italiano
  • ↳   Risorse italiane (documentazione e tools)
  • ↳   Polskie forum (Polish)
  • ↳   Instalacja i sprzęt
  • ↳   Polish OTW
  • ↳   Portuguese
  • ↳   Documentação, Ferramentas e Dicas
  • ↳   Russian
  • ↳   Scandinavian
  • ↳   Spanish
  • ↳   Other Languages
  • Architectures & Platforms
  • ↳   Gentoo on ARM
  • ↳   Gentoo on PPC
  • ↳   Gentoo on Sparc
  • ↳   Gentoo on Alternative Architectures
  • ↳   Gentoo on AMD64
  • ↳   Gentoo for Mac OS X (Portage for Mac OS X)
  • Board index
  • All times are UTC
  • Delete cookies

© 2001–2026 Gentoo Foundation, Inc.

Powered by phpBB® Forum Software © phpBB Limited

Privacy Policy

 

 

magic