Ticket #27 (closed defect: fixed)

Opened 6 years ago

Last modified 6 years ago

The Problem with Mp3Info

Reported by: tobi Owned by:
Priority: normal Milestone: Release 1.2
Keywords: Cc: maksim_lin@…

Description (last modified by tobi) (diff)

Besides the general suggestions (1, 2) to use a more up-to-date Java library the current code obviously cannot read ID3v2 tags at all which unfortunately is exactly what most modern music players (e.g. iTunes) are writing in an MP3 file.

I've added two MP3 test files, one containing ID3v1, the other ID3v2 tags only. The unit test fails as soon as the ID3v2 file is being read and processed.

I suggest we replace the Java library and rewrite the module code in one of the next releases. I'll add Michi and Maksim as CC recipients as both hinted to the ancient Uberdosis library. Maybe they would be willing to help us improving the module by contributing their knowledge and/or code.

Here's a list of MP3/ID3 implementations in Java including the ones used by Maksim and Michi:

Attachments

MP3.java (10.1 kB) - added by maksim_lin@… 6 years ago.
Simple Javawrapper for ID3 v2.3 tag read/write

Change History

  Changed 6 years ago by maksim_lin@…

Hi, I have code using the library from http://javamusictag.sourceforge.net/ and also using 1 class (de.vdheide.mp3.MP3Properties) only for gettting the duration of an MP3 file which is pulled out of the distribution of the chaptertool app (http://id3v2-chap-tool.sourceforge.net/).

The Java code itself is a very simple wrapper for easy access in JS to the underlying java libs. It provides reading/writing for those ID3v 2.4 tags that we are interested but can be trivially extended to any other tags.

I'd be very happy to have this code adopted into Jala and am open to license requirements, namespace changes, etc. We are using this in our podcasting app backend and have tested the written tags in iTunes and WinAmp?.

I'l attach the code in a followup.

Please note that I only need to use the MP3Properties class for our podcasting app to get mp3 file duration which the javamusictag lib does not provide, but maybe we can just pull that file into here directly (its licensed under LGPL so not sure if that makes it possible or not...)

Maks.

Changed 6 years ago by maksim_lin@…

Simple Javawrapper for ID3 v2.3 tag read/write

  Changed 6 years ago by tobi

Thanks a lot, Maksim.

As far as I am able to review Java your code is looking good. However, for Jala we should stick to providing JavaScript code – which isn't a big deal because it would be quite easy to transform your MP3 class into an equivalent JavaScript constructor. If you agree this change shouldn't be an issue for your podcast code, either; I think all you would (and of course, should) need to do is to update your constructor call.

I consider writing ID3 tags a very welcome extension of the current code. Nevertheless, we need backwards-compatibility for our own applications. Too bad the org.farng.mp3 package does not provide necessary data like duration. It also appears to be a little dated (last activity around March 2006 although "still in beta being about 75% completed").

As we are ready for an overhaul of jala.Mp3Info, anyway, I suggest we should use an up-to-date package and avoid adding extra JARs.

Looking around for a more comprehensive Java package, I noticed that Michi's choice (just like ours) somehow disappeared or moved elsewhere.

Here's a list of MP3/ID3 implementations in Java including the ones used by Maksim:

Maksim if you are (or anyone else is) interested in taking a closer look at the alternatives just drop a comment here.

follow-up: ↓ 4   Changed 6 years ago by robert

Afais MP3SPI is still existing (just the link you set in your comment is wrong, it contains a "]" at the end), however it doesn't seem to be alive very much (last update 30.Nov.2005).

In general, i second your opinion to stick with JavaScript as far as possible, and try to avoid additional .jar files (besides the one necessary). I didn't look through all your links, but at first glimpse JAudioTagger looks quite good to me.

in reply to: ↑ 3   Changed 6 years ago by tobi

  • description modified (diff)

Replying to robert:

Afais MP3SPI is still existing (just the link you set in your comment is wrong, it contains a "]" at the end)

Apologies for my mistake. I copied the link from the Helma mailing-list archive; that's where the trailing bracket came from. I'll add the updated list of implementations to the description.

I didn't look through all your links, but at first glimpse JAudioTagger looks quite good to me.

Yes, was my first impression, too.

  Changed 6 years ago by Manfred

Hi.

I've just found out the following:

Sun, 04 Mar 2007 00:21:55 GMT Entagged is unmaintained

So this project ist dead 4 the moment, i think.

  Changed 6 years ago by tobi

  • milestone set to Release 1.3

Scheduled for release 1.3, unless someone provides the code quickly.

  Changed 6 years ago by stefanp

I've put together an updated summary of my library evaluation from last fall.

The short summary:

  • No library does it all.
  • Mp3info (the library currently in use) will be necessary for parsing correct file durations as all other libraries fail with VBR files.
  • With such a number of libaries at hand and no clear favorite, I'd suggest we create our own javascript API that is completely independent of the underlying java library. This way we might switch libraries in the future without breaking apps.

