Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi WAV-Dateien und ID3Tag? (https://www.delphipraxis.net/97500-wav-dateien-und-id3tag.html)

Martin K 11. Aug 2007 16:37


WAV-Dateien und ID3Tag?
 
Hallo,
weiß jemand wie man ID3Tags aus wav-Dateien auslesen bzw. sie ändern kann?
Für MP3s hab ich entsprechende Units gefunden, aber das funzt leider nicht mit Wave-Dateien....

Andreas L. 11. Aug 2007 16:41

Re: WAV-Dateien und ID3Tag?
 
Ich wusste gar nicht das wav-Dateien auch ID3-Tags aufnehmen können.

Martin K 11. Aug 2007 16:45

Re: WAV-Dateien und ID3Tag?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ja, das wusste ich auch nicht, bis ich es selber gesehen habe.
Hier mal ein Beispiel als Anhang:
(WMP zeigt die Tags manchmal an, QuickTime zeigt sie immer an, Winamp nicht getestet)

Gausi 11. Aug 2007 16:55

Re: WAV-Dateien und ID3Tag?
 
In diesem File sind keine ID3Tags enthalten. Was dabei der eine oder andere Player manchmal anzeigt, sind wohl irgendwelche anderen Tags, die sich am Ende der Datei verstecken (im Hexeditor kann man das erkennen). Vielleicht hilft dir das hier weiter.

Martin K 11. Aug 2007 17:07

Re: WAV-Dateien und ID3Tag?
 
Ok, danke erstmal.
Dachte, das wären auch ID3-Tags.
Nur hab ich jetzt keine Ahnung, wie ich diesen "INFO List Chunk" auslesen kann oder viel wichtiger, ihn zu ändern bzw. komplett zu entfernen...

Der_Unwissende 11. Aug 2007 17:42

Re: WAV-Dateien und ID3Tag?
 
Zitat:

Zitat von Martin K
Ok, danke erstmal.
Dachte, das wären auch ID3-Tags.
Nur hab ich jetzt keine Ahnung, wie ich diesen "INFO List Chunk" auslesen kann oder viel wichtiger, ihn zu ändern bzw. komplett zu entfernen...

Hi,
einfach mal nach der Spezifiktion googlen bzw. dem Link folgen, der genannt wurde. Da findest Du die einzelne Elemente. Ohne mich selbst detailiert mit der richtigen Spezifikation beschäftigt zu haben, Grob haben sie wohl den Aufbau, dass sie durch ein "INFO" eingeleitet werden. Dem folgen Einträge in der Form <ID><Länge><Wert>, wobei ID eben die Art des Eintrags identifiziert, Länge ist ein 32 Bit Wert (Cardinal) der angibt, wie lang der zugehörige Eintrag ist, Wert enthält dann den String/Wert. Die Strings werden dabei (musst Du schauen ob in der Länge enthalten oder nicht) mit #0#0 beendet, dem folgt dann der nächste String.
An sich musst Du also nur schauen, ob es im unteren Teil der Wave-Datei eine INFO-Struktur gibt und Dir dann merken, wo der letzte Eintrag kommt, diesen Teil kannst Du löschen (z.B. durch einen Stream, aus dem Du alle Byte vor dieser Struktur und alle hinter der Struktur in einen neuen Stream kopierst). In diesem Fall endet die Datei sogar mit dieser Struktur, hier solltest Du aber lieber auf Nummer sicher gehen und Dich nicht darauf verlassen.
Um die Wave-Datei nicht unnötig zu durchsuchen solltest Du vielleicht schauen, ob Du der Wave-Spezifikation entnehmen kannst, wo der normale Wave-Teil endet und eben optionale Informationen beginnen.

Gruß Der Unwissende

dominikkv 11. Aug 2007 17:56

Re: WAV-Dateien und ID3Tag?
 
du kannst dir ja mal die ATL anschauen -> klick

semo 11. Aug 2007 20:33

Re: WAV-Dateien und ID3Tag?
 
schau dir mal im wiki den entsprechenden beitrag zu RIFF WAVE an.
da ist alles haargenau erklärt.
http://de.wikipedia.org/wiki/RIFF_WAVE

es gibt aber auch genug beispiele im netz.
google mal nach "delphi twave"

Martin K 13. Aug 2007 00:22

Re: WAV-Dateien und ID3Tag?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Erstmal vielen Dank an alle, die hier noch geantwortet haben, dachte nicht, dass ich noch so viel Hilfe bekomme :thumb:
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] = 'I' then
      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 <> 'NFO' then 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] = 'I' then
      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 <> 'NFO' then 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:

