首页  编辑  

mp3 ID3标签信息

Tags: /超级猛料/Multi-Media.多媒体相关/   Date Created:

严黎斌

unit ID3Kernel;

interface

type

 Tid3v1= record

   Tag: array[0..2] of char;      //00..02 , ='TAG'

   Title:array[0..$1d] of char;  //03..20

   Artist:array[0..$1d] of char;  //21..3e

   Album:array[0..$1d] of char;  //3f..5c

   Year:array[0..3] of char;      //5d..60

   Comment:array[0..$1c] of char; //61..7d

   Track:byte;                    //7e

   Genre:byte;                    //7f

 end;

function ReadID3v1(strFile:string;var pid3v1:Tid3v1):integer;

function WriteID3v1(strFile:string;var pid3v1:Tid3v1):integer;

function DeleteID3v1(strFile:string):integer;

implementation

function ReadID3v1(strFile:string;var pid3v1:Tid3v1):integer;

var

 f1:file of byte;

 bytAll: array [0..$7f] of byte;

 i: integer;

begin

 result:=1;

 if strFile='' then exit;

 AssignFile(f1,strFile);

 FileMode:=0;

 Reset(f1);

 if FileSize(f1)<=$80 then exit;

 Seek(f1, FileSize(f1)-$80);

 for i:=0 to $7f do Read(f1,bytAll[i]);

 if (bytAll[0]<>ord('T')) and (bytAll[1]<>ord('A'))

   and (bytAll[2]<>ord('G')) then exit; // no 'TAG' found

 Move(bytAll,pid3v1,$80);

 CloseFile(f1);

 result:=0;

end;

function WriteID3v1(strFile:string;var pid3v1:Tid3v1):integer;

var

 f1:file of byte;

 bytAll: array [0..$7f] of byte;

 i: integer;

begin

 result:=1;

 AssignFile(f1,strFile);

 FileMode:=2;

 Reset(f1);

 if FileSize(f1)<=$80 then exit;

 Seek(f1, FileSize(f1)-$80);

 for i:=0 to $2 do Read(f1,bytAll[i]); // test if 'TAG' exists

 if (bytAll[0]=ord('T')) and (bytAll[1]=ord('A'))

       and (bytAll[2]=ord('G'))

   then Seek(f1,FileSize(f1)-$80)

   else Seek(f1,FileSize(f1));

 Move(pid3v1,bytAll,$80);

 for i:=0 to $7f do Write(f1,bytAll[i]);

 CloseFile(f1);

 result:=0;

end;

function DeleteID3v1(strFile:string):integer;

var

 f1:file of byte;

 bytAll: array [0..$7f] of byte;

 i: integer;

begin

 Result:=1;

 AssignFile(f1,strFile);

 FileMode:=2;

 Reset(f1);

 if FileSize(f1)<=$80 then exit;

 Seek(f1, FileSize(f1)-$80);

 for i:=0 to $2 do Read(f1,bytAll[i]); // test if 'TAG' exists

 if (bytAll[0]=ord('T')) and (bytAll[1]=ord('A'))

       and (bytAll[2]=ord('G'))

   then begin

     Seek(f1,FileSize(f1)-$80);

     Truncate(f1)

   end;

 CloseFile(f1);

 Result:=0;

end;

end.

***********************************************

{

 Byte 1-3 = ID 'TAG'

 Byte 4-33 = Titel / Title

 Byte 34-63 = Artist

 Byte 64-93 = Album

 Byte 94-97 = Jahr / Year

 Byte 98-127 = Kommentar / Comment

 Byte 128 = Genre

}

type

 TID3Tag = record

   ID: string[3];

   Titel: string[30];

   Artist: string[30];

   Album: string[30];

   Year: string[4];

   Comment: string[30];

   Genre: Byte;

 end;

const

