This tutorial will quickly get you up and running with id3lib.
First, id3lib must be a part of your development environment. The latest files can always be downloaded from the id3lib homepage.
To use the basic functionality of id3lib in your C++ code, a single #include
is necessary.
#include <id3/tag.h>
There are other files that must be included to access more advanced functionality, but this will do most of the core functionality.
Almost all functionality occurs via an ID3_Tag object. An ID3_Tag object basically encapsulates two things: a collection of ID3_Frame objects and file information. The goal is to populate an ID3_Tag object with ID3_Frame objects, and the easiest way to do this is to associate the tag with a file. This is done primarily via the ID3_Tag constructor, like so:
ID3_Tag myTag("song.mp3");
This constructor links, or associates, the object myTag
with the file "song.mp3". In doing so, the tagging information from "song.mp3" is parsed and added to myTag
. This association can also be accomplished by creating an empty tag and making an explicit call to Link().
The default behavior of Link() is to parse all possible tagging information and convert it into ID3v2 frames. The tagging information parsed can be limited to a particular type (or types) of tag by passing an ID3_TagType (or combination of ID3_TagTypes). For example, to read only the ID3v1 tag, pass in the constant ID3TT_ID3V1.
myTag.Link("song.mp3", ID3TT_ID3V1);
Another example would be to read in all tags that could possibly appear at the end of the file.
myTag.Link("song.mp3", ID3TT_ID3V1 | ID3TT_LYRICS3V2 | ID3TT_MUSICMATCH);
After linking with a file, the object myTag
now contains some or all of the tagging information present in the file "song.mp3", represented as ID3v2 frames. How can that information be accessed? There are a variety of ways to do this. One is to iterate through all the frames in the tag.
// use an std::auto_ptr here to handle object cleanup automatically ID3_Tag::Iterator* iter = myTag.CreateIterator(); ID3_Frame* myFrame = NULL; while (NULL != (myFrame = iter->GetNext())) { // do something with myFrame } delete iter;
Another way to access tagging information is by searching for specific frames using the Find() method. For example, the album frame can be found in the following manner:
ID3_Frame* myFrame = myTag.Find(ID3FID_ALBUM); if (NULL != myFrame) { // do something with myFrame }
The Find() method can be used to search for frames with specific information. For example, the following code can be used to find the frame with the title "Nirvana".
ID3_Frame* myFrame = myTag.Find(ID3FID_TITLE, ID3FN_TEXT, "Nirvana"))); if (NULL != myFrame) { // do something with myFrame }
As indicated, the Find() method will return a NULL pointer if no such frame can be found. If more than one frame meets the search criteria, subsequent calls to Find() with the same parameters will return the other matching frames. The Find() method is guaranteed to return all matching frames before it wraps around to return the first matching frame.
All ID3_Frame objects are comprised of a collection of ID3_Field objects. These fields can represent text, numbers, or binary data. As with frames, fields can be accessed in a variety of manners. The fields of a frame can be iterated over in much the same manner of the frames of a tag.
// use an std::auto_ptr here to handle object cleanup automatically ID3_Frame::Iterator* iter = myFrame->CreateIterator(); ID3_Field* myField = NULL; while (NULL != (myField = iter->GetNext()) { // do something with myField } delete iter;
If you know which field type you're looking for, you can access it directly.
ID3_Field* myField = myFrame->GetField(ID3FN_TEXT); while (NULL != myField) { // do something with myField }
Note: The ID3_FrameInfo class provides information about the frame types known to id3lib.
The ID3_Field represents a single piece of data within an ID3v2 frame. As mentioned, an ID3_Field can represent three possible types of data: integers, binary data, and text strings. The type of a particular field object is immutable; it is determined at the time of its construction (almost always when a frame is constructed) and can't be changed. If in doubt, the field type can be accessed through its GetType() method.
Having an ID3_Field object isn't much use if you cannot access and/or alter its data. Luckily, the id3lib API provides overloaded Set
and Get
methods for all data types.
If the field is an integer, the following methods can be used to access the data.
All text data is accessed in a slightly different manner. The following code example best illustrates these differences.
// for ascii strings char str1[1024]; const char* p1 = "My String"; const char* p2 = "My Other String"; myField->Set(p1); (*myField) = p2; // equivalent to Set myField->Get(str1, 1024); // copies up to 1024 bytes of the field data into str1 p1 = myField->GetRawText(); // returns a pointer to the internal string
Binary data is similar to text data, except that its base type is a pointer to an unsigned, rather than a signed, char.
// for binary strings uchar data[1024]; const uchar *p1 = getBinaryData(); // not an id3lib function size_t size = getBinarySize(); // not an id3lib function myField->Set(p1, size); myField->Get(data, 1024); // copies up to 1024 bytes of the field data into str1 p1 = myField->GetRawBinary(); // returns a pointer to the internal string
When you're ready to save your changes back to the file, a single call to Update() is sufficient.
tag.Update();