Der_Unwissende 13. Aug 2007 11:06

Re: WAV-Dateien und ID3Tag?
 
Hi,
auf den ersten Blick fällt mir auf, dass Du das Einlesen/Suchen nach dem Chunk nocht optimieren könntest. So kommt die Datei, die Du lesen möchtest ja von der Festplatte. So eine Festplatte ist etwas anders aufgebaut als der RAM, man hat nicht ganz so schön einen Wahlfreien Zugriff. Natürlich kannst Du ein beliebiges Datum lesen, aber dazu muss es erst auf der Platte gesucht werden. Insbesondere gehört dazu die Platzierung des Lesekopfes (besser gesagt der Leseköpfe) auf der richtigen Spur und dann muss die Platte auch noch warten, bis das richtige Datum unter dem Kopf ist. Einmal gefunden kann diese dann aber sehr sehr sehr schnell viele Daten lesen und als großen Strom weiterreichen. Es gibt aber an sich auch eine untere Grenze, die Blockgröße des Systems.
Worauf ich eigentlich hinaus möchte, nach dem 'I' byteweise zu suchen ist total ineffizient! Zwar greifen hier schon einige Caching-Mechanismen des OS, es wird eben ohnehin nicht nur ein Byte ausgelesen, aber etwas besser geht es, wenn Du hier einen Lesepuffer verwendest. Wenn Du von 100.000 Byte max. Größe ausgehst, könntest Du diese eigentlich schon komplett in den Speicher laden (sind knappe 98 KByte, die hat man ja doch noch frei). Der Vorteil liegt einfach darin, dass der ganze Overhead (ggf. Zugriff auf den Hintergrundspeicher, auslesen aus dem Stream, Stream.Position aktualisieren, ...) nun auf die 98 KByte aufgeteilt wird. Der Unterschied ist überraschend deutlich und sollte selbst bei Deiner kurzen Suchen (in nur 100.000 max. Schritten) spürbar oder zumindestens messbar sein.
An sich kannst Du aber auch die Suche nach dem 'Info' noch weiter vereinfachen. Das was Du aus dem Stream lädst sind erstmal nur rohe Bytes, die eben interpretiert werden. Ein String funktioniert auf die gleiche Art und Weise. Was Du also machen kannst ist einfach die Daten in einen Stream kopieren. Wichtig dabei, Du musst vorher die Länge des Strings setzen!

Grob geht das wie folgt:
Delphi-Quellcode:
function getInfoChunkPos(const buffer: TByteDynArray): Integer;
var s: String;
    index: Integer;
    count: Integer;
begin
  result := -1;
  index := 0;
 
  // über den ganzen Puffer laufen
  while (index < length(buffer)) and (result < 0) do
  begin
    // max. Länge durch 1024 oder noch nicht gelesene Daten im Puffer beschränken
    count := min(1024, length(buffer) - index);
    // Größe des String setzen
    setLength(s, count);
    // Daten aus dem Puffer in den String kopieren
    move(buffer[index], s[1], count);
    // neuen Startindex im Puffer setzen
    inc(index, count);

    // mit dem String arbeiten
    result := pos('Info', s) - 1;
  end;