Genres : array[0..146] of string =

   ('Blues','Classic Rock','Country','Dance','Disco','Funk','Grunge',

   'Hip- Hop','Jazz','Metal','New Age','Oldies','Other','Pop','R&B',

   'Rap','Reggae','Rock','Techno','Industrial','Alternative','Ska',

   'Death Metal','Pranks','Soundtrack','Euro-Techno','Ambient',

   'Trip-Hop','Vocal','Jazz+Funk','Fusion','Trance','Classical',

   'Instrumental','Acid','House','Game','Sound Clip','Gospel','Noise',

   'Alternative Rock','Bass','Punk','Space','Meditative','Instrumental Pop',

   'Instrumental Rock','Ethnic','Gothic','Darkwave','Techno-Industrial','Electronic',

   'Pop-Folk','Eurodance','Dream','Southern Rock','Comedy','Cult','Gangsta',

   'Top 40','Christian Rap','Pop/Funk','Jungle','Native US','Cabaret','New Wave',

   'Psychadelic','Rave','Showtunes','Trailer','Lo-Fi','Tribal','Acid Punk',

   'Acid Jazz','Polka','Retro','Musical','Rock & Roll','Hard Rock','Folk',

   'Folk-Rock','National Folk','Swing','Fast Fusion','Bebob','Latin','Revival',

   'Celtic','Bluegrass','Avantgarde','Gothic Rock','Progressive Rock',

   'Psychedelic Rock','Symphonic Rock','Slow Rock','Big Band','Chorus',

   'Easy Listening','Acoustic','Humour','Speech','Chanson','Opera',

   'Chamber Music','Sonata','Symphony','Booty Bass','Primus','Porn Groove',

   'Satire','Slow Jam','Club','Tango','Samba','Folklore','Ballad',

   'Power Ballad','Rhytmic Soul','Freestyle','Duet','Punk Rock','Drum Solo',

   'Acapella','Euro-House','Dance Hall','Goa','Drum & Bass','Club-House',

   'Hardcore','Terror','Indie','BritPop','Negerpunk','Polsk Punk','Beat',

   'Christian Gangsta','Heavy Metal','Black Metal','Crossover','Contemporary C',

   'Christian Rock','Merengue','Salsa','Thrash Metal','Anime','JPop','SynthPop');

var

 Form1: TForm1;

implementation

{$R *.dfm}

function readID3Tag(FileName: string): TID3Tag;

var

 FS: TFileStream;

 Buffer: array [1..128] of Char;

begin

 FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);

 try

   FS.Seek(-128, soFromEnd);

   FS.Read(Buffer, 128);

   with Result do

   begin

     ID      := Copy(Buffer, 1, 3);

     Titel   := Copy(Buffer, 4, 30);

     Artist  := Copy(Buffer, 34, 30);

     Album   := Copy(Buffer, 64, 30);

     Year    := Copy(Buffer, 94, 4);

     Comment := Copy(Buffer, 98, 30);

     Genre   := Ord(Buffer[128]);

   end;

 finally

   FS.Free;

 end;

end;

procedure TfrmMain.Button1Click(Sender: TObject);

begin

 if OpenDialog1.Execute then

 begin

   with readID3Tag(OpenDialog1.FileName) do

   begin

     LlbID.Caption := 'ID: ' + ID;

     LlbTitel.Caption := 'Titel: ' + Titel;

     LlbArtist.Caption := 'Artist: ' + Artist;

     LlbAlbum.Caption := 'Album: ' + Album;

     LlbYear.Caption := 'Year: ' + Year;

     LlbComment.Caption := 'Comment: ' + Comment;

     if (Genre >= 0) and (Genre <=146) then

      LlbGenre.Caption := 'Genre: ' + Genres[Genre]

     else

      LlbGenre.Caption := 'N/A';

   end;

 end;

end;

---------------------------------------

ID3v2.pas 单元代码:

unit ID3v2;

interface

uses

 Classes, SysUtils;

const

 TAG_VERSION_2_3 = 3;                               { Code for ID3v2.3.x

tag }

type

 { Class TID3v2 }

 TID3v2 = class(TObject)

   private

     { Private declarations }

     FExists: Boolean;

     FVersionID: Byte;

     FSize: Integer;

     FTitle: string;

     FArtist: string;

     FAlbum: string;

     FTrack: Byte;

     FYear: string;

     FGenre: string;

     FComment: string;

     procedure FSetTitle(const NewTitle: string);

     procedure FSetArtist(const NewArtist: string);

     procedure FSetAlbum(const NewAlbum: string);

     procedure FSetTrack(const NewTrack: Byte);

     procedure FSetYear(const NewYear: string);

     procedure FSetGenre(const NewGenre: string);

     procedure FSetComment(const NewComment: string);

   public

     { Public declarations }

     constructor Create;                                     { Create

object }

     procedure ResetData;                                   { Reset all

data }

     function ReadFromFile(const FileName: string): Boolean;      { Load

tag }

     function RemoveFromFile(const FileName: string): Boolean;  { Delete

tag }

     function SaveToFile(const FileName: string): Boolean;        { Save

tag }

     property Exists: Boolean read FExists;              { True if tag

found }

     property VersionID: Byte read FVersionID;                { Version

code }

     property Size: Integer read FSize;                     { Total tag

size }

     property Title: string read FTitle write FSetTitle;        { Song

title }

     property Artist: string read FArtist write FSetArtist;    { Artist

name }

     property Album: string read FAlbum write FSetAlbum;       { Album

title }

     property Track: Byte read FTrack write FSetTrack;        { Track

number }

     property Year: string read FYear write FSetYear;         { Release

year }

     property Genre: string read FGenre write FSetGenre;        { Genre

name }

     property Comment: string read FComment write FSetComment;     {

Comment }

 end;

