(Download the script from this article flac2mp3.sh)

When converting FLAC files to MP3, the first problem you will notice is that lame does not support FLAC files. This might now seem like big problem, because you can easily decode FLAC files using the command line tool flac and then use the decoded file with lame.

The Problem

The real problem is that you will loose your metadata in this process, so the tags you added to your FLAC won’t be copied to the MP3 file. While you could “easily” add them by hand, it is pretty annoying to do that even if you only want to convert a handful of files.

The solution

The solution is to extract the metadata from the FLAC file using metaflac and to use the options lame provides to inject the tags into the MP3 file when calling lame.

Note:

This section is merely provided to explain the steps involved. You do not need to read this nor do you need to do this by hand, since I offer you a small script that will do these steps for you (look at the very first line of the article or below under “Download” to download the script).

Step 1 – Extract the Metadata

To extract a single tag, you can use metaflac like this:

metaflac --show-tag=<tag> <file>

To extract the artist of the track from the file named “1 – Let It In.flac”, you could call:

metaflac --show-tag=ARTIST "1 - Let It In.flac"

 

In general you will get a result like this:

<TAG>=<VALUE>

In the mentioned example you might get the following:

ARTIST=Josh Woodward

 Step 2 – Fomat the Metadata

We only need the name of the artist, so we need to get rid of  “ARTIST=”. This can be easily achieved with sed.  The general way of replacing something with sed is this:

sed 's/OLD/NEW/'

OLD is the part that you want to replace and NEW is the part that you want to replace it with. What we want to replace is “ARTIST=” (which is our OLD) and what we want to replace it with is nothing (which will essentially remove OLD), so our NEW is empty. And this is what we get:

sed 's/ARTIST=//'

But that would only work for the ARTIST tag. A general solution would be to remove anything up to and including the equal sign. I won’t go into detail on this one, but this would be achieved by setting OLD to “.*=” and the line would look like this:

sed 's/.*=//'

To make this work, we need to we need to pass the output of metaflac to our sed command, which we would do like this:

metaflac --show-tag=ARTIST "1 - Let It In.flac" | sed 's/.*=//'

This way the output of metaflac (“ARTIST=Josh Woodward”) is send to our sed command, which then removes the “ARTIST=” part and thus we get the output:

Josh Woodward

 

Step 3 – Store the tag

While the line from Step 2 works, it merely prints the tag. What we need to do is to store the tag somehow, so that we can use it again later for adding the tag to the MP3 file. To store the output of a command in a variable, you generally type:

<var>=`<command>`

(Those are not single quotes in this line, but backticks/grave accents) This will execute <command> and then store the output to the variable <var>.

In this example we could do this:

ARTIST=`metaflac –show-tag=ARTIST “1 – Let It In.flac” | sed ‘s/.*=//’`

This would execute out metaflac command and save the output (“Josh Woodward”) in the variable ARTIST.

We can test if everything worked by printing the value of ARTIST:

echo $ARTIST

which should now give us:

Josh Woodward

 

Step 4 – Passing the tags to lame

In general, calling lame (and using VBR mode) would work like this:

lame -V <oldfile> <mp3file>

If you want lame to save metadata to the mp3 file, you can use several options do to this. To continue our example, let’s assume we want to add the name of the artist (that we have stored in the variable ARTIST in the last step) to the new MP3 file. This can be done with the –ta option:

lame -V --ta "$ARTIST" <oldfile> <mp3file>

In a similar way, we can add other tags to the mp3 file as well. Here is a small table that shows you the options lame offers to add metadata, the name of the FLAC tag that theese options correspond to and what they mean.

FLAC tag Lame option Description
TITLE
--tt
The title of the track
ARTIST
--ta
The title artist
ALBUM
--tl
The album name
DATE
--ty
The year of the album
COMMENT
--tc
a comment for this track
TRACKNUMBER, TRACKTOTAL
--tn
The number of the track and the total number of the tracks
GENRE
--tg
the genre of the track

Step 5 – Passing the FLAC to lame

We have not solved the original problem yet: you can not pass a flac file to lame. We could decode the FLAC to WAV and then pass the WAV file to lame, but we don’t need do really create a WAV file, because we can just decode the FLAC and pass the decoded data directly to lame. To do this, we need to call flac with two options:

  • -d to tell it we want to decode a flac file
  • -c, so that the decoded data is not written to a file, but to stdout

Then, we can tell lame that it should read the data from stdin instead of from a file, which can be done by providing a dash for the <oldfile> parameter. Now we can connect them both with a pipe and the decoded flac data will directly flow into our lame command:

flac -c -d <flacfile>| lame - <mp3file>

In our example, we would get something like this (which includes adding the ARTIST tag and a VBR quality of 6):

flac -c -d "1 - Let It In.flac" | lame -V 6 --ta "$ARTIST" - "1 - Let It In.mp3"

