Index » Empathy Jukebox : Blob ce2df4 / ID3 Tags / id3.pas
unit id3;

interface
uses classes,sysutils;

const
MaxID3Genre=147;
ID3Genre: array[0..MaxID3Genre] 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', 'AlternRock', 'Bass', 'Soul', '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 American',
    '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', 'Rhythmic 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 Rap',
    'Heavy Metal', 'Black Metal', 'Crossover', 'Contemporary Christian',
    'Christian Rock', 'Merengue', 'Salsa', 'Trash Metal', 'Anime', 'Jpop',
    'Synthpop'  {and probably more to come}
  );

type tid3tag = record
field : string;
track : string;
artist : string;
album : string;
year : string;
comments  : string;
genre : string;
trackno : integer;
end;

function readtag(fn : string) : tid3tag;
function writetag(fn : string;tag : tid3tag) : boolean;
function readversion2tag(fn : string) : tid3tag;

implementation

procedure makesize(s : string; l : integer);

begin

if length(s)<l then begin
   while(length(s)<l) do begin
   s:=s+#0;
   end;
end;

if length(s)>l then s:=copy(s,1,l);

end;

function checkvalidtag(f : tfilestream) : boolean;
var
tag : array [0..3] of char;
begin
f.Seek(f.size-128,soFromBeginning);
f.read(tag,3);
if uppercase(tag)<>'TAG' then result:=false else result:=true;
end;

function readtag(fn : string) : tid3tag;
var
readbytes : integer;
f : tfilestream;
pc : array[0..255] of char;

begin
fillchar(result,sizeof(tid3tag),0);
result.field:='';
try
if fileexists(fn)=false then exit;
f:= tfilestream.Create(fn,fmOpenRead or fmShareDenyNone );
except
exit;
end;

if checkvalidtag(f)=false then begin;
  f.free;
  result:=readversion2tag(fn);
  exit;
  end;

f.Seek(f.size-128,soFromBeginning);

fillchar(pc,255,0);
readbytes:=f.read(pc,3);
if readbytes<>3 then begin;f.free;exit;end;;
result.field:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,30);
if readbytes<>30 then begin;f.free;exit;end;;
result.track:='';
result.track:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,30);
if readbytes<>30 then begin;f.free;exit;end;;
result.artist:='';
result.artist:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,30);
if readbytes<>30 then begin;f.free;exit;end;;
result.album:='';
result.album:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,4);
if readbytes<>4 then begin;f.free;exit;end;;
result.year:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,30);
if readbytes<>30 then begin;f.free;exit;end;
result.trackno:=ord(pc[29]);
result.comments:=pc;

fillchar(pc,255,0);
readbytes:=f.read(pc,1);
if readbytes<>1 then begin;f.free;exit;end;;
if (pc='') then result.genre:='Unclassified' else if ord(pc[0])<MaxID3Genre then result.genre:=ID3Genre[ord(pc[0])];
f.free;

end;

function writetag(fn : string;tag : tid3tag) : boolean;
var
f : tfilestream;
written : integer;
pc : array[0..255] of char;
begin
result:=false;

try
f:= tfilestream.Create(fn,fmOpenReadWrite);
except
exit;
end;

if checkvalidtag(f)=false then f.Seek(f.size,soFromBeginning) else f.Seek(f.size-128,soFromBeginning);
makesize(tag.field,3);
makesize(tag.track,30);
makesize(tag.artist,30);
makesize(tag.album,30);
makesize(tag.year,4);
makesize(tag.comments,30);
makesize(tag.genre,1);

strpcopy(pc,tag.field);
written:=f.Write(pc,3);
if written<>3 then begin;f.free;exit;end;;

strpcopy(pc,tag.track);
written:=f.Write(pc,30);
if written<>30 then begin;f.free;exit;end;;
strpcopy(pc,tag.artist);

written:=f.write(pc,30);
if written<>30 then begin;f.free;exit;end;;

strpcopy(pc,tag.album);
written:=f.write(pc,30);
if written<>30 then begin;f.free;exit;end;;

strpcopy(pc,tag.year);
written:=f.write(pc,4);
if written<>4 then begin;f.free;exit;end;;

strpcopy(pc,tag.comments);
written:=f.write(pc,30);
if written<>30 then begin;f.free;exit;end;;

strpcopy(pc,tag.genre);
written:=f.write(pc,1);
if written<>1 then begin;f.free;exit;end;;

result:=true;
f.free;
end;


function readversion2tag(fn : string) : tid3tag;
var
f : tfilestream;
ms : tmemorystream;
sr : string;
scrap : integer;
p : longint;
sz : longint;
z : string;

function readframe(tag : string) : string;
begin
p:=pos(tag,sr);
if p>0 then begin
z:=copy(sr,p+length(tag),4);

z:=inttostr(ord(z[1]))+inttostr(ord(z[2]))+inttostr(ord(z[3]))+inttostr(ord(z[4]));

sz:=strtoint(z);
result:=copy(sr,p+length(tag)+6,sz);
end;

end;

begin
try
f:=tfilestream.Create(fn,fmOpenRead or fmShareDenyNone );
except
exit;
end;

ms:=tmemorystream.Create;

ms.LoadFromStream(f);


setlength(sr,ms.size+1);
ms.Seek(0,soFromBeginning);
ms.read(sr[1],ms.size-1);
 ms.free;
 f.free;

 if pos('ID3',sr)=0 then begin
  setlength(sr,0);
 exit;
end;


result.track:=trim(readframe('TIT2'));
result.artist:=trim(readframe('TPE1'));
try
result.album:=trim(readframe('TALB'));
val(readframe('TRCK'),result.trackno,scrap);
except
end;
result.year:='';
try
result.year:=trim(readframe('TYER'));
except

end;


result.genre:=trim(readframe('TCON'));
setlength(sr,0);
end;


end.