end;
Ist jetzt ein einfaches Beispiel, bei dem Du ein beliebiges dyn. Array von Byte übergibst (z.B. aus einer Wave-Datei). In einer Schleife werden immer in 1024-Byte-Happen die Daten aus dem Puffer in einen String kopiert (optimieren kannst Du das natürlich, wenn Du sicherstellst, dass der Puffer ein vielfaches von 1024 ist!). Auf den String wird dann die Pos-Funktion angewendet, die Dir den Index des ersten Vorkommens des Substrings 'Info'. Das zusätzliche -1 bei der letzten Zuweisung kommt daher, dass ein String immer 1 indiziert ist, das erste Element in einem Stream/dyn. Array/... aber immer die 0 bekommt. Somit wäre die Position hier um 1 versetzt.
Ob 1024 hier eine gute Größe ist, darüber lässt sich natürlich streiten. Zudem solltest Du natürlich beachten, dass man den String in zwei Teilen aus dem Puffer holen kann, also ein String mit 'Inf' endet und das erste Zeichen des nächsten Strings dann eben mit 'o' beginnt. Um das zu vermeiden sollte man bessert inc(index, count - 4) verwenden, das sollte sicherstellen, dass das Ende des Vorgängerstrings noch mit berücksichtigt wird.

Ansonsten sieht der Code doch ganz ordentlich aus, ein paar Kleinigkeiten gibt es natürlich dennoch (nichts Wildes!). Zum Beispiel kannst Du bei lokalen Variablen wie dem Stream auf das FreeAndNil verzichten. Wird eine Referenz nach ihrer Freigabe eh nicht mehr erreicht, reicht auch ein Free. Es schadet aber auch nichts zusätzlich die Referenz auf NIL zu setzen. Auch der Typ der Variable Stream kann direkt als TFileStream gesetzt werden. Stream verwendet man eigentlich immer dort, wo es einem völlig egal ist, was für ein Stream übergeben wird. macht auch hier nichts, Du könntest eben nur nicht auf Besonderheiten eines TFileStream (ohne Cast) zugreifen.
Die letzte Kleinigkeit, die noch am ehesten berücksichtigt werden sollte ist die von Dir verwendete Sperre, wenn Du die Dateien veränderst. Beim Lesen ist das fmShareDenyWrite natürlich sinnvoll, da Du so beliebig vielen Prozessen das Lesen ermöglichst. Aber wenn Du selbst die Datei schreibst, dann sollte möglichst kein anderer Prozess versuchen die Datei während dessen zu lesen. Was man sonst zu sehen bekommt kann eben doch irgendwas völlig Inkonsistentes sein. Besser wäre es, wenn Du hier gleich exklusiv (Lesen und Schreiben) sperrst (fmShareExclusive).

Gruß Der Unwissende

Martin K 13. Aug 2007 14:43

Re: WAV-Dateien und ID3Tag?
 
Okay, ich werden das dann mal versuchen umzusetzen, aber eine Frage noch:
Wie meinst du das mit den 1024 Byte einlesen?
Wenn ich die 100.000 Byte direkt von dem Stream in einem String lese, kann ich doch dann auch direkt in diesem String mit Pos() nach 'INFO' suchen, oder wird das "zu groß" für einen String?

Ein anderes Problem was ich noch überhaupt nicht berücksichtigt habe:
Ich gehe einfach davon aus, dass die Datei mit dem INFO Chunk endet und danach nichts mehr kommt.
Was aber wenn danach noch ein anderer Chunk kommt, der nicht zu dem INFO-Teil gehört?
Wie erkenne ich, ob ein anderer Chunk beginnt?
Oder ist das immer so, das der INFO Chunk ganz am Ende der Datei steht (was bei meinen Testdateien immer so war) ?

Der_Unwissende 13. Aug 2007 14:59

Re: WAV-Dateien und ID3Tag?
 
Zitat:

Zitat von Martin K
Wenn ich die 100.000 Byte direkt von dem Stream in einem String lese, kann ich doch dann auch direkt in diesem String mit Pos() nach 'INFO' suchen, oder wird das "zu groß" für einen String?

Genau hier liegt das Problem, es ist immer sehr schwer eine pauschale Grenze anzugeben. Das kann schon mit der Größe der jeweiligen Caches und der entsprechenden Strategie Deiner CPU variieren, wo die optimale Größe liegt, vom Algorithmus abhängen und natürlich von der Größe des Perfomance-Unterschieds (in den meisten Fällen sind ein paar zig-ms mehr oder weniger egal, woanders zählt jede ns).

Zitat:

