0% found this document useful (0 votes)
7 views

Do Anything With ID3

Uploaded by

Bruno Voltz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Do Anything With ID3

Uploaded by

Bruno Voltz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

CodeProject: Do Anything With ID3.

Free source code and programming help Page 1 sur 10

Languages » C# » General C# 2.0, C#, Windows, .NET, .NET 2.0,


WinForms, VS2005, VS, Dev

Do Anything With ID3 Posted : 6 Mar 2007


By Hamed_ji Updated : 22 Mar 2007
Views : 49,198
A class for read and write ID3

36 votes for this Article.


Popularity: 7.58 Rating: 4.87 out of 5 1 2 3 4 5

z Download ID3 Class - 195.3 KB


z Download ID3 Editor - 466.9 KB
z Download Setup - 581.8 KB
z Download FrameID - 15.9 KB

Introduction

ID3 is additional information that attaches to mp3 files. This information can be: text, files, images,
lyrics and much more.

ID3 Editor – Text information dialog

ID3Info is a class that allows you to manage ID3 of files. My article is about this class.

To learn how ID3 works in detail, look at The ID3 Homepage. This is the best place to help you
understand the details of ID3. In this article I won't explain the details of ID3. I'll just explain the basics
of ID3 and how the ID3Info class works.

This class can Read/Write both versions of ID3: ID3v1 and ID3v2. For ID3v2 minor versions this class
can read ID3v2.2, ID3v2.3, ID3v2.4 and can write ID3v2.3 and ID3v2.4.

The most popular version of ID3 is 2.3.0 and version 1.

In this article my focus is more on ID3v2 because there are too many other good references for ID3v1.

To understand how this class works you need to know some basics. Classes, inheritance, and some

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 2 sur 10

useful .NET classes (like ArrayList, FileStream, MemoryStream, etc.).

I wrote an application with ID3Info. This application doesn't use more than 60% of ID3Info's power. I
just wrote the application to find bugs. In my opinion it's not complete. I will try to make it better using
my own time and other user's ideas.

I'll just explain some basics here.

ID3v1

ID3 Editor – General Dialog

ID3v1 usage is so simple. The last 128 bytes of file may contain ID3v1 information. It starts with 'TAG',
this is ID3v1 identifier. 'TAG' keyword will follow with Title (30 character), Artist (30 Character), Album
(30 Character), Year (4 Character), Comment (28 character), Track Number (1 byte) and Genre (1
byte).

Genre has a table within ID3 definition. All softwares must use that table. ID3Info returns Genre
number not Genre name.

As you can see, there's nothing complex in ID3v1.

ID3v1 class, in ID3.ID3v1Frames namespace handles ID3v1 jobs.

private string _FilePath;


private string _Title;
private string _Artist;
private string _Album;
private string _Year;
private string _Comment;
private byte _TrackNumber;
private byte _Genre;

The variables in this class hold ID3v1 data. There are some properties for each variable and they check
the limitations of ID3v1. For example, _Comment does not allow comments to be more than 28
characters.

There's another variable that allows the ID3Info class to know if the current file must contain ID3v1.
This variable name is _HaveTag.

In the constructor, set the _FilePath variable to the path of the file. If the programmer wanted to
load ID3v1 data in the constructor (With LoadData argument), otherwise load sets information to "".

Loading ID3v1

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 3 sur 10

To load ID3v1 you must use the 'Load()' method. This method first defines a FileStream to a file and
tries to find out if the file contains ID3 data. The HaveID3 method determines if file contains ID3v1.
And if the file contains ID3v1, HaveID3 tries to load it.

For reading text, I have used the 'Frame.ReadText' method. This method just reads text from a
specified FileStream, according to TextEncoding and the maximum available length.

public void Load()


{
FileStream FS = new FileStream(_FilePath, FileMode.Open);
if (!HaveID3(FS))
{
FS.Close();
_HaveTag = false;
return;
}
_Title = Frame.ReadText(FS, 30, TextEncodings.Ascii);
FS.Seek(-95, SeekOrigin.End);
//…

FS.Seek(-2, SeekOrigin.End);
_TrackNumber = Convert.ToByte(FS.ReadByte());
_Genre = Convert.ToByte(FS.ReadByte());
FS.Close();
_HaveTag = true;
}

Saving ID3v1

To save ID3v1 we first need to understand if the file currently has ID3. To do so use the 'HaveID3
(FilesStream)' function. If the file currently contains ID3 and the user wants to remove ID3 we just
delete it. If the file currently doesn't contain ID3 and the user wants to save info we just write ID3 at
the end of the file. If you want to change ID3 information you must overwrite it.

GetTagBytes is a property that converts ID3 information to a byte array.

