«« Java Signed Bytes and Decoding Flags jid3rL with FramesGroup »»
blog header image
The id3v2 Frames Hierarchy

There are many id3v2 frame types that allow instances of the same type with the same id to exist in a tag. One of the most frequently used is the Comments frame type.

The Comments frame type has the following pieces of information:

- language
- short description
- actual text

The id3v2 spec says that you can have multiple Comments frames as long as they don't have the same language and short description. So you might have a few comments with a different short description, or with the same short description but translated into several languages.

As an aside, WinAmp and iTunes both use a zero length string for the short description of user-entered comments (iTunes likely just followed WinAmp's de facto standard). iTunes also has a few custom comments it puts into files you rip from CD with it. One appears to be a string of combined CDDB lookup numbers, one of which should actually be stored in the Unique File Identifier frame. The other comment appears to be normalization data.

Other id3v2 frame types only let you have one frame of that type with the same id. This is true for the Text Information frame type, which holds values like artist name, album name, track number, etc. You can only have one Text Information frame in a tag with a given frame id.

A good data structure for holding frames is a Java Map. Since each different frame type has frames with a unique id, you map the id to the frame. If the tag doesn't have a frame with that id, the map returns null when you try to get it. But wait, there's a problem ...

Oh yeah, those Comments frames -- they all have the same frame id. If I only used the frame id with the Map, I'd only be able to store one comment at a time. The solution I'm using has maps within maps recursively. Except I wanted it to be a little more arbitrary, so I made a new class I called Hierarchy to abstract this away.

A Hierarchy is a wrapped Map but because it has multiple levels of hierarchy it uses paths instead of keys. The paths are just a List of any types of Object you want, except Hierarchy itself. There are three main methods to this madness:

public Object put(List path, Object o)
public Object get(List path)
public Object remove(List path)

The put method lets you create the hierarchy by stipulating a path. The Object o will be placed at the end of the path. The get method gets an object based on a path. If the path is invalid or no object is found, the method returns null. The remove method will remove the Object at the end of the given path from the Hierarchy and also remove any empty paths this creates.

With my Comments frame example, the path will be:

1. frame id
2. short description
3. language

Text Information frames can be found in the Hierarchy by just using the frame id as the path, since there can only be one with each id per tag.

Posted at August 09, 2004 at 04:29 PM EST
Last updated August 09, 2004 at 04:29 PM EST
Comments


an interesting generic solution. Two questions...

1) How do lists compare in Java? If I have ["eng","music history"], do I need the same instance to the above to compare equal, or will any ["eng","music history"] work?

I had a similar situation at work, whereby an entry was uniquely identified by 2 numbers, not one. So my solution was as follows...

I created a double hashtable, which would take two items and map it to a value.

put(object firstKey, object secondKey, object aValue)

Internally, I created a Pair object and I overwrote the Equals method (in .Net so capital E) so that the internals of DoubleHashtable were simply a hashtable.

Here's my point.

Internally, I wonder if it is worthwhile to have a ValueList - which compares equal if all the values within that list are the same (even thought it may be a different list itself). That way, you simply put your List into a ValueList and internally use a Hashtable (btw, what kind of map are you using?) as normal.

» Posted by: dru at August 25, 2004 10:49 PM

Object comparisons use the equals() method for equality. If you override equals() for a class, you should follow the contract that's specified in the JavaDocs for Object. There are basic rules you have to ensure your implementation of equals() follows.

For Vector, which implements the List interface, it tests of the values are the same not the exact instances.

If you made your own list class and didn't override equals(), then equals() returns false unless they are exactly the same object. This isn't what you'd want, so it's a good idea to always override equals() for data classes.

» Posted by: Ryan at August 25, 2004 11:20 PM
Google
 
Search scope: Web ryanlowe.ca