Now that the basic  steps involved are covered, we can let a script do the work.

 

 

The Script

I wrote a small script that converts a FLAC file to MP3 while preserving  the following tags (=all the tags listed in “Step 4″ above):

  • Track Title
  • Track Artist
  • Album Title
  • Year
  • Comment
  • Tracknumber
  • Total number of tracks
  • Genre

Download

You can download the script here: flac2mp3.sh

Usage

The script takes three arguments:

  • The VBR quality (This corresponds to the -V option of lame, which means that you can use a number between 0 and 9, with smaller numbers meaning higher quality and bigger files). If you omit this option, -V 4 will be used.
  • The filename of the FLAC file you want to convert
  • The filename of the new MP3 file that you want to create.
  • You can (but don’t have to) add “mtime” as the fourth argument in which case the script will not start the conversion if the MP3 file is newer than the FLAC file, which indicates that a conversion is not necessary. (If you don’t add “mtime”, the script will convert the files no matter what)

Example:

If you want to convert the file “1 – Let It In.flac” to “1 – Let It In.mp3″ with a VBR quality level of 3, you would call the script like this:

flac2mp3.sh 3 "1 - Let It In.flac" "1 - Let It In.mp3"
flac2mp3.sh 3 "1 - Let It In.flac" "1 - Let It In.mp3" mtime

Source

The script generally works as described under “The Solution”, but instead of repeating the line from “Step 3″ for every tag, it uses a more elegant approach (which in this case just means less code). But instead of posting the complete source code (which you can look at by download the script), let me just show you  the meat of the script (extracting the 8 tags and passing them to lame for conversion):

for tag in TITLE ARTIST ALBUM DATE COMMENT TRACKNUMBER TRACKTOTAL GENRE; do
    eval "$tag=\"`metaflac --show-tag=$tag "$FLAC" | sed 's/.*=//'`\""
done

flac -cd "$FLAC" | lame -V "$V" --tt "$TITLE" --ta "$ARTIST" --tl "$ALBUM" --ty "$DATE" --tc "$COMMENT" --tn "$TRACKNUMBER/$TRACKTOTAL" --tg "$GENRE" - "$MP3"

 

Update (2012-06-05)

I have updated the script a little. It’s now possible to append a “mtime” after the three arguments. When adding “mtime”, the script will only start the conversion if the MP3 file does not exist yet or the FLAC file is newer than the MP3 file.