public void Save()


{
FileStream fs = new FileStream(_FilePath, FileMode.Open);
bool HTag = HaveID3(fs);
if (HTag && !_HaveTag) // just delete ID3

fs.SetLength(fs.Length - 128);
else if (!HTag && _HaveTag)
{
fs.Seek(0, SeekOrigin.End);
fs.Write(GetTagBytes, 0, 128);
}
else if (HTag && _HaveTag)
{
fs.Seek(-128, SeekOrigin.End);
fs.Write(GetTagBytes, 0, 128);
}
fs.Close();
}

An Mp3 file with ID3 looks something like this figure:

ID3v2

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 4 sur 10

ID3v2 saves at the beginning of the file. It saves as frames. Each frame contains some information, for
example, one contains artist, another, title of song. A frame also contains: release date, composer,
pictures related to track, track number and much more information.

Each frame contains two main parts:

1. Frame header: contains a FrameID that indicates what this frame contains. For example, if a
FrameID is 'TIT2', this means this frame contains "title of song". Frame header also contains
some flags, and length of frame in byte. For more information about ID3 frames look at The ID3
Homepage.
2. Frame data: contains data of that frame. Each frame has its own structure to store data.

I have classified ID3 frames into 25 classes. All of them inherit the 'Frame' class

ID3v2 minor versions

ID3v2 has some minor versions which have small differences. The main difference is in version 2.2. In
this version, FrameID is three characters, but in later versions it increased to four characters. And in
v2.2 frame headers don't contain a frame flag. Many frames have been added to v2.3 and some added
to v2.4. The most popular version is v2.3.

Frame Class

In 'Main.cs' the file is 'Frame' class. This is the main class used for ID3 frames. As you can see, this is
an abstract class (must be inherited in Visual Basic) because for any frame there's another class that
inherits this class. Some of the most important things are done in this class.

In this class we have some abstract properties and methods.

z IsAvailable: Indicates if current information is valid for this frame.


z FrameStream: Get a MemoryStream that contains data from frame to save.
z Length: Indicates how many bytes this frame needs to save.

These two properties and one method must override all inherited classes. This class also contains some
static methods that are used to read/write data from/to FileStream.

When we want to save a frame first we need to save frame header. The FrameHeader method creates
a MemoryStream and writes the frame header to it. This method will be used in inherited frames to
write their own data after the frame header.

ID3v2 class

This class reads and writes ID3v2. In the constructor you indicate the file path and must determine
whether to load its data or not.

To load data you can use the filter option.

Filter: You can indicate class by opening some special frames. Imagine you have a player application
and you want load the ID3 of a file. In your application you just view "Title of song". So why should you
load all frames? This makes the application slower and uses more RAM to store useless information.

You can add 'TIT2' to Filter. And set FilterType to LoadFiltersOnly to load the Title of track if it
exists. You must always remember: if you use filtering, don't save file info because you might lose
some data.

The Load method checks if file has ID3 (HaveID3 method). If the file has ID3, then Load starts
reading frames. But first, version information must be read with the ReadVersion(FileStream)
method. This method stores version information in the _Ver variable which is available with
'VersionInfo' properties. Then with 'ReadFrames' all frames are read.

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 5 sur 10

public void Load()


{
FileStream ID3File = new FileStream(_FilePath, FileMode.Open);
if (!HaveID3(ID3File)) // If file doesn't contain ID3v2 exit function

{
_HaveTag = false;
ID3File.Close();
return;
}
ReadVersion(ID3File); // Read ID3v2 version

_Flags = (ID3v2Flags)ID3File.ReadByte();
// Extended Header Must Read Here

ReadFrames(ID3File, ReadSize(ID3File));
ID3File.Close();
_HaveTag = true;
}

Read Frames method

Note: FrameID in ID3v2.2 is three characters but in later versions it's four characters.

private void ReadFrames(FileStream Data, int Length)