implementation

const

 { ID3v2 tag ID }

 ID3V2_ID = 'ID3';

 { Max. number of supported tag frames }

 ID3V2_FRAME_COUNT = 7;

 { Names of supported tag frames }

 ID3V2_FRAME: array [1..ID3V2_FRAME_COUNT] of string =

   ('TIT2', 'TPE1', 'TALB', 'TRCK', 'TYER', 'TCON', 'COMM');

type

 { ID3v2 frame header }

 FrameHeader = record

   ID: array [1..4] of Char;                                      { Frame

ID }

   Size: Integer;                                    { Size excluding

header }

   Flags: Word;                                                      {

Flags }

 end;

 { ID3v2 header data - for internal use }

 TagInfo = record

   { Real structure of ID3v2 header }

   ID: array [1..3] of Char;                                  { Always

"ID3" }

   Version: Byte;                                           { Version

number }

   Revision: Byte;                                         { Revision

number }

   Flags: Byte;                                               { Flags of

tag }

   Size: array [1..4] of Byte;                   { Tag size excluding

header }

   { Extended data }

   FileSize: Integer;                                    { File size

(bytes) }

   Frame: array [1..ID3V2_FRAME_COUNT] of string;  { Information from

frames }

 end;

{ ********************* Auxiliary functions & procedures

******************** }

function ReadHeader(const FileName: string; var Tag: TagInfo): Boolean;

var

 SourceFile: file;

 Transferred: Integer;

begin

 try

   Result := true;

   { Set read-access and open file }

   AssignFile(SourceFile, FileName);

   FileMode := 0;

   Reset(SourceFile, 1);

   { Read header and get file size }

   BlockRead(SourceFile, Tag, 10, Transferred);

   Tag.FileSize := FileSize(SourceFile);

   CloseFile(SourceFile);

   { if transfer is not complete }

   if Transferred < 10 then Result := false;

 except

   { Error }

   Result := false;

 end;

end;

{ ---------------------------------------------------------------------------

}

function GetVersionID(const Tag: TagInfo): Byte;

begin

 { Get tag version from header }

 Result := Tag.Version;

end;

{ ---------------------------------------------------------------------------

}

function GetTagSize(const Tag: TagInfo): Integer;

begin

 { Get total tag size }

 Result :=

   Tag.Size[1] * $200000 +

   Tag.Size[2] * $4000 +

   Tag.Size[3] * $80 +

   Tag.Size[4] + 10;

 if Result > Tag.FileSize then Result := 0;

end;

{ ---------------------------------------------------------------------------

}

procedure SetTagItem(const ID, Data: string; var Tag: TagInfo);

var

 Iterator: Byte;

begin

 { Set tag item if supported frame found }

 for Iterator := 1 to ID3V2_FRAME_COUNT do

   if ID3V2_FRAME[Iterator] = ID then Tag.Frame[Iterator] := Data;

end;

{ ---------------------------------------------------------------------------

}

function Swap32(const Figure: Integer): Integer;

var

 ByteArray: array [1..4] of Byte absolute Figure;

begin

 { Swap 4 bytes }

 Result :=

   ByteArray[1] * $1000000 +

   ByteArray[2] * $10000 +

   ByteArray[3] * $100 +

   ByteArray[4];

end;

{ ---------------------------------------------------------------------------

}

procedure ReadFrames(const FileName: string; var Tag: TagInfo);

var

 SourceFile: file;

 Frame: FrameHeader;

 Data: array [1..250] of Char;

 DataPosition: Integer;

