PDA

View Full Version : Flac To MP3 - C#/.NET Version



johnc_22
2006-05-01, 11:21
I needed a way to keep my FLAC and MP3 libraries in synch so I wrote a quick and dirty application to do this. I'm not Perl fluent so it was quicker for me to go this route, believe it or not. It reads the Ogg-vorbis comments out of the FLAC file, decodes the FLAC file back to WAV and them "lames" it to MP3 applying the comments. Most of the lame settings are hard-coded right now and I don't plan on making it a hobby to maintain the thing, but I'll be happy to hand off the source code to someone who'd like to or anyone who's interested in customizing it for their own needs.

There's certainly room for improvement as currently I read the entire FLAC file into a byte array and then scan it for the comments - it would certainly be more efficient to read the file only as much as necessary to get the comments and then quit, but whatever, I just let it run all night. I've converted about 65GB of FLAC to 12GB of MP3 (192kbps) so far but will have to free up some room on my drive before I can go any further. It works well for what I needed and is intelligent enough to ignore files and folders that it finds already existing in the destination tree.

Yes, this is my first post but my Squeezebox (had it about a month) has been so easy to use that I really haven't had any questions I couldn't get answered by searching here.

My Squeezebox rocks - I truly love this device.

John

ianwi
2006-05-01, 14:16
Here's some C# code my friend wrote to read the Vorbis comments. You really just need to read the first 1K of the file.

This is based on the format spec here:
http://flac.sourceforge.net/format.html

public static FlacMetadata ReadComments(Stream flacStream)
{

byte byteBuffer = 0;
byte[] intBuffer = new byte[4];
byte[] textBuffer = new byte[1024];

uint length = 0;
uint count = 0;
string text = "";
bool finished = false;

FlacMetadata metadata = new FlacMetadata();

// check the flac marker (first 4 bytes should
// be ASCII "fLaC"

flacStream.Read(textBuffer, 0, 4);

text = Encoding.ASCII.GetString(textBuffer, 0, 4);

if (text == "fLaC")
{
// read all metadata block headers
while (!finished)
{
byteBuffer = (byte)flacStream.ReadByte();

// first bit is last metadata block marker
finished = ((byteBuffer & 0x80) == 0x80);

// next 7 bits represent block type
byte blockType = (byte)(byteBuffer & 0x7F);

// next 24 bits represent size of metadata block
intBuffer[0] = 0;

flacStream.Read(intBuffer, 1, 3);
length = ToUInt32(intBuffer, true);

switch (blockType)
{

case 0: // STREAMINFO

// <16> The minimum block size (in samples) used in the stream.
// <16> The maximum block size (in samples) used in the stream.
// <24> The minimum frame size (in bytes) used in the stream.
// <24> The maximum frame size (in bytes) used in the stream.
// <20> Sample rate in Hz.
// <3> (number of channels)-1.
// <5> (bits per sample)-1.
// <36> Total samples in stream.
// <128> MD5 signature of the unencoded audio data.

flacStream.Seek(length, SeekOrigin.Current);
break;

case 4: // VORBIS_COMMENT

// http://www.xiph.org/vorbis/doc/v-comment.html
// NOTE: vorbis_comments are encoded little endian

flacStream.Read(intBuffer, 0, 4);
length = ToUInt32(intBuffer, false);
flacStream.Read(textBuffer, 0, (int)length);
text = Encoding.UTF8.GetString(textBuffer, 0, (int)length);
flacStream.Read(intBuffer, 0, 4);

count = ToUInt32(intBuffer, false);

for (int i = 0; i < count; ++i)
{
flacStream.Read(intBuffer, 0, 4);
length = ToUInt32(intBuffer, false);
flacStream.Read(textBuffer, 0, (int)length);
text = Encoding.UTF8.GetString(textBuffer, 0, (int)length);
string[] textParts = text.Split('=');
metadata.Comments.Add(textParts[0], textParts[1]);
}

// the vorbis spec states that a single bit follows
// for framing but these seems to be absent...

break;

/*
case 1: // PADDING
case 2: // APPLICATION
case 3: // SEEKTABLE
case 5: // CUESHEET
*/

case 127: // invalid

finished = true;

break;

default:

// ignore
flacStream.Seek(length, SeekOrigin.Current);
break;

}
}
}
else
{
throw new ArgumentOutOfRangeException("flacStream",
"Passed stream is not a FLAC stream or is not positioned correctly.");
}

return metadata;

}