The options are:

  • JAudioTagger if the priority is a library undergoing active development, including other tags coming up the future.
  • JavaMusicTag if we want the status quo of id3 text and image tags to be handled easily.
  • Mp3info if we want the status quo of id3 text tags to be handled easily.

The evaluation

  • Basics on ID3 tags (all versions): http://www.id3.org/ (Introduction & Developer Information are worth a read)

what was tested

  • read/write id3v1 (artist, title, year and genre)
  • read/write id3v2 (artist, title, year and genre)
  • add new id3v2 tags, plus speed when adding
  • handling of different v2 tag versions
  • read/write images to id3v2 tags
  • read file properties (bitrate, frequency, duration, vbr status)
  • read audio length from vbr correctly
  • development activity,
  • documentation
  • license

evaluated libraries

listed in brackets are alternative names or package names that are sometimes used for a library.

  • Mp3info (de.ueberdosis)
    http://sourceforge.net/projects/mp3info/
    • Currently in use in jala.Mp3Info.
    • For text tags, as good as JavaMusicTag.
    • API isn't as clear as JavaMusicTag's and documentation lags behind.
    • No editing of images or advanced tag contents.
    • It's the only library to parse file durations correctly in VBR files.
    • Frozen.
  • JAudioTagger
    https://jaudiotagger.dev.java.net/
    • Branched from javamusictag#.
    • Designed to handle any kind of tags for any kind of audio format, not just mp3 and id3.
    • API requires a bit of knowledge of id3v2 tags and frames.
    • Still seems a bit buggy.
    • The only choice for editing more advanced tags and images.
  • javalibrarymp3 (java_mp3, vdheide, Vonderheide)
    http://www.vdheide.de/java_mp3/
    • Ok for reading, buggy when writing tags.
    • Does images but not advanced tags.
    • BBC's Chaptertool is based on this library (see class bbc.rd.id3.ID3Util).
    • Frozen.

  • jd3lib
    http://sourceforge.net/projects/jd3lib/
    No closer look taken: There aren't any docs and the API isn't clear at all on the first glance. The source code exists in different versions from 2002 and 2005. The project seems to be unmaintained since 2005.

evaluation table

Mp3info JavaMusicTag JAudioTagger javalibrarymp3 entagged mp3spi
read id3v1 tag functions (1) functions functions functions functions functions
read id3v2 tag frame-level functions frame-level functions not transparent functions
write id3v1 tag functions functions functions doesn't work (2) functions -
write id3v2 tag frame-level functions frame-level functions not transparent -
unicode support ok ok ok not transparent not transparent -
add new id3v2 frames to the file frame-level ok doesn't work ok, but not transparent not transparent -
speed when adding new id3v2 tags to reference file ~900ms ~500ms doesn't work ~100ms - -
transparent access to v2.2., v2.3, v2.4 etc. don't bother at read + edit, choose when adding new convenience wrapper, user may go into the details user has to work with frame identifiers, has to choose sub-version when adding new not transparent - -
read images from id3v2 tag frame-level frame-level frame-level function - -
write images to id3v2 tag not available should work, but not tested should work, but not tested should work, but not tested - -
read file properties ok ok, but wrong bitrate for vbr files ok, but wrong bitrate for vbr files ok, but wrong bitrate for vbr files - -
identify vbr files correctly implicit only ok ok not supported - ok
read audio length from vbr files correctly ok, but parsing may take some time wrong result wrong result wrong result wrong result -
last development activity march 2005, appears to be frozen march 2006, no activity since march 2007 december 2004 "feb 2006, ""unmaintained""" november 2005
documentation inline only, but ok tutorial & api docs are quite good not very much. but mailinglists are active inline only, but intuitive api not very much inline
license LGPL LGPL LGPL LGPL GPL LGPL
remarks access to different tags through different mechanisms clear API difficult API, all operations on v2 tags deal with individual frames buggy with id3v1 tags, sometimes keeps file locks no info on whether id3v1/id3v2 tags are read or written read only library
size of jar file 138 kb 188 kb 331 kb 47 kb 149 kb 24 kb

(1) functions = API provides individual functions like getArtist(), getTitle() etc. frame-level means, one has to access the data using frame identifiers like TIT2, TYER etc.

(2) the library hides IO error messages, so I couldn't find out why the write operation didn't work.

  Changed 6 years ago by maksim_lin@…

Wow, thanks for such a comprehsive survey of all the java id3 libs Stefan! It does clearly show what a mess the current situation with java id3 libs really is. I think your suggestion to define our own seperate JS API and then use whatever java libraries are needed/best is definitely the way to go.

I'm happy to help with creating the JS->Java plumbing code for the API and could start by modifying what I already have (using JavaMusicTag? lib) as 1 possible implementation of the API. Others could then do same thing using other java libs...

Can you or someone (or me) put up a proposed API and we start from there?

I would suggest we dont use id3 frame ids in the API and instead use "symbolic" fields (eg. artist, title, etc), especially if in the future the API is used for other audio file formats metadata (eg. OGG, WMA, AAC) or even video files.

  Changed 6 years ago by stefanp