{
string FrameID;
int FrameLength;
FrameFlags Flags = new FrameFlags();
byte Buf;
// If ID3v2 is ID3v2.2 FrameID, FrameLength of Frames is 3 byte

// otherwise it's 4 character

int FrameIDLen = VersionInfo.Minor == 2 ? 3 : 4;


// Minimum frame size is 10 because frame header is 10 byte

while (Length > 10)


{
// check for padding( 00 bytes )

Buf = Frame.ReadByte(Data);
if (Buf == 0)
{
Length--;
continue;
}
// if read byte is not zero. it must read as FrameID

Data.Seek(-1, SeekOrigin.Current);
// ---------- Read Frame Header -----------------------

FrameID = Frame.ReadText(Data, FrameIDLen, TextEncodings.Ascii);


if (FrameIDLen == 3)
FrameID = FramesList.Get4CharID(FrameID);
FrameLength = Convert.ToInt32(Frame.Read(Data, FrameIDLen));
if (FrameIDLen == 4)
Flags = (FrameFlags)Frame.Read(Data, 2);
else
Flags = 0; // must set to default flag

long Position = Data.Position;


if (Length > 0x10000000)
throw (new FileLoadException("This file contain frame that
have more than 256MB data"));
bool Added = false;
if (IsAddable(FrameID)) // Check if frame is not filter

Added = AddFrame(Data, FrameID, FrameLength, Flags);


if (!Added)
{
// if don't read this frame

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 6 sur 10

// we must go forward to read next frame

Data.Position = Position + FrameLength;


}
Length -= FrameLength + 10;
}
}

How are frames stored in this class?

As you can see 'ReadFrames' reads frame header and 'AddFrame' method tries to load the content of
the frame. The 'AddFrame' method first checks if the frame is a text frame.

Text frames are frames that contain text only. For example: title, artist, album, etc.. All text frame
FrameIDs start with 'T'; you can see a list of text frames in ID3 documentation. If it was not a text
frame, a switch statement is used to try to find out what kind of frame it is.

ID3 Editor – Files Dialog

As I mentioned before there are about 25 classes to store frames. You can find these classes in the
'Frame classes' directory. Switch statement uses FrameID to select the "true" class. For example, if
FrameID is 'APIC'.

AttachedPictureFrame TempAttachedPictureFrame = new AttachedPictureFrame(


FrameID, Flags, Data, Length);
if (TempAttachedPictureFrame.IsReadableFrame)
{
_AttachedPictureFrames.Add(TempAttachedPictureFrame);
return true;
}
else
AddError(new ID3Error(TempAttachedPictureFrame.ErrorMessage, FrameID));
break;

As you can see I've created 'AttachedPictureFrame'. This class inherits the Frame class and reads
information from the attached picture from a frame. After creating an attached picture with
'IsReadable', properties check if frames data is readable. If data is readable
'AttachedPictureFrame' tries to add this attached picture to an attached picture array.

Note: you can store more than one piece of information in some frames. For example, in some frames

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 7 sur 10

you can save as many pictures as you want. But for other frames this is not possible. In the Relative
volume frame, for example, the ID3v2 class just contains a variable for that frame. (To better
understand frames that can hold additional information look at references).

Errors

If you look more closely at AttachedPicture's code you'll see the else statement contains an
'AddError' method. If for any reason the Frame class (that AttachedPictureFrame inherited) can't
read the data of the frame, IsReadable properties will return false. This means an error occurred while
reading, so the program will add an error message to the array of errors.

Why error collection and no exception

Adding errors to a collection allows the program to load other frames that have no error. If, when error
occurred program throw exception other later frames will not read.

Remember you can clear the Error list, and must do it when required.

Frame Equality

As I have said many times, for each type of frame we have a special class. Imagine for an mp3 file, we
start reading frames. We find a frame with a 'TIT2' FrameID. And then find another frame with a 'TIT2'
FrameID. Can we have two frames with a 'TIT2' FrameID? The answer is no. We must overwrite the
first frame with the second one. It means if we find two frames with one FrameID that they must not
be repeated (though some FrameIDs can repeat) - we must store the last one.

For each frame class there's an Equal method. It's an inherited method from the object class. To
explain the Equal method I will use the 'TextFrame' class as an example. As you can see, the
'TextFrame' class equality overrides as below ('TextFrames.cs').

public override bool Equals(object obj)


{
if (obj.GetType() != this.GetType())
return false;
// if FrameID of two text frames were equal they are equal

// ( the text value is not important )

if (this._FrameID == ((TextFrame)obj)._FrameID)
return true;
else
return false;
}

In this method I have checked if the FrameID of the current frame class is Equal to another one. They
are equal. The text of frame is not important. This is because for text frames we must not have more
than one frames with the same FrameID.

The usage of this override is in the 'ArrayList' class. When we want to add new Frames to the list we
can simply remove the previous one with 'ArrayList.Remove' (because this method uses the
'Object.Equal' method).

So always remember frame equality means no two frames have exactly same data.

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 8 sur 10

ID3 Editor – Lyric Editor Dialog

Using ID3Info

In this part I explain how to use the ID3Info class. I have used the ID3Info class in the 'ID3 editor'
application. To see samples of how you can use ID3Info, you can take a look at the 'ID3 Editor' source
code.

How to load ID3Info

To load data you can use constructor.

ID3Info File = new ID3Info("Path", true);

Or

ID3Info File = new ID3Info("Path", false);


// You can use filter here

// ID3File.ID3v2Info.Filter.Add("TIT2");

// ID3File.ID3v2Info.FilterType = FilterTypes.LoadFiltersOnly;

File.Load();

Reading Text information

After defining the ID3Info class and loading data, you need to get data from the class. to get text
information you can use the GetTextFrame method as shown below.

ID3Info File = new ID3Info("Path", true);


String Title = File.ID3v2Info.GetTextFrame("TIT2");
And to set text information you can use 'SetInformation' method, And below.
ID3Info File = new ID3Info("Path", true);
File.ID3v2Info.SetTextFrame("TIT2","My Title", TextEncodings.Ascii,
ID3File.ID3v2Info.VersionInfo.Minor);

Note: For any text you must set a text encoding, and a minor version of ID3v2. This is because these
two parameters are important to text information. In the next version both of them will be automatic.

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 9 sur 10

You can get a list of all text frames related to file from File.ID3v2Info.TextFrames. To get a list of
FrameIDs look at the FrameID table.

Unknown frame

If the application can't find what the FrameID means, it will not delete that. That frame will add to an
unknown frames array (File.ID3v2Info.UnKnownFrames). There is also a boolean property
indicating if you would like to save unknown frames (File.ID3v2Info.DropUnknown).

Load linked frames

Linked frames are information that is attached from another file. For example, you can attach a picture
to one file, and for another file in the same album use a linked frame to add the same picture from that
file. In this way you will save memory and consume less memory, saving data.

Linked frames indicate which FrameID must read from which file. If you set
ID3File.ID3v2Info.LoadLinkedFrames' boolean properties to true the application will
automatically load linked frames while loading data.

Saving

To save data you can call the 'ID3Info.Save()' method. This will save ID3v1 normally and ID3v2 with
a minor version of 3. Or use ID3Info.Save(MinorVersion of ID3v2). And finally, you can use
ID3Info.Save(ID3v2 minor version, Rename string). Rename string is a string that let you
rename a file while saving. In rename string you can use [Title], [Track], [00Track], [000Track],
[Album]. These are case sensitive.

Examples

Load this string "[Title] – [Album]"

ID3Info File = new ID3Info("Path", true);


String MyText = File.ID3v2Info.GetTextFrame("TIT2") + " - " +
File.ID3v2Info.GetTextFrame("TALB");
// Now my text contain Title – Album

Load all attached pictures

using ID3;
using ID3.ID3v2Frames.BinaryFrames

// Code:

ID3Info File = new ID3Info("Path", true);


Image[] ImageArray = new Image[File.ID3v2Info.AttachedPictureFrames.Count];
for(int I = 0; I < File.ID3v2Info.AttachedPictureFrames.Count; i++)
ImageArray[I] = Image.FromStream(
ID3File.ID3v2Info.AttachedPictureFrames.Items[i])
// now ImageArray contain array of images attached to file

Retrieve English unsynchronized lyrics

This method returns English lyrics if they exist.

using ID3;
using ID3.TextFrames;
ID3Info File = new ID3Info("Path", true);
foreach(TextWithLanguageFrame TWL in File.ID3v2Info.TextWithLanguageFrames)
if(TWL.FrameID == "USLT" && TWL.Language == "ENG")
return TWL.Text;

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008


CodeProject: Do Anything With ID3. Free source code and programming help Page 10 sur 10

return null;

For more examples you can look at 'ID3 Editor' source code. If there are problems contact me.

Note: ID3 editor has a help feature you can use to understand how ID3 editor works. And the source
code is available to see how to work with each frame.

In Future

I know parts of the ID3Class application need some changes. It can be more powerful. I will try to
improve both the ID3Info class and ID3 Editor. If you have any ideas about how this application can
be more amazing contact me. Write comments here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the
download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Hamed_ji I like programming because, you can create something that never exist before.
and this is special part of programming.

other special thing about programming is that must of time that you make
program. your program goal is out of computer area. you make math,
accounting or multimedia applications for ex. this is the reason when you
programming you learn somthing about other sciences and this make
programming more nice.
Occupation: Web Developer
Location: Iran, Islamic Republic Of

Discussions and Feedback

94 messages have been posted for this article. Visit


http://www.codeproject.com/KB/cs/Do_Anything_With_ID3.aspx to post and view comments
on this article, or click here to get a print view with messages.

PermaLink | Privacy | Terms of Use Copyright 2007 by Hamed_ji


Last Updated: 22 Mar 2007 Everything else Copyright © CodeProject, 1999-2008
Editor: Sean Ewington Web13 | Advertise on the Code Project

file://E:\Samples\Net 1.1\Multimedia\Audio\Do Anything With ID3\Article.htm 30/05/2008

You might also like