Zitat von Martin K
Ein anderes Problem was ich noch überhaupt nicht berücksichtigt habe:
Ich gehe einfach davon aus, dass die Datei mit dem INFO Chunk endet und danach nichts mehr kommt.
Was aber wenn danach noch ein anderer Chunk kommt, der nicht zu dem INFO-Teil gehört?
Wie erkenne ich, ob ein anderer Chunk beginnt?
Oder ist das immer so, das der INFO Chunk ganz am Ende der Datei steht (was bei meinen Testdateien immer so war) ?

Das wurde schon angesprochen, Du müsstest Dich hier schlau machen, wie eine WAVE-Datei aufgebaut ist. Hat die z.B. einen Header, der die Größe der Chunks angibt, eine Art TOC oder auch einen Footer, der immer angibt wie groß das vorhergehende Chunk ist? Sowas kannst Du immer der entsprechenden Spezifikation entnehmen. Leichter und sinnvoller ist es aber allemal, dass man hier auf bestehende Komponenten zurückgreift (soweit vorhanden). Da wurde (wenn ich mich recht entsinne) auch schon in diesem Thread auf ein paar hingewiesen, die solltest Du Dir dann einfach mal anschauen.

Gruß

Martin K 13. Aug 2007 15:09

Re: WAV-Dateien und ID3Tag?
 
Ja unter dieser URL gibt es eine Unit WAVfile.pas, doch leider weiß ich damit nichts so recht anzufangen. Wenn ich das richtig sehe, kann man hier nur allgemeine Infos zur WAV-Datei auslesen (Bitrate, Anzahl der Kanäle und so), aber wie man damit die Position des INFO Chunk oder ähnliches erhalten soll?!?

Der_Unwissende 13. Aug 2007 15:41

Re: WAV-Dateien und ID3Tag?
 
Zitat:

Zitat von Martin K
aber wie man damit die Position des INFO Chunk oder ähnliches erhalten soll?!?

Das kannst Du dem Link zum Wiki-Eintrag entnehmen. Eine Wave-Datei hat einen recht einfachen Aufbau, Du hast einen Header "RIFF"<Größe der Datei>"WAVE", dem folgen dann die Chunks in der Form <ChunkID><Größe><Daten>. ChunkID ist dabei genau wie die Größe immer exakt 4 Byte groß. Während Du die ID also einfach in einen String der Länge 4 einlesen kannst, kannst Du die Größe in ein Cardinal einlesen.
Entsprechend kannst Du die Wave-Datei auf vorhandene INFO-Chunks prüfen, ungetestet ungefähr so:

Delphi-Quellcode:
function hasInfoChunk(const file: TStream): Boolean;
var ChunkId: String;
    count: Cardinal;
begin
  result := false;
  setLength(ChunkId, 4);

  // Prüfen ob Datei größer als Header (12 Byte) und erstes Chunk (mind. 8 Byte)
  if (file.size >= 20) then
  begin
    while (file.Position + 8 < file.Size) and (not result) do
    begin
      file.Position := 16;
      file.Read(ChunkId, 4);
      file.Read(count, 4);
 
      // prüfen ob das gelesene Chunk ein Info-Chunk ist
      if ChunkId = 'Info' then
      begin
        result := true;
      end
      else
      begin
        file.Position := file.Position + count;
      end;
    end;
  end;
end;
So ganz grob sollte das klappen. Natürlich ist auch hier das lesen von 2x4 Zeichen nicht wirklich effizient, nur werden mehr Zeichen nicht betrachtet. Besser wäre es sicherlich trotzdem einen Puffer von 8 Byte zu verwenden und die Daten dann in die Variablen zu kopieren, aber das ist eine andere Sache. Hier greift (hoffentlich) die Compileroptimierung und passt das gleich sinnvoll an.