Here's a proposal for the API of jala.Audio.

  Changed 6 years ago by maksim_lin@…

The above API proposal is excellant. Giving a generic "easy to use" functionality with MP3 object properties and still allowing low-level access to ID3 tags as required is great and also provides a clear way to extend in the future for other file formats.

Stefan which libraries are you planning to use?

Let me know if I can help with code contribution, testing, etc.

  Changed 6 years ago by robert

Stefan, first of all many thanks for for your efforts, including this proposal and the fabulous library comparison above. In general i'm +1 for the structure of jala.Audio, however i'd like to propose some minor modifications:

  • What irritates me is that jala.Audio.Tag doesn't represent a single tag, but a bundle of tags, i.e. getTag() doesn't return a single tag as i expected, but returns a Tag instance which provides access to all tags of a certain type. Therefor i'd propose to rename jala.Audio.Tag to jala.Audio.TagBundle, and put the according method names of jala.Audio.* into plural form, eg. rename getTag() to getTags(). Same with createTag(), which i'd expect to create a single tag, therefor i'd prefer to call it setTags(), and also rename hasTag() to hasTags() and removeTag() to removeTags(). The singular form would imo be only valid if i could pass a tag name or constant representing a tag field to the methods (which btw. would be quite nice too).
  • MP3 looks like a constant to me, so i'd prefer to name the prototype Mp3. Same with ID3v1/2, i'd rename them to Id3v1/2
  • How about adding two convenience methods getId3v1Tags() and getId3v2Tags() to jala.Audio.Mp3?
  • I didn't test it, but instead of assigning the standard fields as properties you could define getter methods for them, using __defineGetter__ (mind that this needs a recent Helma 1.6 snapshot). This way it's impossible to modify the values of these properties, and it should be easier to update the field values after setting tags using setTags():
    for (var tagName in metadata) {
       this.__defineGetter__(tagName, function() { return metadata[tagName]; });
    }
    

  Changed 6 years ago by stefanp

Hi Robert and Maksim! Thanks for your inputs, I'll go through it backwards:

__defineGetter__ looks great, I've overlooked that js-feature so far. To me the Helma 1.6 requirement wouldn't be a problem and we could put it in a try/catch block so that it doesn't throw an error with older versions.

+1 for the convenience methods.

For renaming the prototypes: Mp3 instead of MP3 is ok with me. You're right that it otherwise would look like a constant. Besides, it would be in line with the previous capitalisation conventions in Jala (Rss, Mp3Info). Still, I'd like to mention that the documents on id3.org always use ID3v1 and ID3v2 (uppercase D) and most of the libraries adhere to that practice.

As for your first point, I'd prefer to stick to the current definition. Even though the term "tag" is a bit ambigious, for mp3 files it is used with the meaning of a container. See the documents on id3.org, e.g. what is ID3v2. The tag itself is a bundle of "tag parts". In v1 such a tag is a fixed block with a fixed space reserved for each tag part, therefore no term for the sub-parts was coined. In v2 the tag consists of frames each representing a tag part. The libraries consistently implement these conventions (AbstractMP3Tag class in JavaMusicTag, org.jaudiotagger.tag-Package). As the term "frame" is useful only for v2 tags, I've tried to avoid it. But in general, I'd expect a method getTags to return an array of both ID3v1 and ID3v2 tag container objects.

@Maksim: By this time, I think JavaMusicTag looks best for our purposes. It's got a clean API, you already know it. For the moment, !JAudioTagger seems a bit too buggy. But as JAudioTagger was branched from JavaMusicTag a switch is still not too difficult, should they ever provide more features.

I'll commit the prototype and method structure to the SVN repository this week, and based on that we can decide who is doing which parts.

  Changed 6 years ago by tobi

Some minor notes just being picky about naming conventions:

  • If jala.Audio is a namespace (which I currently assume) it should be written jala.audio (lowercase A).
  • I don't like getId3v1Tag and getId3v2Tag as method names, they are difficult to write, to remember and to distinguish. Furthermore, they generally appear very technical, not user-friendly. I suggest something more trivial like getV1/getV2Tag() or getTag(version).
  • convert/getSubType() should be written convert/getSubtype() (lowercase T).

  Changed 6 years ago by anonymous

I've worked in most of the suggestions:

  • both, jala.audio and jala.audio.tag are lowercase
  • more convenience methods added to jala.audio.Mp3 (createV1Tag, hasV1Tag, removeV1Tag etc)

The outline of Audio.js is as well as the required library is in the SVN trunk [165].

If you volunteer to take over work on some methods, let me know.

  Changed 6 years ago by stefanp

The completed jala.audio package is in the svn repository, ready to undergo some testing. The wiki proposal has been updated with the minor changes that slipped in during coding.

There still is an issue with adding/reading images, but I'm positive about solving this today.

  Changed 6 years ago by tobi

  • status changed from new to closed
  • resolution set to fixed
  • milestone changed from Release 1.3 to Release 1.2

Replaced by Mp3 prototype.

Note: See TracTickets for help on using tickets.