Massid3lib (Mass id3 v1.1 Tag library)
by John George K. xeonfusion@users.sourceforge.net (C) 2001
Project Page : http://sourceforge.net/projects/massid3lib/
Massid3lib is an open source library coded in Visual C++ 6.0 & MFC.
It was written for both practical as well as for demonstration purposes, as to how one could use MFC & C++ to write selected one or more id3v1.1 tags.
First something about Id3 v1.0 specifications:
ID3 Tag standard = 128 bytes of text divided into 6 fields which can be added on end of MP3 file. This standard was created by NamkraD in 1996.
ID3 Tag begins on position -128 bytes from end of file. If there is an ID3 Tag identifier - "TAG" on position 0, then the ID3 Tag is already appended. Next fields carry data:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Now the structure of id3v1.1 tags:
ID3v1 may well be easy to implement for programmers, but it sure is frustrating for those with their own, creative ideas. Since the ID3v1 tag had a fixed size and no space marked "Reserved for future use", there isn't really room for that much improvement, if you want to maintain compatibility with existing software.
One who found a way out was Michael Mutschler who made a quite clever improvement on ID3v1. Since all non-filled fields must be padded with zeroed bytes its a good assumption that all ID3v1 readers will stop reading the field when they encounter a zeroed byte. If the second last byte of a field is zeroed and the last one isn't we have an extra byte to fill with information. As the comments field is to short to write anything useful in the ID3v1.1 standard declares that this field should be 28 characters, that the next byte always should be zero and that the last byte before the genre byte should contain which track on the CD this music comes from
So the id3v1.1 tag fields would be like this:
Tag Field |
Data |
Offset (from end of mp3) |
TAG |
3 characters |
-128 to -126 |
Song title |
30 characters |
-125 to -96 |
Artist |
30 characters |
-95 to -66 |
Album |
30 characters |
-65 to -36 |
Year |
4 characters |
-35 to -32 |
Comment |
28 characters |
-31 to -4 |
Null character |
1 byte |
-3 |
Track |
1 byte |
-2 |
Genre |
1 byte |
-1 |
How to use this library:
The library is designed such that various id3v1.1 tag fields are written by functions of the main class as independent modules. This means that one could design an interface which allows the user to enter one or more tag fields and set a large number of mp3s to the same tags. For example I would like to change all the comment tags of a batch of mp3s to a blank field with no comments or some other comment. Doing this with other libraries would overwrite not only the comment tags but also other fields. So the user disables all other boxes except the comment box in the user interface of the program and a call is made to the writeComment Tag( ) of the library.
Making the calls:
I would assume that you have already designed a function that gets all the file paths of the mp3s (with or without recursion of subdirectories).
First of all, call the prepareTag () before any write operations, this function checks the mp3 to see if from the offset -128 to -126 of the mp3 contains "TAG" , if it does then the file is closed else the file is written with "TAG" at that location and padded with 125 bytes of null character, then only can the individual tag writing functions seek to the apprpriate locations. If this step is not done and an mp3 doesn't contain a tag space then the function will rewind into the offset of audio data! which we certainly wouldn't like to happen.
The functions of the libraries receive two arguments each:
Note: this seems to be a common mistake, there should be no limitation placed on the character array length in the argument the function receives, because for example even though artist tag can hold 30 characters we may type in a string of 8 characters and pass it to the function. This will cause the function to output an error because it expects 30 characters every time. Also note that when writing strings the write member function will stop at the null termination at the end of string, this means it won't write our 8 characters and 21 nulls!! So passing variable length arrays is a work around this.
Example of a call:
if (m_Commentchk.GetCheck() == 1)
{
if (LPCTSTR(m_commentdata) == NULL)
{
char* nocommentdata = "nocomment";
massid3lib().writeCommentTag(LPCTSTR(m_FileFind->GetFilePath()), nocommentdata);
}
else
{
massid3lib().writeCommentTag(LPCTSTR(m_FileFind->GetFilePath()), LPCTSTR (m_commentdata));
}
}
Another example:
if (m_Trackchk.GetCheck() == 1)
{
massid3lib().writeTrackTag(LPCTSTR(m_FileFind->GetFilePath()), int(m_trackdata));
}
Note that an attempt to pass a null pointer (when a blank field data is sent as argument to the function) will cause the library to malfunction and may even cause loss of the tag data, so please be careful and send the parameters as above and all will work well. Of course this is an early release and more error trapping routines will have to be added.