Question

I'm using both old good MPGTools and own, simple method of setting ID3 Tag in my MP3 files. But both approaches are too old to support ID3Tag version 2. I'm looking for any solution that would allow my application, written in Delphi 7, to either remove ID3Tag from each file it process or to set it to exactly the same values as ID3Tag version 1 is set.

Currently I'm removing ID3Tagv2 manually, using quick keyboard combination in Winamp.

I don't use v2 or album art or all these "new" addition, so the quickiest way to get rid of ID3Tagv2 (if it exists in particular file) would be all I need.

Of course I've tried to search the Internet using Google, but either I've got bad day or I'm asking wrong question, because all the results I'm getting on above mentioned questions are fake result from search engine stealers like Software Informer etc.

Was it helpful?

Solution

As it happens, one of my projects sitting here that is awaiting completion (about 80%, I'm more a hobbyist when it comes to Delphi and had more pressing stuff come up, then I found a program I was able to download which fit my requirements precisely) is a full ID3 tag editor for MP3 files. While v1 was super-easy, v2 is much harder. You can refer to the standard document for v2.3 here. But I will confine myself to the points addressed here.

You might want ID3v2 tags depending on the application. My portable MP3 player only accepts v2 tags, which is what pushed me to do the project in the first place.

ID3v2 tags are written at the beginning of files in a variable length manner with variable numbers of tags which may or may not be present. Fortunately, the full length of the data should be in the first record if it's an ID3v2 tagged file. Hence, read the file locate the length of the ID3v2 data, then rewrite the file without the ID3v2 data and the tags are removed. Having the data at the beginning makes this necessary and is indeed a frustration. Anything I do in the future to the code would involve trying to change data in place. Some very dirty code follows, which AFAIR worked, but you will need to clean up if you use (I'm sure some here will be content to point out exactly how I should). But test it well just to be sure. Also be sure to ask if I missed anything from the unit I copied this out of (it's a 19.3KB pas file) that you would need:

type
  sarray = array[0..3] of byte;
  psarray = ^sarray;

  ID3v2Header = packed record
     identifier: array[0..2] of char;
     major_version: byte;
     minor_version: byte;
     flags: byte;
     size: DWord;
  end;

 function size_decodeh(insize: DWord): DWord;
   { decodes the size headers only, which does not use bit 7 in each byte,
     requires MSB conversion as well }
   var
     outdval: DWord;
     outd, ind: psarray;
     tnext2, pnext2: byte;

   begin
     outdval := 0;
     outd := @outdval;
     ind := @insize;
     tnext2 := ind^[2] shr 1;
     pnext2 := ind^[1] shr 2;

     outd^[0] := ind^[3] or ((ind^[2] and $01) shl 7);
     outd^[1] := tnext2 or ((ind^[1] and $03) shl 6);
     outd^[2] := pnext2 or ((ind^[0] and $07) shl 5);
     outd^[3] := ind^[0] shr 3;
     Result := outdval;
   end;

procedure ID3v2_LoadData(filename: string; var memrec: pointer;
                       var outsize: integer);
  { procedure loads ID3v2 data from "filename".  Returns outsize = 0 if
    there is no ID3v2 data }

var
  infile: file;
  v1h: ID3V2Header;
begin
  assign(infile, filename);
  reset(infile, 1);
// read main header to get id3v2 size
  blockread(infile, v1h, sizeof(v1h));
// detect if there is id3v2 data
  if v1h.identifier = 'ID3' then
    begin
      outsize := size_decodeh(v1h.size);
      // read ID3v2 header data
      getmem(memrec, outsize);
      blockread(infile, memrec^, outsize);
      Close(infile);
    end
  else
    outsize := 0;
  end;

 function id3v2_erase(infilestr: string): boolean;
  { erase all ID3v2 data.  Data are stored at the beginning of file, so file
    must be rewritten }
   const
     tempfilename = 'TMp@!0X.MP3';
   var
     memrec: pointer;
     outsize, dataread: integer;
     IsID3v2: boolean;
     databuffer: array[1..32768] of byte;
     newfile, origfile: file;
   begin
  // reuse service routine to get information
     Id3v2_loaddata(infilestr, memrec, outsize);
  // is there ID3v2 data?
     if outsize > 0 then
       begin
        // need to clean up after the service routine
         freemem(memrec);
        // get amount of data to erase
        outsize := outsize + sizeof(Id3v2Header);
        writeln('Data to delete is: ', outsize, ' bytes.');
        // now rewrite the file
        AssignFile(origfile, infilestr);
        reset(origfile, 1);
        AssignFile(newfile, tempfilename);
        rewrite(newfile, 1);
        Seek(origfile, outsize);
        repeat
          blockread(origfile, databuffer, sizeof(databuffer), dataread);
          blockwrite(newfile, databuffer, dataread);
        until dataread = 0;
        CloseFile(origfile);
        CloseFile(newfile);
       // rename temp file and delete original
        DeleteFile(infilestr);
        RenameFile(tempfilename, infilestr);
        IsID3v2 := true;
      end
  else
     IsID3v2 := false;
  Result := IsID3v2;
end;

Full editing capability that works in most all situations is obviously a tougher hill to climb than that, but all the details are there in that document I linked to. Hopefully this helps you out.

OTHER TIPS

There are few libs that works fine with ID3V2. Back in 2006 I did a big research to find Delphi library that supports most of the Id3V2 specification for Delphi 7. And I found these 2:

  1. Audio Tools Library (was the best for that moment). I think that it even could read/write tags in Unicode. Here is the unit Id3V2.pas
  2. JVCL has component to work with Id3V2 tags. But it didn't had Unicode support for non-unicode Delphi in 2006.

Btw, if you do not use JVCL yet, it's not worth to install more than 600 components just to get Id3V2 support. So, take a look at Audio Tools Library.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top