Jedenfalls kannst Du auf die gleiche Art auch den Offset zu dem entsprechenden Chunk zurückgeben lassen, das wäre eben File.Position - 8 (da Du ja mit ChunkId und Count schon weiter gelaufen bist) und könntest so auch gleich das ganze Chunk entfernen (alles bis dorthin und alles dahinter - count sagt Dir ja wie groß das Chunk ist - abschneiden/rauskopieren, Du weißt schon.

Martin K 13. Aug 2007 16:00

Re: WAV-Dateien und ID3Tag?
 
Hmm, gut gut...
Du hast mir wirklich sehr viel geholfen.
Werde mich heute Abend vielleicht nochmal näher damit beschäftigen.
Danke erstmal!
Leider hab ich nicht immer so die Zeit...
Wenn es geht, würde ich viel mehr Zeit mit Programmieren und hier im Forum verbringen.

Martin K 13. Aug 2007 23:52

Re: WAV-Dateien und ID3Tag?
 
So, hab jetzt erstmal das Lesen des INFO Chunks komplett überarbeitet.
Ich springe jetzt nicht mehr 100000 Bytes vom Dateiende rückwärts, sondern lese sauber ein, wie viel Bytes die anderen Chunks der WAV-Datei groß sind und überspringe sie.
Des weiteren berücksichtige ich auch, dass der LIST Chunk nicht nur den INFO Chunk enthalten kann, sondern auch noch andere List Chunks.
(der INFO Chunk wird mit einem INFO eingeleitet und ist dann zuende, wenn die Chunk ID nicht mehr mit einem 'I' beginnt, denn alle Chunk IDs des INFO Chunks beginnen mit einem 'I')

Außerdem hab ich der Einfachheit halber mal die Funktionen ReadID und ReadSize ausgelagert.
ReadID liest die ID (Name) eines Chunks ein (4-Byte String)
ReadSize liest die Größe des folgenden Blocks ein (4-Byte Integer, folgt auf die ID)

Delphi-Quellcode:
type
  String4 = array[0..3] of Char;


function ReadINFOListChunk(const FileName: string; var ChunkID, Description: TStrings): Boolean;
var Stream: TFileStream;

  function ReadID: String4;
  begin
    if Stream.Read(Result, 4) <> 4 then
      raise Exception.Create('Invalid WAVE Format');
  end;

  function ReadSize: Cardinal;
  begin
    if Stream.Read(Result, 4) <> 4 then
      raise Exception.Create('Invalid WAVE Format');
  end;

var EndPos: Cardinal; // gibt die Endposition des LIST Chunks an
    chunk: String4; // zum Speichern der Chunk ID
    desc: array[0..255] of Char; // zum Einlesen der Beschreibung
begin
  Result := False;
  Stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite);
  try
    // allgemeiner Header für WAV-Dateien
    if (ReadID <> 'RIFF') or (ReadSize <> Stream.Size - 8) or (ReadID <> 'WAVE') then
      raise Exception.Create('Invalid WAVE Format');
    // zum LIST Chunk springen
    while (Stream.Position < Stream.Size) and (ReadID <> 'LIST') do
      Stream.Seek(ReadSize, soFromCurrent);

    if Stream.Position < Stream.Size then // enthält LIST Chunk
    begin
      EndPos := ReadSize + Stream.Position;
      // zum INFO Chunk springen
      while (Stream.Position < EndPos) and (ReadID <> 'INFO') do
        Stream.Seek(ReadSize, soFromCurrent);

      if Stream.Position < EndPos then // enthält INFO Chunk
      begin
        Result := True;
        chunk := ReadID;
        // INFO Chunks einlesen: ID muss mit 'I' beginnen
        while chunk[0] = 'I' do
        begin
          ChunkID.Append(chunk); // Chunk ID hinzufügen
          Stream.Read(desc, ReadSize); // Beschreibung auslesen
          Description.Append(desc); // Beschreibung hinzufügen
          // nächste Chunk ID einlesen, falls LIST Chunk noch nicht zuende
          if Stream.Position < EndPos then
            chunk := ReadID
          else
            Break;
        end;
      end;
    end;
  finally
    Stream.Free;
  end;
end;
Die Funktionen zum ändern und löschen werd ich dann morgen machen...

// Nachtrag:
Ich gehe mal davon aus, dass WAVE-Dateien nicht größer als 4 GB sind (also High(Cardinal)).
Das sollte eigentlich auch nicht möglich sein, da nach dem RIFF im Header ein 4-Byte Integer folgt, der die gesamte Dateigröße angibt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz