Converting FLAC to MP3

I ran into a little issue with a bunch of FLAC audio files. Portable audio players generally can't play the FLAC audio format and I needed to get some of these files into a format that I could use on an iPod. FLAC is a great audio format. It is a lossless algorithm, which makes for outstanding audio, but the files are still quite large. A Variable Bit Rate (VBR) MP3 file is a compromise between better sounding audio and a much smaller file.

But, when faced with a bunch of FLAC files to convert, I couldn't help but think that there had to be an easier way to convert the files rather than type in the same command on the command-line over and over for each file. Fortunately the idea popped into my head to just write a program to do it because it would be quicker to type in a program than to deal with the command-line over and over.

Well, I don't know if it was any quicker, but it didn't take too long, and now I have a program that I can use in the future. Plus, it's easily modifiable to do many other things. The code is below and a short discussion below that.

Dir.glob(Dir.pwd() + "/*.flac") do |filename|
if File.stat(filename).directory?
p "#{filename} is a directory"
else
p "converting #{filename}"
bb = IO.popen("flac -sdc #{filename} | lame -V 0 --vbr-new -q 0 -b 32 -F -B 320 - #{filename}.mp3", "r+")
b = bb.readlines
puts b.join
end
end

Put all of the code into a file and run with the Ruby interpreter from the directory that contains the files you want to convert. At least, that's the way it's written. If the glob pattern is modified it can find files differently.

If you take out the directory check (which is for the most part unnecessary) the program is 6 lines long. It starts out with calling the glob() method on the Dir object. Glob is great. It lets you pattern search for files. Here I'm asking it to find everything in the current directory that has an extension of "flac". It's setup to accept a block to which it sends one argument, the filename found. So, for each file name that matches the pattern it will call the code block. I do a quick check to be sure we got a file and not a directory. Then I perform the conversion using IO.popen(). Now, I could have used the backtick (`command`) operator to run the command, but it's my understanding that by using IO.popen(), Ruby will actually fork off a subprocess to run the command. Presumably I could run multiple conversions concurrently, although lame seemed to use both of my processor cores to perform the conversion anyway which would make running multiple concurrent conversions kind of silly. IO.popen() returns an IO object to which both the standard out and error are connected. Calling readlines() on the IO object returns an array of all of the output. Then I print the contents of the array using b.join() to see the output of the command.

The command itself uses flac to open the FLAC format audio file that we're globbing over, then pipes the output to lame to perform the MP3 encoding. The command is setup to create the highest quality VBR MP3 it can using bit-rates between 32 and 320 kbps.

Quick and easy. Also general purpose. This kind of structure can be used to invoke anything over a list of files based upon whatever glob pattern you would want to use.

Back to Main Page