begin

 try

   { Set read-access, open file }

   AssignFile(SourceFile, FileName);

   FileMode := 0;

   Reset(SourceFile, 1);

   Seek(SourceFile, 10);

   while (FilePos(SourceFile) < GetTagSize(Tag)) and (not

EOF(SourceFile)) do

   begin

     FillChar(Data, SizeOf(Data), 0);

     { Read frame header and check frame ID }

     BlockRead(SourceFile, Frame, 10);

     if not (Frame.ID[1] in ['A'..'Z']) then break;

     DataPosition := FilePos(SourceFile);

     { Read frame data and set tag item if frame supported }

     BlockRead(SourceFile, Data, Swap32(Frame.Size) mod SizeOf(Data));

     SetTagItem(Frame.ID, Data, Tag);

     Seek(SourceFile, DataPosition + Swap32(Frame.Size));

   end;

   CloseFile(SourceFile);

 except

 end;

end;

{ ---------------------------------------------------------------------------

}

function ExtractTrack(const TrackString: string): Byte;

var

 Index, Value, Code: Integer;

begin

 { Extract track from string }

 Index := Pos('/', Trim(TrackString));

 if Index = 0 then Val(Trim(TrackString), Value, Code)

 else Val(Copy(Trim(TrackString), 1, Index - 1), Value, Code);

 if Code = 0 then Result := Value

 else Result := 0;

end;

{ ---------------------------------------------------------------------------

}

function ExtractGenre(const GenreString: string): string;

begin

 { Extract genre from string }

 Result := Trim(GenreString);

 if Pos(')', Result) > 0 then Delete(Result, 1, LastDelimiter(')',

Result));

end;

{ ---------------------------------------------------------------------------

}

function RebuildFile(const FileName: string; NewTagData: TStream):

Boolean;

var

 Tag: TagInfo;

 Source, Destination: TFileStream;

 BufferName: string;

begin

 { Rebuild file with old file data and new tag (optional) }

 Result := false;

 if (not FileExists(FileName)) or (FileSetAttr(FileName, 0) <> 0) then

exit;

 if not ReadHeader(FileName, Tag) then exit;

 if (NewTagData = nil) and (Tag.ID <> ID3V2_ID) then exit;

 try

   { Create file streams }

   BufferName := FileName + '~';

   Source := TFileStream.Create(FileName, fmOpenRead or

fmShareExclusive);

   Destination := TFileStream.Create(BufferName, fmCreate);

   { Copy data blocks }

   if Tag.ID = ID3V2_ID then Source.Seek(GetTagSize(Tag),

soFromBeginning);

   if NewTagData <> nil then Destination.CopyFrom(NewTagData, 0);

   Destination.CopyFrom(Source, Source.Size - Source.Position);

   { Free resources }

   Source.Free;

   Destination.Free;

   { Replace old file and delete temporary file }

   if (DeleteFile(FileName)) and (RenameFile(BufferName, FileName)) then

     Result := true

   else

     raise Exception.Create('');

 except

   { Access error }

   if FileExists(BufferName) then DeleteFile(BufferName);

 end;

end;

{ ---------------------------------------------------------------------------

}

procedure BuildHeader(var Tag: TagInfo);

var

 Iterator, TagSize: Integer;

begin

 { Build tag header }

 Tag.ID := ID3V2_ID;

 Tag.Version := TAG_VERSION_2_3;

 Tag.Revision := 0;

 Tag.Flags := 0;

 TagSize := 0;

 for Iterator := 1 to ID3V2_FRAME_COUNT do

   if Tag.Frame[Iterator] <> '' then

     Inc(TagSize, Length(Tag.Frame[Iterator]) + 11);

 { Convert tag size }

 Tag.Size[1] := TagSize div $200000;

 Tag.Size[2] := TagSize div $4000;

 Tag.Size[3] := TagSize div $80;

 Tag.Size[4] := TagSize mod $80;

end;

{ ********************** Private functions & procedures

********************* }

procedure TID3v2.FSetTitle(const NewTitle: string);

begin

 { Set song title }

 FTitle := TrimRight(NewTitle);

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetArtist(const NewArtist: string);

begin

 { Set artist name }

 FArtist := TrimRight(NewArtist);

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetAlbum(const NewAlbum: string);

begin

 { Set album title }

 FAlbum := TrimRight(NewAlbum);

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetTrack(const NewTrack: Byte);