johnc_22
2006-05-01, 15:13
Cool - thanks!

erland
2006-05-01, 23:04
I'm not sure, but the already existing perl based flac2mp3 utility might work on Windows, I have personally only used it on linux. Anyway thanks for posting the code for your conversion utility.

flac2mp3:
http://robinbowes.com/projects/flac2mp3

johnc_22
2006-05-02, 07:11
I'm not sure, but the already existing perl based flac2mp3 utility might work on Windows, I have personally only used it on linux. Anyway thanks for posting the code for your conversion utility.

flac2mp3:
http://robinbowes.com/projects/flac2mp3

I read that it does work for Win32 provided you are proficient enough in Perl to get it installed and tweak it as needed, but sadly I am not. I use C# every day in my work life and .NET makes it a piece of cake to manipulate files and folders so I just rolled my own.

Anyone that wants the code just PM me.

radish
2006-05-02, 07:13
To be fair, installing perl involves going to activestate.com, downloading the installer and running it. It's no more complex than installing VS2k5. But yes, the more code the better so thanks for sharing.

johnc_22
2006-05-02, 08:57
To be fair, installing perl involves going to activestate.com, downloading the installer and running it. It's no more complex than installing VS2k5. But yes, the more code the better so thanks for sharing.

I got as far as installing activestate but then wasn't really sure how to install the rest of the necessary pieces for doing FLAC, etc even though I did download them . . .

Robin Bowes
2006-05-02, 09:34
johnc_22 wrote:
> radish Wrote:
>> To be fair, installing perl involves going to activestate.com,
>> downloading the installer and running it. It's no more complex than
>> installing VS2k5. But yes, the more code the better so thanks for
>> sharing.
>
> I got as far as installing activestate but then wasn't really sure how
> to install the rest of the necessary pieces for doing FLAC, etc even
> though I did download them . . .

I really *must* get round to writing some docs...

Alas, I'm too busy doing paid work.

R.

sugarmonster
2006-05-04, 11:42
@JohnC: I'd be interested to see how you're reading the FLAC comments. I've been working on an album art downloader in C# (more as an exercise in 2.0 than anything else). The bit-twiddling needed to decode the comments was doing my head in so I ended up porting the relevant parts of the java FLAC library on Sourceforge over to C#!

Can you PM / email me?

(BTW if anyone's interested the java lib will compile in J# with minimal changes but it doesn't play nicely with C# when you do that)

Cheers,

Marc.

zooropa320
2006-05-04, 11:51
Nothing wrong with the code route but I would also suggest Foobar2000 to transcode from flac to mp3. I've used it with the -aps flag to create great sounding vbr mp3s to play on my ipod. The Foobar UI and array of features can be daunting initially but there are plenty of guides to get you started.

johnc_22
2006-05-04, 13:58
@JohnC: I'd be interested to see how you're reading the FLAC comments. I've been working on an album art downloader in C# (more as an exercise in 2.0 than anything else). The bit-twiddling needed to decode the comments was doing my head in so I ended up porting the relevant parts of the java FLAC library on Sourceforge over to C#!

Can you PM / email me?

(BTW if anyone's interested the java lib will compile in J# with minimal changes but it doesn't play nicely with C# when you do that)

Cheers,

Marc.

There's more efficient code than mine posted above in this thread to do just what you need. I've emailed you a zip of my source though.

johnc_22
2006-05-04, 13:59
Nothing wrong with the code route but I would also suggest Foobar2000 to transcode from flac to mp3. I've used it with the -aps flag to create great sounding vbr mp3s to play on my ipod. The Foobar UI and array of features can be daunting initially but there are plenty of guides to get you started.

I guess I didn't really RTFM very well on Foobar2000 because it was not obvious from the UI that you could do this . . . oh well. Hey, I enjoyed the mini-project anyway.