This will avoid unnecessary conversions in case the MP3 is newer than the FLAC file, which indicates it is up-to-date. This is useful when using this script to somehow manage your library as it will reduce a large number of conversions.

  11 Responses to “Converting FLAC to MP3 (including Tags) on command line”

  1. I searched a lot of this information on page metaflac and flac did not find. Thank you.

  2. Hi tordeu,

    nice script you got together there.

    After have been ok for years i recently discovered the tag-chaos associated with my demand of having flac/mp3 synced copies of my library for the usage on iPods/Smartphones.
    I started using the great perl-script from Robin Bowes, see below.
    http://projects.robinbowes.com/flac2mp3

    The fun started when i saw some chaotic displays of my libraries in my favorite audio-player foobar2000 (with ColumnsUI and foovert).
    The fun got even greater once i started comparing foobar, mp3tag, mediainfo and metaflac outputs. To be honest it is kind of driving me nuts, still.
    Not only the mapping between flac and id3v2 tags but also the usage of frames/fields within one format seems chaotic partially. e.g. metaflac reading “Organization” and foobar2000/mp3tag displaying “Publisher”.
    So mainly due to albumartist, tracknumber/tracktotal, discnumber/disctotal issues i started looking around
    alternatives to the perl-script (since i seem to stupid e.g. to figure out how to match tracknumber and tracktotal from the flac-tags to the TRCK frame in id3v2 with it).

    So i stumbled across your shell-script. Besides that i needed to comment out the pipefail and the check of the parameter readings (probably due to bash differences, using ubuntu 11.10 server here) it works well.
    I also have appended more meta-fields as e.g. TPE2/ALBUMARTIST, TPOS, TPUB.
    So far so good.

    What i am missing right now is e.g. one feature from the perl-script, md5sum.
    It is using the md5sum of the flac-tag to decide if a new transcode is necessary or if only the meta-data has changed and only writing tags would suffice if the flac-file is found to be altered since the last run of the script. So far i have no clue how i would do that.

    You see any chance you might be interested in expanding your script in that matter?
    Not need to transcode everything once some tags have changed or i decide to append more meta-fields to be synced to the mp3 copies would be really cool.

    Another thing i have not tried yet with your script is the folder-structure of the library. The perl-script takes a source and destination folder as input and (e.g. /music/flac/ and /music/mp3/) re-creates the sub-structure on its own.
    I know there are ways around that, e.g. using “find” or similar to maybe achieve this. But i was just wondering if your script could do the same itself?

    Best regards
    Bernhard

    • First of all: Sorry for taking so long to reply.

      The feature you mentioned is a great idea. Unfortunately, this script does not support that, because it is/was only intended to convert a single FLAC to mp3 without any additional options.

      I am thinking about additional tools to manage music libraries and automate some tasks. But everybody organizes his/her music differently. The problem with avoiding unnecessary conversions is that using the hash of the tags is not enough. You would have to calculate the hash of the audio data as well, which would still take some time in case the library is big.
      It will work in most real cases, but if it does not, you have no idea why. And calculating the hash of all FLAC files in a large collection still takes some time.

      I will try to work on the script next week or the week after that to improve the situation at least a little bit. I am thinking of adding an option to only convert the FLAC if the FLAC file was changed after the MP3 was created.
      That would not be a perfect solution and still convert way too many audio files, but I think it would still be a big improvement and it won’t be necessary to calculate the hash of every file. I could also add different methods of deciding when to convert at a later time to provide optimized solutions for different cases.

      I still want the script to be very simple in usage, however, which is why I will won’t add library management features and I don’t want it to add its own tags to the mp3s or modify the tags of the FLAC files.

  3. Hi tordeu,

    not a problem at all. I was on vacation for the last week, so your reply felt like “immediate”. :)
    Glad to see you are yourself still interested in evolution.

    As to the issues itself:
    - No necessity to calculate the md5 sums of the flac-audio-part. If i am not mistaken libflac itself does add the md5sum tag to the file during creation. And that is for the audio only, not the meta-data. (metaflac –show-md5sum audio.flac). Actually it is the md5sum of the raw-data which gets encoded to flac. So in means of the actual usage of checksums to recognize data-corruption it is worthless unless you use the same source file again for an encoding (checksum and flac-data should be identical if algorithms are deterministic).
    But anyhow if using the md5sum tag of the flac and transfer it over to the mp3-metadata it should be a valid indicator if these flac files have been transcoded before or not (and could be skipped this time).
    Of course someone who has problems with the actual flac or mp3 encoding itself will not get help from this, but in that case you do have some major issues somewhere else anyways.
    - Calculating the checksum for the flac-meta-part is also not necessary. I think working with file-dates (creation, modification) should suffice to determine if the flac-meta-part has received an update and should be transfered over to the mp3-metadata. Although i have not thought in depth about this one on which cases this could fail (without noticing it).

    You are right about everybody working in different ways and everyone/many has/have a different view on what might be the perfect way to organize things. While it sometimes bugs me i am also glad that this is the case… otherwise many many things would be sooooo boring and no fun at all.
    I am also with you on “simple in usage”. I am not looking for an all-in-one solution, just trying to get together my “tool-chain” to get the result i want and all consumers (smartphone, pc-audio, boxee-box, …) be happy with the “material-source&meta”.
    After all it is your (simple) script and i am glad you are sharing your experiences with the public. With people like you it is way easier to get along and further than if everybody would need to have in-depth readings and studies of man-pages and what not…

    • I started developing a new python script which might eventually “replace” this script and my flac2ogg script as well as hopefully provide additional functionality. Unfortunately I don’t know how long this will take and I am currently pretty much just hacking something together, because I really don’t have a good overview of what might be useful or necessary.
      So my current plan is to release the python script when it’s ready, then add functionality as necessary and then review the script later to see how this all can be done better/more flexible etc.

      The python script is now capable of at least converting flac2mp3 and I want to add flac2ogg and flac2flac support, as well as a possibility for different “conditional” conversions, where the conversion will only take place once specific conditions (like the mtime of the flac is newer as the mtime of the mp3 as well as the idea with the md5 hash) are met.
      I also want to add the possibility to just transfer the tags. I might split this into several scripts and provide a set of scripts for working with audio files, but I don’t really know, yet.

      As a “quick fix” I modified the bash script a little. It is now possible to add “mtime” at the end, if which case the conversion will only take place if the flac file is newer than the mp3 file.
      I hope that this might at least provide some benefit to you and a few others.

  4. Hi tordeu,

    not a problem, take your time.

    Looking forward to what you are coming up with eventually. :)

  5. Thank you very much. An easy way to use your shell script on all the .flac’s in the directory is:

    for i in *.flac ; do /wherever/flac2mp3.sh 3 “$i” “${i%\.flac}.mp3″ mtime ; done

  6. Very useful. Thanks!!

  7. Very useful, thank you! And thanks David for “${i%\.flac}.mp3″ – I tend to end up with file.flac.mp3 because I am to lazy to turn on my brain :)

  8. I began creating another python script which may in the end “swap” this script and my flac2ogg script and additionally surely give extra practicality. Shockingly I don’t know to what extent this will take and I am presently virtually simply hacking something together, on the grounds that I truly don’t have a great outline of what could be convenient or fundamental.
    :

Leave a Reply to rahulanki Cancel reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>