begin

 { Set track number }

 FTrack := NewTrack;

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetYear(const NewYear: string);

begin

 { Set release year }

 FYear := TrimRight(NewYear);

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetGenre(const NewGenre: string);

begin

 { Set genre name }

 FGenre := TrimRight(NewGenre);

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.FSetComment(const NewComment: string);

begin

 { Set comment }

 FComment := TrimRight(NewComment);

end;

{ ********************** Public functions & procedures

********************** }

constructor TID3v2.Create;

begin

 { Create object }

 inherited;

 ResetData;

end;

{ ---------------------------------------------------------------------------

}

procedure TID3v2.ResetData;

begin

 { Reset all variables }

 FExists := false;

 FVersionID := 0;

 FSize := 0;

 FTitle := '';

 FArtist := '';

 FAlbum := '';

 FTrack := 0;

 FYear := '';

 FGenre := '';

 FComment := '';

end;

{ ---------------------------------------------------------------------------

}

function TID3v2.ReadFromFile(const FileName: string): Boolean;

var

 Tag: TagInfo;

begin

 { Reset data and load header from file to variable }

 ResetData;

 Result := ReadHeader(FileName, Tag);

 { Process data if loaded and header valid }

 if (Result) and (Tag.ID = ID3V2_ID) then

 begin

   FExists := true;

   { Fill properties with header data }

   FVersionID := GetVersionID(Tag);

   FSize := GetTagSize(Tag);

   { Get information from frames if version supported }

   if (FVersionID = TAG_VERSION_2_3) and (FSize > 0) then

   begin

     ReadFrames(FileName, Tag);

     { Fill properties with data from frames }

     FTitle := Trim(Tag.Frame[1]);

     FArtist := Trim(Tag.Frame[2]);

     FAlbum := Trim(Tag.Frame[3]);

     FTrack := ExtractTrack(Tag.Frame[4]);

     FYear := Trim(Tag.Frame[5]);

     FGenre := ExtractGenre(Tag.Frame[6]);

     FComment := Trim(Copy(Tag.Frame[7], 5, Length(Tag.Frame[7]) - 4));

   end;

 end;

end;

{ ---------------------------------------------------------------------------

}

function TID3v2.RemoveFromFile(const FileName: string): Boolean;

begin

 { Remove tag from file }

 Result := RebuildFile(FileName, nil);

end;

{ ---------------------------------------------------------------------------

}

function TID3v2.SaveToFile(const FileName: string): Boolean;

var

 NewTagData: TStringStream;

 Tag: TagInfo;

 Iterator, FrameSize: Integer;

