Recent

Author Topic: Reading MP3 Tags  (Read 2666 times)

nikel

  • Full Member
  • ***
  • Posts: 186
Reading MP3 Tags
« on: September 12, 2020, 01:32:11 am »
Hello, I'm following a tutorial at tweaking4all in order to read idv2 tags of mp3's.

I'm trying to create a console application, here's my code
Code: Pascal  [Select][+][-]
  1. procedure TMain.ReadID3(SFilename:string);
  2. var
  3.   FMP3: file of Byte;
  4.   Tag: ID3Struct;  // line 88
  5. begin
  6.   try
  7.     (* SFileName - (string) The full file name with path. *)
  8.     AssignFile(FMP3, SFileName);
  9.     Reset(FMP3);
  10.     try
  11.       Seek(FMP3, FileSize(FMP3) - 128);
  12.       BlockRead(FMP3, Tag, SizeOf(Tag));
  13.     finally
  14.     end;
  15.   finally
  16.     CloseFile(FMP3);
  17.   end;
  18.   if FMP3.Signature <> 'TAG' then begin // line 102
  19.  
  20.     { Doesn't have an ID3 tag }
  21.   end else begin
  22.  
  23.     { Do something with the tag }
  24.   end;
  25. end;

I'm getting two errors so far:

Quote
project1.lpr(88,3) Error: Duplicate identifier "Tag"

project1.lpr(102,11) Error: Illegal qualifier

How can I fix this?
« Last Edit: September 20, 2020, 10:34:53 pm by nikel »

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Need help with reading mp3 tags
« Reply #1 on: September 12, 2020, 01:47:18 am »
Tag is a Property name of most classes, it allows you to use it for just about anything.

Use a different name or place a & in front of it, but still you need to use that too so what's the difference ;)

Use a Name like The_Tag;

etc


The only true wisdom is knowing you know nothing

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Need help with reading mp3 tags
« Reply #2 on: September 12, 2020, 01:52:01 am »
Hi!

Line 88:

Tag is a predifined property of all components.
So you can't use it.
Name it MP3Tag - or whatever

Line102:

The signature is not part of the file but of the MP3Tag (former Tag).
You need:

Code: Pascal  [Select][+][-]
  1. If MP3Tag.signature <>  'TAG' then ...

Don't invent the wheel again:

I know of two solutions in this forum about ID3 tags.
But maybe there are more.


Winni

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Need help with reading mp3 tags
« Reply #3 on: September 12, 2020, 02:19:05 am »
Thanks for the replies. Changing variable name fixed the problem. I don't want to invent the wheel or America for the second time. It's a small code which doesn't require external libraries.  :)

nikel

  • Full Member
  • ***
  • Posts: 186
Reading MP3 Tags
« Reply #4 on: September 20, 2020, 10:34:30 pm »
I couldn't make it work properly.

This
Code: Pascal  [Select][+][-]
  1. WriteLn(MP3Tag.Title);
  2. WriteLn(MP3Tag.Artist);
  3. WriteLn(MP3Tag.Album);
  4. WriteLn(MP3Tag.Comment);

outputs:

Quote
G

/zoneinfo/Europe/Istanbul

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: Reading MP3 Tags
« Reply #5 on: September 20, 2020, 10:46:47 pm »
And how is your ID3Struct defined?

Bart

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Reading MP3 Tags
« Reply #6 on: September 20, 2020, 10:52:17 pm »
I put it below class definitions. Here's my full code:

Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Classes, SysUtils, CustApp
  10.   { you can add units after this };
  11.  
  12. type
  13.  
  14.   { TMain }
  15.  
  16.   TMain = class(TCustomApplication)
  17.   protected
  18.     procedure DoRun; override;
  19.   public
  20.     procedure ReadID3(SFilename:string);
  21.     constructor Create(TheOwner: TComponent); override;
  22.     destructor Destroy; override;
  23.     procedure WriteHelp; virtual;
  24.   end;
  25.  
  26.   ID3Struct = record
  27.     Signature: array[0..2] of Char; { Should be: "TAG" }
  28.     Title,
  29.     Artist,
  30.     Album: array[0..29] of Char;
  31.     Year: array[0..3] of Char;
  32.     Comment: array[0..29] of Char;
  33.     Genre: Byte;
  34.   end;
  35.  
  36. { TMain }
  37. var
  38.    ID3Genre: array[0..126] of string = (
  39.    'Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge',
  40.    'Hip-Hop', 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B',
  41.    'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', 'Alternative', 'Ska',
  42.    'Death Metal', 'Pranks', 'Soundtrack', 'Euro-Techno', 'Ambient',
  43.    'Trip-Hop', 'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', 'Classical',
  44.    'Instrumental', 'Acid', 'House', 'Game', 'Sound Clip', 'Gospel',
  45.    'Noise', 'AlternRock', 'Bass', 'Soul', 'Punk', 'Space', 'Meditative',
  46.    'Instrumental Pop', 'Instrumental Rock', 'Ethnic', 'Gothic',
  47.    'Darkwave', 'Techno-Industrial', 'Electronic', 'Pop-Folk',
  48.    'Eurodance', 'Dream', 'Southern Rock', 'Comedy', 'Cult', 'Gangsta',
  49.    'Top 40', 'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American',
  50.    'Cabaret', 'New Wave', 'Psychadelic', 'Rave', 'Showtunes', 'Trailer',
  51.    'Lo-Fi', 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro',
  52.    'Musical', 'Rock&  Roll', 'Hard Rock', 'Folk', 'Folk-Rock',
  53.    'National Folk', 'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival',
  54.    'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock',
  55.    'Psychedelic Rock', 'Symphonic Rock', 'Slow Rock', 'Big Band',
  56.    'Chorus', 'Easy Listening', 'Acoustic', 'Humour', 'Speech', 'Chanson',
  57.    'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus',
  58.    'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba',
  59.    'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle',
  60.    'Duet', 'Punk Rock', 'Drum Solo', 'Acapella', 'Euro-House', 'Dance Hall', 'Test'
  61.  );
  62.  
  63. procedure TMain.DoRun;
  64. var
  65.   ErrorMsg: String;
  66. begin
  67.   // quick check parameters
  68.   ErrorMsg:=CheckOptions('h', 'help');
  69.   if ErrorMsg<>'' then begin
  70.     ShowException(Exception.Create(ErrorMsg));
  71.     Terminate;
  72.     Exit;
  73.   end;
  74.  
  75.   // parse parameters
  76.   if HasOption('h', 'help') then begin
  77.     WriteHelp;
  78.     Terminate;
  79.     Exit;
  80.   end;
  81.  
  82.   { add your program here }
  83.   ReadID3('/media/can/DRIVE_2/sarkilar/mp3/burcu_tatlises/gundelik/01___gundelik.mp3');
  84.  
  85.  
  86.   // stop program loop
  87.   Terminate;
  88. end;
  89.  
  90. procedure TMain.ReadID3(SFilename:string);
  91. var
  92.   FMP3: file of Byte;
  93.   MP3Tag: ID3Struct;  // line 88
  94. begin
  95.   try
  96.     (* SFileName - (string) The full file name with path. *)
  97.     AssignFile(FMP3, SFileName);
  98.     Reset(FMP3);
  99.     try
  100.       Seek(FMP3, FileSize(FMP3) - 128);
  101.       BlockRead(FMP3, MP3Tag, SizeOf(Tag));
  102.     finally
  103.     end;
  104.   finally
  105.     CloseFile(FMP3);
  106.   end;
  107.   if MP3Tag.Signature <> 'TAG' then begin
  108.     WriteLn('Doesn''t have a tag')
  109.     { Doesn't have an ID3 tag }
  110.   end else begin
  111.  
  112.     { Do something with the tag }
  113.     WriteLn(MP3Tag.Title);
  114.     WriteLn(MP3Tag.Artist);
  115.     WriteLn(MP3Tag.Album);
  116.     WriteLn(MP3Tag.Comment);
  117.   end;
  118. end;
  119.  
  120. constructor TMain.Create(TheOwner: TComponent);
  121. begin
  122.   inherited Create(TheOwner);
  123.   StopOnException:=True;
  124. end;
  125.  
  126. destructor TMain.Destroy;
  127. begin
  128.   inherited Destroy;
  129. end;
  130.  
  131. procedure TMain.WriteHelp;
  132. begin
  133.   { add your help code here }
  134.   writeln('Usage: ', ExeName, ' -h');
  135. end;
  136.  
  137. var
  138.   Application: TMain;
  139. begin
  140.   Application:=TMain.Create(nil);
  141.   Application.Title:='Read Mp3 Tags';
  142.   Application.Run;
  143.   Application.Free;
  144. end.

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: Reading MP3 Tags
« Reply #7 on: September 20, 2020, 11:00:23 pm »
Make your ID3Struct  a packed record perhaps?

Bart

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Reading MP3 Tags
« Reply #8 on: September 20, 2020, 11:16:39 pm »
I tried it didn't work. I'll also need rating and initial key values. How can I fix it?

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: Reading MP3 Tags
« Reply #9 on: September 20, 2020, 11:27:21 pm »
Code: Pascal  [Select][+][-]
  1.         BlockRead(FMP3, MP3Tag, SizeOf(Mp3Tag)); <<===== (your code says: SizeOf(Tag))

I tested this with these 2 fixes and it works.
Code: [Select]
C:\Users\Bart\LazarusProjecten\bugs\forum\mp3tag>mp3tag "01-Fantasy_ Loving is Easy.mp3"
Title    : Fantasy: Loving is Easy
Artist   : Barclay James Harvest
Album    : XII
Comment  :

Bart

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Reading MP3 Tags
« Reply #10 on: September 21, 2020, 12:33:24 am »
Hi!

It's nice that Bart helps, but the boy is too lazy to search - as I told him:

https://forum.lazarus.freepascal.org/index.php/topic,49887.msg362891.html#msg362891

Winni

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Reading MP3 Tags
« Reply #11 on: September 21, 2020, 01:26:41 am »
I put it below class definitions. Here's my full code:
The use of "try finally" is something strange in the ReadID3 function. I would fix it like this:
Code: Pascal  [Select][+][-]
  1. (* SFileName - (string) The full file name with path. *)
  2. procedure ReadID3(const SFilename: string);
  3. var
  4.   FMP3: file of Byte;
  5.   MP3Tag: ID3Struct;
  6.   FSize: Int64;
  7. begin
  8.   FillChar(MP3Tag, SizeOf(MP3Tag), 0);
  9.   AssignFile(FMP3, SFileName);
  10.   Reset(FMP3);
  11.   try
  12.     FSize := FileSize(FMP3);
  13.     if FSize > SizeOf(ID3Struct) then
  14.     begin
  15.       Seek(FMP3, FSize - SizeOf(ID3Struct));
  16.       BlockRead(FMP3, MP3Tag, SizeOf(ID3Struct));
  17.     end;
  18.   finally
  19.     CloseFile(FMP3);
  20.   end;
  21.   if MP3Tag.Signature <> 'TAG' then
  22.   begin
  23.     WriteLn('Doesn''t have a tag');
  24.   end
  25.   else
  26.   begin
  27.     { Do something with the tag }
  28.     WriteLn(AnsiToOem(MP3Tag.Title));
  29.     WriteLn(AnsiToOem(MP3Tag.Artist));
  30.     WriteLn(AnsiToOem(MP3Tag.Album));
  31.     WriteLn(AnsiToOem(MP3Tag.Comment));
  32.   end;
  33. end;
And the AnsiToOem (in Windows Writeln use OEM codepage for output, MP3 tags - ANSI) function is:
Code: Pascal  [Select][+][-]
  1. function AnsiToOem(const S: string): RawByteString;
  2. begin
  3.   Result := S;
  4.   SetCodePage(Result, CP_OEMCP);
  5. end;

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Reading MP3 Tags
« Reply #12 on: September 21, 2020, 01:41:52 am »
Hi!

It's nice that you try to take care of the codepage but the reality shows that the ID3 Tags V1 are very often encoded in the codepage from their country.

So you can  never be shure what codepage was active when the tag was set.
I have seen kyrillic and greek codepages. You got the same problem as allways with ANSI without codepage information: No solution. Or a heuristic one ????

Winni

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Reading MP3 Tags
« Reply #13 on: September 21, 2020, 02:14:39 am »
No solution. Or a heuristic one ????
But without this function, even a tag created in the same country may look incorrect when output. So a small solution is better than none.

TRon

  • Hero Member
  • *****
  • Posts: 2435
Re: Reading MP3 Tags
« Reply #14 on: September 21, 2020, 02:16:07 am »
Hello, I'm following a tutorial at tweaking4all in order to read idv2 tags of mp3's.
How nice from tweaking4all to show you how to read id3v1 tags instead of id3v2 tags (which you seem to ask for) .. unfortunately, the two different formats do not have anything in common other then most mp3 have both v1 and v2.x tags embedded.

Therefor all listed code so far do not meet your request.

 

TinyPortal © 2005-2018