Archive

Posts Tagged ‘read’

How to Read / Write ID3 Tags in MP3 Files

December 15th, 1999 m3Rlin No comments

The thing that makes MPEG Layer 3 files good (besides their size:) are ID3 tags. Thanks to them you can save information about the song. Here’s the ID3 tag structure and information on reading/modifying them. Enjoy!
The ID3 tag is saved in the last 128 bytes of a MPEG Layer 3 file. It starts with a “TAG” string. If this string is absent that means that ID3 information has been removed. But don’t worry – all you have to do is append it to the file.
In newer versions of Delphi if you are going to use this code you may want to use the packed keyword with arrays and records.
The MPEG Layer 3 ID3 tag structure:

  ID3Struct = record
    Signature: array[0..2] of Char; { Should be: "TAG" }
    Title,
    Artist,
    Album: array[0..29] of Char;
    Year: array[0..3] of Char;
    Comment: array[0..29] of Char;
    Genre: Byte;
  end;

Here’s the genre (Max. 256 entries).

  ID3Genre: array[0..126] 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'
  );

This is the ID3 Tag read code:

var
  fMP3: file of Byte;
  Tag: ID3Struct;
begin
  try
    (* sFileName - (string) The full file name with path. *)
    AssignFile(fMP3, sFileName);
    Reset(fMP3);
    try
      Seek(fMP3, FileSize(fMP3) - 128);
      BlockRead(fMP3, Tag, SizeOf(Tag));
    finally
    end;
  finally
    CloseFile(fMP3);
  end;
  if fMP3.Signature <> 'TAG' then begin
    ...
    { Doesn't have an ID3 tag }
  end else begin
    ...
    { Do something with the tag }
  end;
end;

(* WriteID3Tag() function
**
** Copyright (c) 2000 Jacob Dybala (m3Rlin)
** Freeware.
**
** Created : January 7 2000
** Modified: January 7 2000
** Please leave this copyright notice.
*)
procedure WriteID3Tag(id3NewTag: ID3Struct; sFileName: string);
var
  fMP3: file of Byte;
  Tag : ID3Struct;
begin
  try
    AssignFile(fMP3, sFileName);
    Reset(fMP3);
    try
      Seek(fMP3, FileSize(fMP3) - ID3OffsetFromEnd);
      BlockRead(fMP3, Tag, SizeOf(Tag));
      if fMP3.Signature = 'TAG' then
        { Replace old tag }
        Seek(fMP3, FileSize(fMP3) - ID3OffsetFromEnd)
      else
        (* Append tag to file because it doesn't exist.
        * Cannot use Append() function. It's only for text files.
        *)
        Seek(fMP3, FileSize(fMP3));
      BlockWrite(fMP3, id3NewTag, SizeOf(id3NewTag));
    finally
    end;
  finally
    CloseFile(fMP3);
  end;
end;

How to Access the Registry Using Windows API

December 15th, 1999 m3Rlin 1 comment

You may, for some reasons not want to use Delphi’s TRegistry component but still want to use the system’s Registry. This may come in handy when creating applications for Windows NT/2000/XP/Vista. Delphi’s TRegistry component will raise an error when attempting to write a string value to the HKEY_LOCAL_MACHINE key. Well, the way to get over this is to call the Windows API directly. This is a little harder than using the TRegistry component, but Delphi users that have some C/C++ experience shouldn’t have any problems. If you like Object Pascal’s standard data types you’re going to hate this ;-) Although this may look like a lot of work it’s really fun. When you’re program saves/reads a lot of data to/from the Registry (like Option dialogs) this may dramatically shorten the time needed for these operations.

This example will not work on Windows 3.x with Win32s installed because the API functions used here are native Win32 functions. Check up the function parameters in the Win32 help.
The API functions we will need:

  • RegCreateKeyEx() or RegOpenKeyEx()
  • RegCloseKeyE()
  • RegSetValueEx()
uses
  Windows;
...
var
  hOpenKey: HKEY;
  iI, iSize, iType: Integer;
  pcTemp: Array[0.256] of Char;
  pdI: PDWORD;
...
  (* This example creates and opens the key HKEY_CURRENT_USERSoftwarem3RlinDelphi FAQ
  ** and saves data in it. If you don't want to create a key but just open an
  ** existing one use the RegOpenKeyEx() function.
  *)
  pdI := nil;
  if RegCreateKeyEx(HKEY_CURRENT_USER, 'Software\\m3Rlin\\Delphi FAQ', 0, nil,
    REG_OPTION_NON_VOLATILE, KEY_WRITE, nil, hOpenKey, pdI) = ERROR_SUCCESS then begin
    // Saving a Boolean value
    iI := Integer(checkboxMain.Checked);
    RegSetValueEx(hOpenKey, 'Boolean Value', 0, REG_DWORD, @iI, SizeOf(iI));
    // Saving a Integer value
    iI := Integer(MainForm.Height);
    RegSetValueEx(hOpenKey, 'Integer Value', 0, REG_DWORD, @iI, SizeOf(iI));
    // Saving a string value
    RegSetValueEx(hOpenKey, 'String Value', 0, REG_SZ, PChar(MainForm.Caption),
    Length(MainForm.Caption) + 1); // The 1 is for the terminating 0 (PChar)
    RegCloseKey(hOpenKey); // Close the open registry key
  end;
  (* This example opens the key HKEY_CURRENT_USERSoftwarem3RlinDelphi FAQ and reads
  ** data from it.
  *)
  pdI := nil;
  if RegOpenKeyEx(HKEY_CURRENT_USER, 'Software\m3Rlin\Delphi FAQ', 0, KEY_READ,
    hOpenKey) = ERROR_SUCCESS then begin
    // Reading an Integer value
    iType := REG_RZ;         // Type of data that is going to be read
    iSize := SizeOf(pcTemp); // Buffer for the value to read
    if RegQueryValueEx(hOpenKey, 'Integer Value', nil, @iType, @iI, @iSize) = ERROR_SUCCESS then
      MainForm.Height := iI;
    // Reading a string value
    if RegQueryValueEx(hOpenKey, 'String Value', nil, @iType, @pcTemp, @iSize) = ERROR_SUCCESS then
      MainForm.Caption := string(pcTemp);
    RegCloseKey(hOpenKey);
  end;
...

Special thanks to Joachim Schonart for pointing out the error in the old code!