begin

 { Build tag and save to file }

 NewTagData := TStringStream.Create('');

 { Prepare tag data }

 FillChar(Tag, SizeOf(Tag), 0);

 Tag.Frame[1] := FTitle;

 Tag.Frame[2] := FArtist;

 Tag.Frame[3] := FAlbum;

 if FTrack > 0 then Tag.Frame[4] := IntToStr(FTrack);

 Tag.Frame[5] := FYear;

 Tag.Frame[6] := FGenre;

 if FComment <> '' then Tag.Frame[7] := 'eng' + #0 + FComment;

 { Build and write tag header }

 BuildHeader(Tag);

 NewTagData.Write(Tag, 10);

 { Build and write tag frames }

 for Iterator := 1 to ID3V2_FRAME_COUNT do

   if Tag.Frame[Iterator] <> '' then

   begin

     NewTagData.WriteString(ID3V2_FRAME[Iterator]);

     FrameSize := Swap32(Length(Tag.Frame[Iterator]) + 1);

     NewTagData.Write(FrameSize, SizeOf(FrameSize));

     NewTagData.WriteString(#0#0#0 + Tag.Frame[Iterator]);

   end;

 { Rebuild file with new tag }

 Result := RebuildFile(FileName, NewTagData);

 NewTagData.Free;

end;

end.

=============================================================================

例子代码:

unit Main;

interface

uses

 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs,

 StdCtrls, FileCtrl, ExtCtrls, ID3v2;

type

 TMainForm = class(TForm)

   DriveList: TDriveComboBox;

   FolderList: TDirectoryListBox;

   FileList: TFileListBox;

   CloseButton: TButton;

   InfoBevel: TBevel;

   IconImage: TImage;

   TagExistsLabel: TLabel;

   TagExistsValue: TEdit;

   VersionLabel: TLabel;

   VersionValue: TEdit;

   SizeLabel: TLabel;

   SizeValue: TEdit;

   TitleLabel: TLabel;

   TitleEdit: TEdit;

   ArtistLabel: TLabel;

   ArtistEdit: TEdit;

   AlbumLabel: TLabel;

   AlbumEdit: TEdit;

   TrackLabel: TLabel;

   TrackEdit: TEdit;

   YearLabel: TLabel;

   YearEdit: TEdit;

   GenreLabel: TLabel;

   GenreEdit: TEdit;

   CommentLabel: TLabel;

   CommentEdit: TEdit;

   RemoveButton: TButton;

   SaveButton: TButton;

   procedure CloseButtonClick(Sender: TObject);

   procedure FormCreate(Sender: TObject);

   procedure FileListChange(Sender: TObject);

   procedure FormClose(Sender: TObject; var Action: TCloseAction);

   procedure SaveButtonClick(Sender: TObject);

   procedure RemoveButtonClick(Sender: TObject);

 private

   { Private declarations }

   FileTag: TID3v2;

   procedure ClearAll;

 end;

var

 MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.ClearAll;

begin

 { Clear all captions }

 TagExistsValue.Text := '';

 VersionValue.Text := '';

 SizeValue.Text := '';

 TitleEdit.Text := '';

 ArtistEdit.Text := '';

 AlbumEdit.Text := '';

 TrackEdit.Text := '';

 YearEdit.Text := '';

 GenreEdit.Text := '';

 CommentEdit.Text := '';

end;

procedure TMainForm.CloseButtonClick(Sender: TObject);

begin

 { Exit }

 Close;

end;

procedure TMainForm.FormCreate(Sender: TObject);

begin

 { Create object and clear captions }

 FileTag := TID3v2.Create;

 ClearAll;

end;

procedure TMainForm.FileListChange(Sender: TObject);

begin

 { Clear captions }

 ClearAll;

 if FileList.FileName = '' then exit;

 if FileExists(FileList.FileName) then

   { Load tag data }

   if FileTag.ReadFromFile(FileList.FileName) then

     if FileTag.Exists then

     begin

       { Fill captions }

       TagExistsValue.Text := 'Yes';

       VersionValue.Text := '2.' + IntToStr(FileTag.VersionID);

       SizeValue.Text := IntToStr(FileTag.Size) + ' bytes';

       TitleEdit.Text := FileTag.Title;

       ArtistEdit.Text := FileTag.Artist;

       AlbumEdit.Text := FileTag.Album;

       if FileTag.Track > 0 then TrackEdit.Text :=

IntToStr(FileTag.Track);

       YearEdit.Text := FileTag.Year;

       GenreEdit.Text := FileTag.Genre;

       CommentEdit.Text := FileTag.Comment;

     end

     else

       { Tag not found }

       TagExistsValue.Text := 'No'

   else

     { Read error }

     ShowMessage('Can not read tag from the file: ' + FileList.FileName)

 else

   { File does not exist }

   ShowMessage('The file does not exist: ' + FileList.FileName);

end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);

begin

 { Free memory }

 FileTag.Free;

end;

procedure TMainForm.SaveButtonClick(Sender: TObject);

var

 Value, Code: Integer;

begin

 { Prepare tag data }

 FileTag.Title := TitleEdit.Text;

 FileTag.Artist := ArtistEdit.Text;

 FileTag.Album := AlbumEdit.Text;

 Val(TrackEdit.Text, Value, Code);

 if (Code = 0) and (Value > 0) then FileTag.Track := Value

 else FileTag.Track := 0;

 FileTag.Year := YearEdit.Text;

 FileTag.Genre := GenreEdit.Text;

 FileTag.Comment := CommentEdit.Text;

 { Save tag data }

 if (not FileExists(FileList.FileName)) or

   (not FileTag.SaveToFile(FileList.FileName)) then

   ShowMessage('Can not save tag to the file: ' + FileList.FileName);

 FileListChange(Self);

end;

procedure TMainForm.RemoveButtonClick(Sender: TObject);

begin

 { Delete tag data }

 if (FileExists(FileList.FileName)) and

   (FileTag.RemoveFromFile(FileList.FileName)) then ClearAll

 else ShowMessage('Can not remove tag from the file: ' +

FileList.FileName);

end;

end.