Thema: Delphi WAV-Dateien und ID3Tag?

Einzelnen Beitrag anzeigen

Benutzerbild von Martin K
Martin K

Registriert seit: 20. Okt 2005
919 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: WAV-Dateien und ID3Tag?

  Alt 13. Aug 2007, 00:22
Erstmal vielen Dank an alle, die hier noch geantwortet haben, dachte nicht, dass ich noch so viel Hilfe bekomme
Auf Basis des Beitrags von Der_Unwissende hab ich mir mal was zurecht gebastelt, wäre nett wenn ihr mal drüber gucken könntet, vielleicht fällt euch noch was auf, was man anders/besser machen könnte, aber funktionieren tut es perfekt!
Um nicht die ganze Datei Byte für Byte nach einem "INFO" zu durchsuchen, hab ich einfach mal beim Dateiende minus einer Konstanten angefangen zu suchen, die Konstante erhält die in etwa maximale Größe des INFO List Chunks:
Delphi-Quellcode:
const
  MAX_LISTCHUNK_SIZE = 100000;


{ INFO List Chunk von einer Datei einlesen: die ChunkID und die einsprechende Beschreibung dazu werden in übergebenen TStrings gespeichert }

function ReadINFOListChunk(const FileName: string; var ChunkID, Description: TStrings): Boolean;
var Stream: TStream; i: Integer; s: array[0..3] of Char; sl: array[0..255] of Char;
begin
  s := #0#0#0#0;
  Result := False;
  Stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite);
  try
    Stream.Seek(-MAX_LISTCHUNK_SIZE, soFromEnd);
    // bis zu 'INFO' einlesen
    while Stream.Read(s, 1) = 1 do
      if s[0] = 'Ithen
      begin
        if Stream.Read(s, 3) = 3 then
        begin
          if (s = 'NFO') then Break
          else Stream.Seek(-3, soFromCurrent);
        end
        else Exit;
      end;
    if s <> 'NFOthen Exit;
    // INFO Chunk einlesen
    Result := True;
    while Stream.Read(s, 4) = 4 do
    begin
      ChunkID.Append(s); // Chunk ID
      if Stream.Read(i, 4) = 4 then
      begin
        if Stream.Read(sl, i) = i then
          Description.Append(sl) // Description
        else Exit;
      end
      else Exit;
      // Null-Bytes überspringen
      while (Stream.Read(s, 1) = 1) and (s[0] = #0) do
      begin end;
      Stream.Seek(-1, soFromCurrent);
    end;
  finally
    FreeAndNil(Stream);
  end;
end;


{ INFO List Chunk in eine Datei schreiben: die ChunkID und die einsprechende Beschreibung werden in TStrings übergebenen }

procedure WriteINFOListChunk(const FileName: string; const ChunkID, Description: TStrings);
var Stream: TStream; i, j: Integer;
begin
  // INFO List Chunk löschen, falls vorhanden
  RemoveINFOListChunk(FileName);
  Stream := TFileStream.Create(FileName, fmOpenReadWrite, fmShareDenyWrite);
  try
    Stream.Seek(0, soFromEnd);
    // Header schreiben
    Stream.Write('LIST:'+#0#0#0+'INFO', 12);
    for i := 0 to ChunkID.Count - 1 do
    begin
      Stream.Write(PChar(ChunkID[i])^, 4); // Chunk ID
      j := Length(Description[i]) + 1;
      Stream.Write(j, 4); // Länge
      Stream.Write(PChar(Description[i] + #0)^, j); // Description
    end;
  finally
    FreeAndNil(Stream);
  end;
end;


{ INFO List Chunk von einer Datei löschen }

function RemoveINFOListChunk(const FileName: string): Boolean;
var Stream: TStream; s: array[0..3] of Char;
begin
  s := #0#0#0#0;
  Result := False;
  Stream := TFileStream.Create(FileName, fmOpenReadWrite, fmShareDenyWrite);
  try
    Stream.Seek(-MAX_LISTCHUNK_SIZE, soFromEnd);
    // bis zu 'INFO' einlesen
    while Stream.Read(s, 1) = 1 do
      if s[0] = 'Ithen
      begin
        if Stream.Read(s, 3) = 3 then
        begin
          if (s = 'NFO') then Break
          else Stream.Seek(-3, soFromCurrent);
        end
        else Exit;
      end;
    if s <> 'NFOthen Exit;
    Stream.Seek(-12, soFromCurrent);
    // List Chunk enthält nur INFO -> kompletten List Chunk löschen
    if (Stream.Read(s, 4) = 4) and (s = 'LIST') then
      Stream.Size := Stream.Position - 4
    else
      Stream.Size := Stream.Position + 4;
    Result := True;
  finally
    FreeAndNil(Stream);
  end;
end;
Ach ja, eine ausführliche Erklärung zu den einzelnen Chunk ID's lässt sich hier finden, unter dem Absatz "INFO List Chunk".

Hier noch Beispiele zur Anwendung:
Delphi-Quellcode:
procedure TForm1.ButtonReadClick(Sender: TObject);
var ChunkID, Description: TStrings; i: Integer; s: String;
begin
  ChunkID := TStringList.Create;
  Description := TStringList.Create;
  try
    if ReadINFOListChunk('C:\test.wav', ChunkID, Description) then
    begin
      s := '';
      for i := 0 to ChunkID.Count - 1 do
        s := s + ChunkID[i] +#9+ Description[i] +#13#10;
      ShowMessage('Datei "C:\test.wav" enthält folgenden INFO List Chunk:' +#13#10#13#10+ s);
    end
    else
      ShowMessage('Datei "C:\test.wav" enthält keinen INFO List Chunk.');
  finally
    ChunkID.Free;
    Description.Free;
  end;
end;

procedure TForm1.ButtonWriteClick(Sender: TObject);
var ChunkID, Description: TStrings;
begin
  ChunkID := TStringList.Create;
  Description := TStringList.Create;
  try
    ChunkID.Add('IART');
    Description.Add('Interpret');
    ChunkID.Add('INAM');
    Description.Add('Titel');
    WriteINFOListChunk('C:\test.wav', ChunkID, Description);
  finally
    ChunkID.Free;
    Description.Free;
  end;
end;

procedure TForm1.ButtonRemoveClick(Sender: TObject);
begin
  if RemoveINFOListChunk('C:\test.wav') then
    ShowMessage('INFO List Chunk wurde gelöscht.')
  else
    ShowMessage('Kein INFO List Chunk vorhanden.');
end;
Im Anhang noch der Code als Unit:
Angehängte Dateien
Dateityp: pas infolistchunk_140.pas (3,4 KB, 13x aufgerufen)
Mit den Menschen ist es wie mit Computern -
es gibt Nullen und Einsen.
  Mit Zitat antworten Zitat