home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kompon / d56 / MPEGPLUS.ZIP / ID3v1 / ID3v1.pas next >
Encoding:
Pascal/Delphi Source File  |  2001-08-02  |  15.3 KB  |  475 lines

  1. { *************************************************************************** }
  2. {                                                                             }
  3. { Audio Tools Library (Freeware)                                              }
  4. { Class TID3v1 - for manipulating with ID3v1 tags                             }
  5. {                                                                             }
  6. { Copyright (c) 2001 by Jurgen Faul                                           }
  7. { E-mail: jfaul@gmx.de                                                        }
  8. { http://jfaul.de/atl                                                         }
  9. {                                                                             }
  10. { Version 1.0 (25 July 2001)                                                  }
  11. {   - Full support for ID3v1.0 & ID3v1.1 tags (read/write)                    }
  12. {                                                                             }
  13. { *************************************************************************** }
  14.  
  15. unit ID3v1;
  16.  
  17. interface
  18.  
  19. uses
  20.   Classes, SysUtils;
  21.  
  22. const
  23.   MAX_MUSIC_GENRES = 148;                       { Max. number of music genres }
  24.   DEFAULT_GENRE = 255;                              { Index for default genre }
  25.  
  26.   { Used with VersionID property }
  27.   TAG_VERSION_1_0 = 1;                                { Index for ID3v1.0 tag }
  28.   TAG_VERSION_1_1 = 2;                                { Index for ID3v1.1 tag }
  29.  
  30. var
  31.   MusicGenre: array [0..MAX_MUSIC_GENRES - 1] of string;        { Genre names }
  32.  
  33. type
  34.   { Used in TID3v1 class }
  35.   String04 = string[4];                          { String with max. 4 symbols }
  36.   String30 = string[30];                        { String with max. 30 symbols }
  37.  
  38.   { Class TID3v1 }
  39.   TID3v1 = class(TObject)
  40.     private
  41.       { Private declarations }
  42.       FExists: Boolean;
  43.       FVersionID: Byte;
  44.       FTitle: String30;
  45.       FArtist: String30;
  46.       FAlbum: String30;
  47.       FYear: String04;
  48.       FComment: String30;
  49.       FTrack: Byte;
  50.       FGenreID: Byte;
  51.       procedure FSetTitle(const NewTitle: String30);
  52.       procedure FSetArtist(const NewArtist: String30);
  53.       procedure FSetAlbum(const NewAlbum: String30);
  54.       procedure FSetYear(const NewYear: String04);
  55.       procedure FSetComment(const NewComment: String30);
  56.       procedure FSetTrack(const NewTrack: Byte);
  57.       procedure FSetGenreID(const NewGenreID: Byte);
  58.       function FGetGenre: string;
  59.     public
  60.       { Public declarations }
  61.       constructor Create;                                     { Create object }
  62.       procedure ResetData;                                   { Reset all data }
  63.       function ReadFromFile(const FileName: string): Boolean;      { Load tag }
  64.       function RemoveFromFile(const FileName: string): Boolean;  { Delete tag }
  65.       function SaveToFile(const FileName: string): Boolean;        { Save tag }
  66.       property Exists: Boolean read FExists;              { True if tag found }
  67.       property VersionID: Byte read FVersionID;                { Version code }
  68.       property Title: String30 read FTitle write FSetTitle;      { Song title }
  69.       property Artist: String30 read FArtist write FSetArtist;  { Artist name }
  70.       property Album: String30 read FAlbum write FSetAlbum;      { Album name }
  71.       property Year: String04 read FYear write FSetYear;               { Year }
  72.       property Comment: String30 read FComment write FSetComment;   { Comment }
  73.       property Track: Byte read FTrack write FSetTrack;        { Track number }
  74.       property GenreID: Byte read FGenreID write FSetGenreID;    { Genre code }
  75.       property Genre: string read FGetGenre;                     { Genre name }
  76.   end;
  77.  
  78. implementation
  79.  
  80. type
  81.   { Real structure of ID3v1 tag }
  82.   TagRecord = record
  83.     Header: array [1..3] of Char;                { Tag header - must be "TAG" }
  84.     Title: array [1..30] of Char;                                { Title data }
  85.     Artist: array [1..30] of Char;                              { Artist data }
  86.     Album: array [1..30] of Char;                                { Album data }
  87.     Year: array [1..4] of Char;                                   { Year data }
  88.     Comment: array [1..30] of Char;                            { Comment data }
  89.     Genre: Byte;                                                 { Genre data }
  90.   end;
  91.  
  92. { ********************* Auxiliary functions & procedures ******************** }
  93.  
  94. function ReadTag(const FileName: string; var TagData: TagRecord): Boolean;
  95. var
  96.   SourceFile: file;
  97. begin
  98.   try
  99.     Result := true;
  100.     { Set read-access and open file }
  101.     AssignFile(SourceFile, FileName);
  102.     FileMode := 0;
  103.     Reset(SourceFile, 1);
  104.     { Read tag }
  105.     Seek(SourceFile, FileSize(SourceFile) - 128);
  106.     BlockRead(SourceFile, TagData, 128);
  107.     CloseFile(SourceFile);
  108.   except
  109.     { Error }
  110.     Result := false;
  111.   end;
  112. end;
  113.  
  114. { --------------------------------------------------------------------------- }
  115.  
  116. function RemoveTag(const FileName: string): Boolean;
  117. var
  118.   SourceFile: file;
  119. begin
  120.   try
  121.     Result := true;
  122.     { Allow write-access and open file }
  123.     FileSetAttr(FileName, 0);
  124.     AssignFile(SourceFile, FileName);
  125.     FileMode := 2;
  126.     Reset(SourceFile, 1);
  127.     { Delete tag }
  128.     Seek(SourceFile, FileSize(SourceFile) - 128);
  129.     Truncate(SourceFile);
  130.     CloseFile(SourceFile);
  131.   except
  132.     { Error }
  133.     Result := false;
  134.   end;
  135. end;
  136.  
  137. { --------------------------------------------------------------------------- }
  138.  
  139. function SaveTag(const FileName: string; TagData: TagRecord): Boolean;
  140. var
  141.   SourceFile: file;
  142. begin
  143.   try
  144.     Result := true;
  145.     { Allow write-access and open file }
  146.     FileSetAttr(FileName, 0);
  147.     AssignFile(SourceFile, FileName);
  148.     FileMode := 2;
  149.     Reset(SourceFile, 1);
  150.     { Write tag }
  151.     Seek(SourceFile, FileSize(SourceFile));
  152.     BlockWrite(SourceFile, TagData, SizeOf(TagData));
  153.     CloseFile(SourceFile);
  154.   except
  155.     { Error }
  156.     Result := false;
  157.   end;
  158. end;
  159.  
  160. { --------------------------------------------------------------------------- }
  161.  
  162. function GetTagVersion(const TagData: TagRecord): Byte;
  163. begin
  164.   Result := TAG_VERSION_1_0;
  165.   { Terms for ID3v1.1 }
  166.   if ((TagData.Comment[29] = #0) and (TagData.Comment[30] <> #0)) or
  167.     ((TagData.Comment[29] = #32) and (TagData.Comment[30] <> #32)) then
  168.     Result := TAG_VERSION_1_1;
  169. end;
  170.  
  171. { ********************** Private functions & procedures ********************* }
  172.  
  173. procedure TID3v1.FSetTitle(const NewTitle: String30);
  174. begin
  175.   FTitle := TrimRight(NewTitle);
  176. end;
  177.  
  178. { --------------------------------------------------------------------------- }
  179.  
  180. procedure TID3v1.FSetArtist(const NewArtist: String30);
  181. begin
  182.   FArtist := TrimRight(NewArtist);
  183. end;
  184.  
  185. { --------------------------------------------------------------------------- }
  186.  
  187. procedure TID3v1.FSetAlbum(const NewAlbum: String30);
  188. begin
  189.   FAlbum := TrimRight(NewAlbum);
  190. end;
  191.  
  192. { --------------------------------------------------------------------------- }
  193.  
  194. procedure TID3v1.FSetYear(const NewYear: String04);
  195. begin
  196.   FYear := TrimRight(NewYear);
  197. end;
  198.  
  199. { --------------------------------------------------------------------------- }
  200.  
  201. procedure TID3v1.FSetComment(const NewComment: String30);
  202. begin
  203.   FComment := TrimRight(NewComment);
  204. end;
  205.  
  206. { --------------------------------------------------------------------------- }
  207.  
  208. procedure TID3v1.FSetTrack(const NewTrack: Byte);
  209. begin
  210.   FTrack := NewTrack;
  211. end;
  212.  
  213. { --------------------------------------------------------------------------- }
  214.  
  215. procedure TID3v1.FSetGenreID(const NewGenreID: Byte);
  216. begin
  217.   FGenreID := NewGenreID;
  218. end;
  219.  
  220. { --------------------------------------------------------------------------- }
  221.  
  222. function TID3v1.FGetGenre: string;
  223. begin
  224.   Result := '';
  225.   { Return an empty string if the current GenreID is not valid }
  226.   if FGenreID in [0..MAX_MUSIC_GENRES - 1] then Result := MusicGenre[FGenreID];
  227. end;
  228.  
  229. { ********************** Public functions & procedures ********************** }
  230.  
  231. constructor TID3v1.Create;
  232. begin
  233.   inherited;
  234.   ResetData;
  235. end;
  236.  
  237. { --------------------------------------------------------------------------- }
  238.  
  239. procedure TID3v1.ResetData;
  240. begin
  241.   FExists := false;
  242.   FVersionID := TAG_VERSION_1_0;
  243.   FTitle := '';
  244.   FArtist := '';
  245.   FAlbum := '';
  246.   FYear := '';
  247.   FComment := '';
  248.   FTrack := 0;
  249.   FGenreID := DEFAULT_GENRE;
  250. end;
  251.  
  252. { --------------------------------------------------------------------------- }
  253.  
  254. function TID3v1.ReadFromFile(const FileName: string): Boolean;
  255. var
  256.   TagData: TagRecord;
  257. begin
  258.   { Reset and load tag data from file to variable }
  259.   ResetData;
  260.   Result := ReadTag(FileName, TagData);
  261.   { Process data if loaded and tag header OK }
  262.   if (Result) and (TagData.Header = 'TAG') then
  263.   begin
  264.     FExists := true;
  265.     FVersionID := GetTagVersion(TagData);
  266.     { Fill properties with tag data }
  267.     FTitle := TrimRight(TagData.Title);
  268.     FArtist := TrimRight(TagData.Artist);
  269.     FAlbum := TrimRight(TagData.Album);
  270.     FYear := TrimRight(TagData.Year);
  271.     if FVersionID = TAG_VERSION_1_0 then
  272.       FComment := TrimRight(TagData.Comment)
  273.     else
  274.     begin
  275.       FComment := TrimRight(Copy(TagData.Comment, 1, 28));
  276.       FTrack := Ord(TagData.Comment[30]);
  277.     end;
  278.     FGenreID := TagData.Genre;
  279.   end;
  280. end;
  281.  
  282. { --------------------------------------------------------------------------- }
  283.  
  284. function TID3v1.RemoveFromFile(const FileName: string): Boolean;
  285. var
  286.   TagData: TagRecord;
  287. begin
  288.   { Find tag }
  289.   Result := ReadTag(FileName, TagData);
  290.   { Delete tag if loaded and tag header OK }
  291.   if (Result) and (TagData.Header = 'TAG') then Result := RemoveTag(FileName);
  292. end;
  293.  
  294. { --------------------------------------------------------------------------- }
  295.  
  296. function TID3v1.SaveToFile(const FileName: string): Boolean;
  297. var
  298.   TagData: TagRecord;
  299. begin
  300.   { Prepare tag record }
  301.   FillChar(TagData, SizeOf(TagData), 0);
  302.   TagData.Header := 'TAG';
  303.   Move(FTitle[1], TagData.Title, Length(FTitle));
  304.   Move(FArtist[1], TagData.Artist, Length(FArtist));
  305.   Move(FAlbum[1], TagData.Album, Length(FAlbum));
  306.   Move(FYear[1], TagData.Year, Length(FYear));
  307.   Move(FComment[1], TagData.Comment, Length(FComment));
  308.   if FTrack > 0 then
  309.   begin
  310.     TagData.Comment[29] := #0;
  311.     TagData.Comment[30] := Chr(FTrack);
  312.   end;
  313.   TagData.Genre := FGenreID;
  314.   { Delete old tag and write new tag }
  315.   Result := (RemoveFromFile(FileName)) and (SaveTag(FileName, TagData));
  316. end;
  317.  
  318. { ************************** Initialize music genres ************************ }
  319.  
  320. initialization
  321. begin
  322.   { Standard genres }
  323.   MusicGenre[0] := 'Blues';
  324.   MusicGenre[1] := 'Classic Rock';
  325.   MusicGenre[2] := 'Country';
  326.   MusicGenre[3] := 'Dance';
  327.   MusicGenre[4] := 'Disco';
  328.   MusicGenre[5] := 'Funk';
  329.   MusicGenre[6] := 'Grunge';
  330.   MusicGenre[7] := 'Hip-Hop';
  331.   MusicGenre[8] := 'Jazz';
  332.   MusicGenre[9] := 'Metal';
  333.   MusicGenre[10] := 'New Age';
  334.   MusicGenre[11] := 'Oldies';
  335.   MusicGenre[12] := 'Other';
  336.   MusicGenre[13] := 'Pop';
  337.   MusicGenre[14] := 'R&B';
  338.   MusicGenre[15] := 'Rap';
  339.   MusicGenre[16] := 'Reggae';
  340.   MusicGenre[17] := 'Rock';
  341.   MusicGenre[18] := 'Techno';
  342.   MusicGenre[19] := 'Industrial';
  343.   MusicGenre[20] := 'Alternative';
  344.   MusicGenre[21] := 'Ska';
  345.   MusicGenre[22] := 'Death Metal';
  346.   MusicGenre[23] := 'Pranks';
  347.   MusicGenre[24] := 'Soundtrack';
  348.   MusicGenre[25] := 'Euro-Techno';
  349.   MusicGenre[26] := 'Ambient';
  350.   MusicGenre[27] := 'Trip-Hop';
  351.   MusicGenre[28] := 'Vocal';
  352.   MusicGenre[29] := 'Jazz+Funk';
  353.   MusicGenre[30] := 'Fusion';
  354.   MusicGenre[31] := 'Trance';
  355.   MusicGenre[32] := 'Classical';
  356.   MusicGenre[33] := 'Instrumental';
  357.   MusicGenre[34] := 'Acid';
  358.   MusicGenre[35] := 'House';
  359.   MusicGenre[36] := 'Game';
  360.   MusicGenre[37] := 'Sound Clip';
  361.   MusicGenre[38] := 'Gospel';
  362.   MusicGenre[39] := 'Noise';
  363.   MusicGenre[40] := 'AlternRock';
  364.   MusicGenre[41] := 'Bass';
  365.   MusicGenre[42] := 'Soul';
  366.   MusicGenre[43] := 'Punk';
  367.   MusicGenre[44] := 'Space';
  368.   MusicGenre[45] := 'Meditative';
  369.   MusicGenre[46] := 'Instrumental Pop';
  370.   MusicGenre[47] := 'Instrumental Rock';
  371.   MusicGenre[48] := 'Ethnic';
  372.   MusicGenre[49] := 'Gothic';
  373.   MusicGenre[50] := 'Darkwave';
  374.   MusicGenre[51] := 'Techno-Industrial';
  375.   MusicGenre[52] := 'Electronic';
  376.   MusicGenre[53] := 'Pop-Folk';
  377.   MusicGenre[54] := 'Eurodance';
  378.   MusicGenre[55] := 'Dream';
  379.   MusicGenre[56] := 'Southern Rock';
  380.   MusicGenre[57] := 'Comedy';
  381.   MusicGenre[58] := 'Cult';
  382.   MusicGenre[59] := 'Gangsta';
  383.   MusicGenre[60] := 'Top 40';
  384.   MusicGenre[61] := 'Christian Rap';
  385.   MusicGenre[62] := 'Pop/Funk';
  386.   MusicGenre[63] := 'Jungle';
  387.   MusicGenre[64] := 'Native American';
  388.   MusicGenre[65] := 'Cabaret';
  389.   MusicGenre[66] := 'New Wave';
  390.   MusicGenre[67] := 'Psychadelic';
  391.   MusicGenre[68] := 'Rave';
  392.   MusicGenre[69] := 'Showtunes';
  393.   MusicGenre[70] := 'Trailer';
  394.   MusicGenre[71] := 'Lo-Fi';
  395.   MusicGenre[72] := 'Tribal';
  396.   MusicGenre[73] := 'Acid Punk';
  397.   MusicGenre[74] := 'Acid Jazz';
  398.   MusicGenre[75] := 'Polka';
  399.   MusicGenre[76] := 'Retro';
  400.   MusicGenre[77] := 'Musical';
  401.   MusicGenre[78] := 'Rock & Roll';
  402.   MusicGenre[79] := 'Hard Rock';
  403.   { Extended genres }
  404.   MusicGenre[80] := 'Folk';
  405.   MusicGenre[81] := 'Folk-Rock';
  406.   MusicGenre[82] := 'National Folk';
  407.   MusicGenre[83] := 'Swing';
  408.   MusicGenre[84] := 'Fast Fusion';
  409.   MusicGenre[85] := 'Bebob';
  410.   MusicGenre[86] := 'Latin';
  411.   MusicGenre[87] := 'Revival';
  412.   MusicGenre[88] := 'Celtic';
  413.   MusicGenre[89] := 'Bluegrass';
  414.   MusicGenre[90] := 'Avantgarde';
  415.   MusicGenre[91] := 'Gothic Rock';
  416.   MusicGenre[92] := 'Progessive Rock';
  417.   MusicGenre[93] := 'Psychedelic Rock';
  418.   MusicGenre[94] := 'Symphonic Rock';
  419.   MusicGenre[95] := 'Slow Rock';
  420.   MusicGenre[96] := 'Big Band';
  421.   MusicGenre[97] := 'Chorus';
  422.   MusicGenre[98] := 'Easy Listening';
  423.   MusicGenre[99] := 'Acoustic';
  424.   MusicGenre[100]:= 'Humour';
  425.   MusicGenre[101]:= 'Speech';
  426.   MusicGenre[102]:= 'Chanson';
  427.   MusicGenre[103]:= 'Opera';
  428.   MusicGenre[104]:= 'Chamber Music';
  429.   MusicGenre[105]:= 'Sonata';
  430.   MusicGenre[106]:= 'Symphony';
  431.   MusicGenre[107]:= 'Booty Bass';
  432.   MusicGenre[108]:= 'Primus';
  433.   MusicGenre[109]:= 'Porn Groove';
  434.   MusicGenre[110]:= 'Satire';
  435.   MusicGenre[111]:= 'Slow Jam';
  436.   MusicGenre[112]:= 'Club';
  437.   MusicGenre[113]:= 'Tango';
  438.   MusicGenre[114]:= 'Samba';
  439.   MusicGenre[115]:= 'Folklore';
  440.   MusicGenre[116]:= 'Ballad';
  441.   MusicGenre[117]:= 'Power Ballad';
  442.   MusicGenre[118]:= 'Rhythmic Soul';
  443.   MusicGenre[119]:= 'Freestyle';
  444.   MusicGenre[120]:= 'Duet';
  445.   MusicGenre[121]:= 'Punk Rock';
  446.   MusicGenre[122]:= 'Drum Solo';
  447.   MusicGenre[123]:= 'A capella';
  448.   MusicGenre[124]:= 'Euro-House';
  449.   MusicGenre[125]:= 'Dance Hall';
  450.   MusicGenre[126]:= 'Goa';
  451.   MusicGenre[127]:= 'Drum & Bass';
  452.   MusicGenre[128]:= 'Club-House';
  453.   MusicGenre[129]:= 'Hardcore';
  454.   MusicGenre[130]:= 'Terror';
  455.   MusicGenre[131]:= 'Indie';
  456.   MusicGenre[132]:= 'BritPop';
  457.   MusicGenre[133]:= 'Negerpunk';
  458.   MusicGenre[134]:= 'Polsk Punk';
  459.   MusicGenre[135]:= 'Beat';
  460.   MusicGenre[136]:= 'Christian Gangsta Rap';
  461.   MusicGenre[137]:= 'Heavy Metal';
  462.   MusicGenre[138]:= 'Black Metal';
  463.   MusicGenre[139]:= 'Crossover';
  464.   MusicGenre[140]:= 'Contemporary Christian';
  465.   MusicGenre[141]:= 'Christian Rock';
  466.   MusicGenre[142]:= 'Merengue';
  467.   MusicGenre[143]:= 'Salsa';
  468.   MusicGenre[144]:= 'Trash Metal';
  469.   MusicGenre[145]:= 'Anime';
  470.   MusicGenre[146]:= 'JPop';
  471.   MusicGenre[147]:= 'Synthpop';
  472. end;
  473.  
  474. end.
  475.