Tuesday, May 29, 2007

mp3, iTunes, standards and taglib

I have a somewhat large mp3 collection. And, specially since I got my iPod, I really like it all to be organized, correctly tagged, with Album covers, all of that. I use iTunes to manage my collection and perform all these annoying tasks, specially because it's supposed be trustworthy and compatible with the iPod. The problem is I work mostly on Linux, so whenever I'd come to the lab and rip a few songs from my iPod to listen on Amarok most covers would get messed up. It would recognize correctly about half the cover and just gray out the rest. Weird, right? Specially because it worked perfect on the iPod. So I grabbed pytagger, which I'd hacked around a bit because of another tag-related problem I'd had before, to try and find out what was going on. I ended up with this little script to extract the cover art from .mp3 files (it creates an AlbumArt.jpg file on the dir of the mp3 file, note that it doesn't replace the AlbumArt.jpg file if it exists!!!). And they got extracted just perfectly well. But the AlbumArt.jpg files weren't enough because, even though Amarok would recognize them as the album cover, it would still use the messed up version when specific songs were being played. Damn!!! So I dug a little deeper to find the problem: taglib was reading the wrong size for the image. That's why it would read only half of the image or so. The id3v2 2.4 specs say that the size should be written using synchsafe integers (with the most-significant bit always set to zero), and taglib abides to that. Apparently, iTunes doesn't (and neither does pytagger)!!! So, all my mp3's (that have id3v2 2.4 tags) aren't compliant with the standard. Thanks a lot iTunes! Since I wasn't about to retag ~6000 mp3 files, or risk not being compatible with my iPod, I hacked taglib to do the wrong thing and act like iTunes. Find the file /taglib/mpeg/id3v2/id3v2frame.cpp, in the taglib source dir and change the line

d->frameSize = SynchData::toUInt(data.mid(4, 4));

to


if (d->frameID=="APIC")
d->frameSize = data.mid(4, 4).toUInt();
else
d->frameSize = SynchData::toUInt(data.mid(4, 4));



It's a horrible hack, but I'll have to live with it until something changes (either iTunes gets fixed, or I downgrade all my songs to id3v2 2.3 or 2.2, which would probably be the best solution). Hope this actually helps anyone facing the same problems I was.

1 comment:

Anonymous said...

We should develop a Picard-like software.