Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Mp3FileUtils (https://www.delphipraxis.net/71449-mp3fileutils.html)

DelTurbo 2. Jul 2011 11:51

AW: Mp3FileUtils
 
Eventuell hilft es...
bei id3v2Tag.WriteToFile(Edit1.Text); kommt er mir MP3ERR_Cache zurück.

Gausi 2. Jul 2011 13:25

AW: Mp3FileUtils
 
Hm, kannst du da mal durchsteppen, weswegen er diesen Fehler zurückgibt? Der Fehler tritt generell auf, wenn das Cachen der Audiodaten fehlschlägt. Da der ID3v2tag am Anfang der Datei steht, muss der ggf. vergrößert werden, wenn mehr Daten gespeichert werden sollen, und auch das häufig vorhandene Padding nicht ausreicht. Dann wird zuerst der Audiodaten-teil in eine temporäre Datei kopiert. Der ID3ERR_Cache-Fehler wird ausgelöst, wenn der FileStream für die tmp-Datei nicht erzeugt werden konnte (also FileStream.Create fehlschlägt oder eine Exception auslöst), oder wenn die Daten nicht komplett kopiert wurden.

Ich hab das hier grade mal mit D7 Personal durchprobiert, hier das wird anstandslos gespeichert. :gruebel:

Die JPEG-Exception kommt im Debugger übrigens, weil die Demo dort unsauber programmiert ist. Da wird mit dem DatenStream, den GetPicture liefert, direkt ein JPEG.LoadFromStream durchgeführt. Ohne Kontrolle, ob da überhaupt was drin steckt. Der fehler wird ohne Debugger einfach durch einen (fast) leeren except-Block ignoriert. ;-)

DelTurbo 2. Jul 2011 13:37

AW: Mp3FileUtils
 
Jop, ich war schon am Tracen. Warum das so ist, wie es ist.... frag mich bitte nicht. Vielleicht hast du eine erklärung.

In der Mp3Utils.Pas Zeile 1890 willst du vom Stream ende, 128 Bytes zurück. Und genau da scheppert es. Ich habe das wie folgt geändert und nun geht es.

Alt:
Delphi-Quellcode:
Stream.Seek(-128, soFromEnd);


Neu:
Delphi-Quellcode:
Stream.Seek(Stream.Size-128, soFromBeginning);


Irgendwie gehört das wieder zu den sachen die ich nicht kapiere. Vielleicht hast du ja eine erklärung. Mir fällt dazu nix ein :cry:

Trotzdem vielen dank für deine mühe.

Edit: Mit der DelphiVersion mit der ich arbeite kann es eigentlich nix zu haben. Ich habe es auf 3 Rechnern Probiert.

Edit2:
Ich habe mir das mal in Assembler angesehen. Es ist auf beiden Rechnern (D7,D2009) gleich.
004806EE 66B90200 mov cx,$0002
004806F2 BA80FFFFFF mov edx,$ffffff80
004806F7 8B45EC mov eax,[ebp-$14]
004806FA 8B30 mov esi,[eax]
004806FC FF5614 call dword ptr [esi+$14]

In cx steh das Kommando. Bei uns 2 für soFromEnd. In edx steht $ffffff80, also 128 zurück. eax wird der Pointer sein. Ich weiss wirklich nicht warum das nicht klappt. Auch der call zeigt richtig in TStream.Seek.

Beide Rechner laufen unter Windows XP mit SP3.

DelTurbo 4. Jul 2011 11:53

AW: Mp3FileUtils
 
Rückmeldung:
Ich habe grade mal aus neugierde ein "sauberes" Windows XP-SP3 genommen, Delphi 7 installiert und deine Demo übersetzt. Läuft einwandfrei. :thumb:

Was ich auf meinem PC, Laptop und in der Virtuellen installiert habe, das es nicht geht weiss ich leider nicht. Ich müsste nun nach und nach alles nachinstallieren um zu sehen wer da mist baut. Bei sowas kann man natürlich lange suchen.... :(

Vielen dank nochmal und netten Gruss

juergen 23. Jul 2011 11:34

AW: Mp3FileUtils
 
Hallo Gausi,

zuerst einmal meinen Respekt für deine Arbeit zu diesem Projekt und dem Bereitstellen als offenen Code! :thumb:
Als einfacher Hobbyprogrammierer konnte ich einiges aus deinem Projekt lernen. :-D

Ich habe jetzt das Problem, dass anscheinend bei einer variablen Bitrate > 256 kbps der ausgelesene Wert der Bitrate aus den MPEG-Informationen falsch ist.
Oft wird nur ein ca. ein 10tel der echten Bitrate angezeigt.
Mir ist das aufgefallen, weil anscheinend Amazon die Bitrate seiner MP3-Lieder erhöht hat.
In diversen Playern wird die richtige Bitrate angezeigt.

Hast du hier eine Idee woher das kommen kann?

Im Rahmen meiner Möglichkeiten stehe ich natürlich gern für Nachfragen, Tests oder dergeleichen zur Verfügung.

Ps.: ich bin mir nicht ganz sicher, meine aber, dass das früher mal richtig angezeigt wurde.

Gausi 23. Jul 2011 12:42

AW: Mp3FileUtils
 
Hm. Ich habe bisher nur einmal ein Album bei Amazon gekauft, und das hatte konstant 256kbps. Von daher wieder meine Standard-Bitte: Schick mir mal ein oder zwei dieser Dateien, damit ich da mal durchsteppen kann, was da schiefläuft. :)

Adresse ist "mail ÄTT gausi PUNKT de"

juergen 23. Jul 2011 12:55

AW: Mp3FileUtils
 
Email mit einer Beispiel-Mp3-Datei ist unterwegs...
Musik ist natürlich Geschmacksache. :)

Hatte gerade festgestellt dass auch die Liedlänge um Faktor 9 zu lang angezeigt wird.

juergen 23. Jul 2011 14:00

AW: Mp3FileUtils
 
Hallo Gausi,

es tut mir wirklich leid!:oops:
Der Fehler lag bei mir!

Ich hatte gerade in deinen Demos nachgeschaut und da waren die Anzeigen richtig. Also musste es bei mir liegen.

Im Zuge von "Aufräumaktionen" in meinem Code vor ca. 4 Wochen hatte ich dabei an 2 Stellen die Reihenfolge vertauscht gehabt.:oops:

Delphi-Quellcode:
    Id3v2Tag.ReadFromStream(stream); // <= das hatte ich direkt vor "MpegInfo.LoadFromStream(stream)" stehen und deswegen war bei mir der Fehler...
    // an das Ende des Tags springen
    if not Id3v2Tag.exists then
      stream.Seek(0, sobeginning)
    else stream.Seek(Id3v2Tag.size, soFromBeginning);

    MpegInfo.LoadFromStream(stream);
    stream.Free;
Bitte sieh mir meine nicht vollständige Überprüfung meines Codes nach.:stupid:
Danke!

Ich wünsche allen ein schönes Wochenende!

Gausi 23. Jul 2011 14:20

AW: Mp3FileUtils
 
Danke für die Datei. Bei mir wird alles richtig angezeigt, aber ich kann die falsche Anzeige reproduzieren und kann bestätigen, dass das vorher richtig angezeigt wurde. Der Fehler liegt nämlich nur zum Teil bei dir. ;-)

Problem ist hier tatsächlich das Auslesen des ID3-Tags. Ich habe da in der letzten Version beim Einlesen des Tags etwas geändert - anstatt jeden Frame des ID3-Tags einzeln aus dem orignal-Filestream einzulesen, wird erst der ganze Tag in einen Memorystream kopiert, und aus diesem Stream dann die Frames gelesen. Ich verspreche mir davon schnelleres Lesen bei Laufwerken im Netzwerk.

Problem ist, dass ich nach dem Lesen des Headers "Tag.Size"-Bytes in den Memorystream kopiere, aber den Header ja schon gelesen habe. Daher kopiere ich 10 Bytes zu viel, bin im Orignal-FileStream 10 Bytes zu weit hinten, und verpasse den Beginn des XING-Headers, in dem Infos über die variable Bitrate enthalten sind. Und dann wird angenommen, dass die ersten AudioFrames (Stille, also geringe Bitrate) als passend für die Datei genommen werden. Und da die Länge aus der Bitrate und Dateigröße berechnet wird, wär das dann auch geklärt.

Abhilfe für das Problem hast du ja schon selbst gefunden. :thumb:

MW97 12. Aug 2011 19:31

AW: Mp3FileUtils
 
Hallo gausi,

Ich finde deine Units echt toll, aber ich habe ein Problem mit deiner MP3FileUtils.
Ich habe den Code den du im Delphi-Treff im Tutorial geschrieben hast so umgeschrieben, dass ich ohne die Klasse TAudioFile auskomme und nur mit den Dateinamen arbeite. Das funktioniert auch alles sehr gut.
Aber wenn ich mit meinen Programm die Titelinformationen von vielen Dateien aktualisiere(Sie werden in Stringlisten gespeichert), steigt der Speicherverbracuh sehr stakt an. Die StringListen enthalten von Programmstart an schon die Titelinfos und werden beim Start nur aktualisiert.

Ich habe schon allesmögliche mit try finally und Free probiert, aber der Speicherverbracuh steigt von 2 auf 182 MB. (In den Stringlisten speichere ich nur Titel, Interpret und Spiellänge).
Kannst du mir da vielleicht weiterhelfen?
Schon mal Danke im Vorraus.

MW97

DeddyH 12. Aug 2011 19:55

AW: Mp3FileUtils
 
Ich bin zwar nicht Gausi, aber das klingt danach, als ob Du immer wieder Objekte erzeugst, ohne sie anschließend freizugeben. Wie sieht denn Dein Code aus?

wicht 13. Aug 2011 09:39

AW: Mp3FileUtils
 
DeddyH könnte da gut recht haben, danach hört es sich an. Benutzt du evtl. FastMM mit den Einstellungen zum Debuggen auf aktiv? Solche Effekte bekomme ich damit nämlich zustande, auch wenn ich alles Freigebe. Hast du es mal mit ReportMemoryLeaksOnShutdown probiert? Damit würdest du eventuelle Leaks vermutlich schnell finden.

MW97 13. Aug 2011 20:04

AW: Mp3FileUtils
 
Hier ist mein Code:

Delphi-Quellcode:
  //Typendeklaration für Bibliothek
  type
    TLibrary=record
      Files             :TStringList;//Damit ordne ich den Titelinfos die pfade zu
      Cols:Array[1..3] of TStringList;//Col[1] für Titel, Col[2] für Interpret, Col[3] für Spiellänge
      //...
  end;
 
  type
    TMainConfig=record
      Lib:TLibrary;
      //...
  end;
 
  //Typendeklaration für Titelinformationen
  type
    TAudioInf=record;
      Interpret: string;
      Titel   : string;
      Pfad    : string;
      Album   : string;
      Jahr    : string;
      Dauer   : integer;
  end;

  //Unit mit Prozeduren zum Auslesen der Infos (aus dem Delphitreff)
  unit UAudioInf;

  interface

  uses
   UTypes;

  procedure GetAudioInfo(FileName: string);
  procedure GetMp3Info;
  procedure GetWmaInfo;
  procedure SetUnknown;
  function GetPlaylistTitel:string;

var
  AudioInf: TAudioInf;

implementation

uses
  SysUtils, Mp3FileUtils, ATL_WMAfile, Classes;


//Hauptprozedur für Titelinformationen
procedure GetAudioInfo(FileName: string);
begin
  AudioInf.Pfad := filename;
  if (AnsiLowerCase(ExtractFileExt(FileName)) = '.mp3') then
    GetMp3Info
  else
    if AnsiLowerCase(ExtractFileExt(FileName)) = '.wma' then
      GetWMAInfo
    else
      SetUnknown;
  if AudioInf.Interpret='' then AudioInf.Interpret:='Unbekannter Interpret';
  if AudioInf.Album=''    then AudioInf.Album:='Unbekanntes Album';
  if AudioInf.Jahr=''     then AudioInf.Jahr:='unbekanntes Jahr';
end;

//Prozedur für Titelinformationen von MP3-Dateien
procedure GetMp3Info;
var
  MpegInfo: TMpegInfo;
  ID3v2Tag: TID3V2Tag;
  ID3v1tag: TID3v1Tag;
  Stream: TFileStream;
begin

  // Daten mit MP3FileUtils auslesen
  Mpeginfo:=TMpegInfo.Create;
  ID3v2Tag:=TID3V2Tag.Create;
  ID3v1tag:=TID3v1Tag.Create;
  Stream := TFileStream.Create(AudioInf.Pfad, fmOpenRead or fmShareDenyWrite);
  try
  id3v1tag.ReadFromStream(Stream);
  Stream.Seek(0, sobeginning);
  Id3v2tag.ReadFromStream(Stream);
  if Not id3v2Tag.exists then
    Stream.Seek(0, sobeginning)
  else
    Stream.Seek(id3v2tag.size, soFromBeginning);
  Mpeginfo.LoadFromStream(Stream);
  Stream.free;
  //Daten übertragen
  if mpeginfo.FirstHeaderPosition >- 1 then
  begin
    if id3v2tag.artist <> '' then
      AudioInf.Interpret := id3v2tag.artist
    else
      AudioInf.Interpret := id3v1tag.artist;
    if id3v2tag.Album <> '' then
      AudioInf.Album :=id3v2tag.Album
    else
      AudioInf.Album:=id3v1tag.Album;
    if id3v2tag.Year<> '' then
      AudioInf.Jahr:=id3v2tag.Year
    else
      AudioInf.Jahr:=id3v1tag.Year;
    if id3v2tag.title <> '' then
      AudioInf.Titel := id3v2tag.title
    else
      if id3v1tag.title <> '' then
        AudioInf.Titel := id3v1tag.title
      else
        AudioInf.Titel := ExtractFileName(AudioInf.Pfad);
    AudioInf.Dauer  := mpeginfo.dauer;
  end else
    SetUnknown;
  finally
  MpegInfo.Free;
  Id3v2Tag.Free;
  Id3v1Tag.Free;
  end;
end;

//Prozedur für Titelinformationen von WMA-Dateien
procedure GetWmaInfo;
var
  wmaFile: TWMAfile;
begin
  if Not FileExists(AudioInf.Pfad) then
  begin
    SetUnknown;
    exit;
  end;
  try
  wmaFile := TWMAFile.create;
  if wmaFile.ReadFromFile(AudioInf.Pfad) then
  begin
    if wmaFile.Title <> '' then
      AudioInf.Titel := wmaFile.Title
    else
      AudioInf.Titel := ExtractFilename(AudioInf.Pfad);
      AudioInf.Interpret := wmaFile.Artist;
      AudioInf.Dauer := Round(wmaFile.Duration);
      AudioInf.Album :=wmaFile.Album;
      AudioInf.Jahr :=wmaFile.Year;
  end else
    SetUnknown;
  finally
  wmaFile.Free;
  end;
end;

//Prozedur für Titelinformationen von unbekannten Dateien
procedure SetUnknown;
begin
  AudioInf.Titel := ExtractFileName(AudioInf.Pfad);
  AudioInf.Interpret := '';
  AudioInf.Dauer := 0;
end;

//Prozedur für Titelinformationen nach %Interpret%-%Titel%
function GetPlaylistTitel:string;
begin
  if Trim(AudioInf.Interpret)='' then
    result := AudioInf.Titel
  else
    result := AudioInf.Interpret + ' - ' + AudioInf.Titel;
end;
in meiner haupunit habe ich dann unter private ein TMainConfig-Objekt deklariert(ProConfig). Beim Programmstart werden die StringListen erstelt uns aus Dateien geladen.

Bei dieser Prozedur steigt dann der Speicherbedarf enorm an:
Delphi-Quellcode:
//Titelinformationen aktualisieren
procedure TForm1.LibRefreshInf(const Visualize: boolean);
var
  i, a, b: integer;
  Edited: boolean;
begin
  Edited:=false;
  if Visualize then
  begin
    Application.CreateForm(TFrmMakeUp, FrmMakeUp);
    FrmMakeUp.Show;
    FrmMakeUp.ChangesDone:=false;
  end;
  if ProConfig.Lib.Files.Count>0 then
  begin
    if Visualize then
    begin
      FrmMakeUp.ProgressBar1.Max:=ProConfig.Lib.Files.Count;
      FrmMakeUp.ProgressBar1.Position:=0;
    end;
    a:=0;
    for i:=ProConfig.Lib.Files.Count-1  downto 0 do
    begin
      if Visualize then
      begin
        inc(a);
        FrmMakeUp.ProgressBar1.Position:=a;
        FrmMakeUp.MainFile:=ProConfig.Lib.Files[i];
      end
      else
        Application.ProcessMessages;
      if FileExists(ProConfig.Lib.Files[i]) then
      begin
                  GetAudioInfo(ProConfig.Lib.Files[i]);
          if AudioInf.Titel<>ProConfig.Lib.Cols[1][i] then
          begin
            Edited:=true;
            ProConfig.Lib.Cols[1][i]:=AudioInf.Titel;
          end;
          if AudioInf.Interpret<>ProConfig.Lib.Cols[2][i] then
          begin
            Edited:=true;
            ProConfig.Lib.Cols[2][i]:=AudioInf.Interpret;
          end;
          if MsToMinuteSecond(AudioInf.Dauer*1000)<>ProConfig.Lib.Cols[3][i] then //MsToMinuteSecond wandelt
          begin                                                                  //Sekunden in Minute:Sekunde um
            Edited:=true;
            ProConfig.Lib.Cols[3][i]:=MsToMinuteSecond(AudioInf.Dauer*1000);
          end;
          end;
      if not FileExists(ProConfig.Lib.Files[i]) then
      begin
        ProConfig.Lib.Files.Delete(i);
        for b:=1 to 3 do
          ProConfig.Lib.Cols[b].Delete(i);
      end;
    end;
  end;
  if Visualize then
  begin
    FrmMakeUp.ChangesDone:=true;
    FrmMakeUp.Close;
  end;
end;
Wenn ich der Prozedur true übergebe zeigt sie mir eine kleine form, die den status anzeigt, aber auch wenn ich das ganze im hintergrund machen lasse (false übergeben) steigt der bedarf.

EDIT:Ich habe gerade einen sehr eigenartigen Effekt festgestellt: Wenn ich in der Bibliothek meines Player 224 Elemente habe(Count der Stringlisten=224, Bedarf beim Start~1,8MB) dann steigt der Bedarf der Anwendung beim ausführen der Prozedur LibRefreshInf nicht. Wenn es aber 1014 Titel sind(Bedraf bei Start ~2,5 MB), dann steigt auf auf 182 MB. ???

Luckie 13. Aug 2011 22:29

AW: Mp3FileUtils
 
Also ich würde als erste dem Code ein Refactoring unterwerfen. So, wie ich das sehen kann, scheint alles in der Unit des Formulares zu stecken. Dazu kommen anscheinend noch globale Variablen und globale Datenstrukturen, weil du da noch einfache Prozeduren und Funktionen hast, die nicht Methoden deiner Klasse sind. Ich würde das erst mal alles sauber in eine oder eventuell sogar mehrere Klassen kapseln und so die GUI von der Datenverarbeitung trennen. Das hilft später bei der Erweiterung, der Überarbeitung und auch jetzt beim Finden von Fehlern und Speicherlecks. Eventuell verschwindet er ja schon beim Refactoring, wenn du wieder mehr Übersicht über deinen Code hast. Weil das ist doch nicht alles oder wird nicht alles bleiben oder?

MW97 14. Aug 2011 11:34

AW: Mp3FileUtils
 
Nein, das ist nicht alles. Die Prozeduren zum Auslesen der Infos habe ich in eine eigene Klasse gepckt. Sie waren schon vorher in einer eigenen Unit. Aber es hat nichts geändert.

DeddyH 14. Aug 2011 11:37

AW: Mp3FileUtils
 
Wird Action im OnClose von FrmMakeUp auf caFree gestellt?

MW97 16. Aug 2011 14:01

AW: Mp3FileUtils
 
Ja, das ist so. Und er zeigt mir die Form ja auch nur an, wenn ich der Prozedur true übergebe. Wenn ich false übergebe, steigt der Speicherbedarf auch.

DeddyH 16. Aug 2011 14:02

AW: Mp3FileUtils
 
Wird noch an anderer Stelle dynamisch Speicher angefordert?

MW97 16. Aug 2011 14:09

AW: Mp3FileUtils
 
Ich habe in dem Programm einige andere kleine Formen, aber ich erstelle alle mit Application.CreateForm und bei OnClose ist Action überall auf caFree. Den record TAudioInf habe ich in eine Klasse umgeschrieben und die Prozeduren GetAudioInfo... dareingepackt. Ich habe dann in der Prozedur ein TAudioInf deklariert, es erstellt und gebe es mit try...finally und Free wieder frei.

DeddyH 16. Aug 2011 14:16

AW: Mp3FileUtils
 
Dann würde ich gern mal die Klasse TAudioInf sehen.

MW97 16. Aug 2011 14:20

AW: Mp3FileUtils
 
Delphi-Quellcode:
type
    TAudioInf=class
      private
        procedure GetMp3Info;
        procedure GetWmaInfo;
        procedure SetUnknown;
      public
        Interpret: string;
        Titel   : string;
        Pfad    : string;
        Album   : string;
        Jahr    : string;
        Dauer   : integer;

        //Titelinformationsprozeduren
        procedure GetAudioInfo(FileName: string);
        function GetPlaylistTitel: string;
  end;

DeddyH 16. Aug 2011 14:24

AW: Mp3FileUtils
 
Und die Implementation?

MW97 16. Aug 2011 14:24

AW: Mp3FileUtils
 
Delphi-Quellcode:
type
    TAudioInf=class
      private
        procedure GetMp3Info;
        procedure GetWmaInfo;
        procedure SetUnknown;
      public
        Interpret: string;
        Titel   : string;
        Pfad    : string;
        Album   : string;
        Jahr    : string;
        Dauer   : integer;

        //Titelinformationsprozeduren
        procedure GetAudioInfo(FileName: string);
        function GetPlaylistTitel:string;
  end;

implementation

uses
  SysUtils, Mp3FileUtils, ATL_WMAfile, Classes;

//*********************************
//Prozeduren für Titelinformationen
//*********************************

//Hauptprozedur für Titelinformationen
procedure TAudioInf.GetAudioInfo(FileName: string);
begin
  Pfad := filename;
  if (AnsiLowerCase(ExtractFileExt(FileName)) = '.mp3') then
    GetMp3Info
  else
    if AnsiLowerCase(ExtractFileExt(FileName)) = '.wma' then
      GetWMAInfo
    else
      SetUnknown;
  if Interpret='' then Interpret:='Unbekannter Interpret';
  if Album=''    then Album:='Unbekanntes Album';
  if Jahr=''     then Jahr:='unbekanntes Jahr';
end;

//Prozedur für Titelinformationen von MP3-Dateien
procedure TAudioInf.GetMp3Info;
var
  MpegInfo: TMpegInfo;
  ID3v2Tag: TID3V2Tag;
  ID3v1tag: TID3v1Tag;
  Stream: TFileStream;
begin
  // Daten mit MP3FileUtils auslesen
  Mpeginfo:=TMpegInfo.Create;
  ID3v2Tag:=TID3V2Tag.Create;
  ID3v1tag:=TID3v1Tag.Create;
  Stream := TFileStream.Create(Pfad, fmOpenRead or fmShareDenyWrite);
  try
  id3v1tag.ReadFromStream(Stream);
  Stream.Seek(0, sobeginning);
  Id3v2tag.ReadFromStream(Stream);
  if Not id3v2Tag.exists then
    Stream.Seek(0, sobeginning)
  else
    Stream.Seek(id3v2tag.size, soFromBeginning);
  Mpeginfo.LoadFromStream(Stream);
  Stream.free;
  //Daten übertragen
  if mpeginfo.FirstHeaderPosition >- 1 then
  begin
    if id3v2tag.artist <> '' then
      Interpret := id3v2tag.artist
    else
      Interpret := id3v1tag.artist;
    if id3v2tag.Album <> '' then
      Album :=id3v2tag.Album
    else
      Album:=id3v1tag.Album;
    if id3v2tag.Year<> '' then
      Jahr:=id3v2tag.Year
    else
      Jahr:=id3v1tag.Year;
    if id3v2tag.title <> '' then
      Titel := id3v2tag.title
    else
      if id3v1tag.title <> '' then
        Titel := id3v1tag.title
      else
        Titel := ExtractFileName(Pfad);
    Dauer  := mpeginfo.dauer;
  end else
    SetUnknown;
  finally
  MpegInfo.Free;
  Id3v2Tag.Free;
  Id3v1Tag.Free;
  end;
end;

//Prozedur für Titelinformationen von WMA-Dateien
procedure TAudioInf.GetWmaInfo;
var
  wmaFile: TWMAfile;
begin
  if Not FileExists(Pfad) then
  begin
    SetUnknown;
    exit;
  end;
  try
  wmaFile := TWMAFile.create;
  if wmaFile.ReadFromFile(Pfad) then
  begin
    if wmaFile.Title <> '' then
      Titel := wmaFile.Title
    else
      Titel := ExtractFilename(Pfad);
      Interpret := wmaFile.Artist;
      Dauer := Round(wmaFile.Duration);
      Album :=wmaFile.Album;
      Jahr :=wmaFile.Year;
  end else
    SetUnknown;
  finally
  wmaFile.Free;
  end;
end;

//Prozedur für Titelinformationen von unbekannten Dateien
procedure TAudioInf.SetUnknown;
begin
  Titel := ExtractFileName(Pfad);
  Interpret := '';
  Dauer := 0;
end;

//Prozedur für Titelinformationen nach %Interpret%-%Titel%
function TAudioInf.GetPlaylistTitel:string;
begin
  if Trim(Interpret)='' then
    result := Titel
  else
    result := Interpret + ' - ' + Titel;
end;

DeddyH 16. Aug 2011 14:29

AW: Mp3FileUtils
 
Auf den ersten Blick kann ich keine Ursache entdecken, zumindest solange keine Exceptions auftreten. Du hast aber nur eine Instanz von TAudioInf, oder?

MW97 16. Aug 2011 14:29

AW: Mp3FileUtils
 
In jeder Prozedur, in der ich Titelinformationen auslesen will, deklariere ich eine Instanz von TAudioInf, und gebe sie wieder frei.

DeddyH 16. Aug 2011 14:33

AW: Mp3FileUtils
 
Da kann ich Dir nur noch raten, FastMM zu installieren und dann ReportMemoryLeaksOnShutdown zu setzen. Damit bekommst Du zumindest heraus, ob wirklich alles sauber aufgeräumt wird und falls nicht, von welchem Typ die Objektleichen sind.

ereetzer 5. Sep 2011 10:39

AW: Mp3FileUtils
 
Hallo Gausi,

ich habe da eine Frage an:

angenommen, ich habe mehrere Bewertungen oder Lyrics, Kommentare, etc.
Wir kann ich denn festlegen, welcher davon in den meisten Programmen angezeigt wird. So wie ich das sehe, wird der erste gefundene
angezeigt?
Wie kann ich nun also die Reihenfolge im Tag ändern. So das also z.Bsp. der als 3. gespeicherte Kommentar als 1. gesichert wird?


Gruß
ereetzer

Gravitar 11. Feb 2013 09:52

AW: Mp3FileUtils
 
Hi,

kann es sein, dass die Mp3FileUtils nicht threadsicher sind?

Habe den merkwürdigen Effekt, dass beim Nutzen von Multithreading, die mp3-Dateien alle mit den gleichen Artist,Titel usw. Informationen überschrieben werden, obwohl ich nur die Lyrics schreibe.

Der Effekt tritt unabhängig davon auf, ob ich nun 10 Threads oder 500 Threads laufen habe.

DelTurbo 11. Feb 2013 10:25

AW: Mp3FileUtils
 
Ich glaube schon das es gehen muss. Da ja auch für jeden Thread ein TId3v2Tag erzeugt wird.

Gravitar 12. Feb 2013 18:29

AW: Mp3FileUtils
 
Ok, ziehe meine Anmerkung zum Thema "Multithreading" zurück. Ich habe einfach nicht daran gedacht, das IDTag vor dem Schreiben neu einzulesen. In der seriellen Abarbeitung entstand ja auch kein Problem, da ich erst eingelesen haben um zu prüfen, ob bereits lyrics vorhanden waren und danach dann geschrieben habe.

Im der Multithreading-Variante wird aber parallel zu unterschiedlichen Zeitpunkten geschrieben. Ohne direktes Einlesen im Thread wird dann der letzte eingelesene IDTag benutzt (meistens das letzte Lied aus der Liste) und damit alle mp3s mit diesen Informationen überschrieben.

Also, mein Fehler :pale:

Aber, MP3-FileUtils ist auf jeden Fall threadsicher, wie über 700 parallele Threads beweisen.:thumb:

Gausi 12. Feb 2013 19:36

AW: Mp3FileUtils
 
Threadsicher sollte das sein, wenn man unterschiedliche Objekte in unterschiedlichen Threads erzeugt. Allerdings muss man ggf. mit Bitmap-Routinen aufpassen, wenn man die Set/GetPicture-Methoden benutzt.

Ob 700 parallele Threads sinnvoll sind, steht aber noch auf einem ganz anderem Blatt. Da ist die CPU doch nur noch mit hin- und herwechseln beschäftigt. :roll:

juergen 25. Mai 2013 15:38

AW: Mp3FileUtils
 
Hallo Gausi,

mir fehlt momentan noch die Disk-Nummer bzw. CD-Nummer als MP3-Tag um Dateien anhand verschiedener MP3-Tag's umzubenennen.
Eine vorhandene Eigenschaft in deinen tollen Mp3FileUtils konnte ich nicht finden. In deiner Doku auf Seite 10 steht unter "Weitere Text-Informationen" etwas von weiteren Properties, welche über ID's gelesen oder gesetzt werden können. Ich weiß aber gar nicht ob ich da überhaupt richtig bin.
Siehst du eine Möglichkeit über deine Mp3FileUtils an die Disk-Nummer bzw. CD-Nummer ran zu kommen`?

Vielen Dank schon mal vorab!

ereetzer 25. Mai 2013 18:08

AW: Mp3FileUtils
 
Hallo,
das sollte der Text-Frame ID "IDv2_PARTOFASET" sein, meine ich?

Bsp.
GetText(IDv2_PARTOFASET)

gruß
ereetzer

Gausi 25. Mai 2013 19:11

AW: Mp3FileUtils
 
Jup, IDv2_PARTOFASET sollte passen. Wenn das für Dateinamen benutzt werden soll, muss man ggf. aufpassen, ob da einfach nur die Nummer drin steckt, oder etwas wie "1/2" (ist afaik die Regel)

juergen 26. Mai 2013 18:25

AW: Mp3FileUtils
 
ich kam erst jetzt zum Lesen...
Vielen Dank für die Hilfestellung und den Hinweis bezügl. der Schreibweise! :dp:

BlueStarHH 27. Mai 2013 14:34

AW: Mp3FileUtils
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,

tolles Projekt. Danke! Ich habe allerdings einen Fehler gefunden: Bei mehreren MP3-Dateien fehlt bei diversen Infos (Title, Artist) immer der erste Buchstabe. WinAmp und WindowsMediaPlayer zeigen die Tag-Infos richtig an. Unter http://www.file-upload.net/download-...certo.mp3.html eine Beispieldatei (Mozart, unterliegt nicht mehr dem Copyright. ACHTUNG: Download der MP3 Datei nur über den Button, wie er hier im Anhang abgebildet ist. Nicht dass jemand auf die Banner bei file-upload.net klickt und Mist runterlädt.) In dieser MP3 Datei ergibt

Delphi-Quellcode:
FTitle := Id3v2Tag.GetText(IDv2_TITEL);


"orn concerto" obwohl im Tag "horn concerto" steht. Das am Anfang h fehlt. Was muss ich machen, damit auch der erste Buchstabe mitkommt? Danke!

juergen 27. Mai 2013 19:11

AW: Mp3FileUtils
 
@BlueStarHH,

ich weiß jetzt nicht genau ob du "nur" auf den Umstand des evtl. fehlerhaften Auslesens von bestimmten Frame-ID's hinweisen möchtest oder ob du eine Lösung für dein Problem suchst. Bei Verfügbarkeit von Tags würde ich eher den "nativen" Tag verwenden und nicht über die Frame-ID gehen:
FTitle := Id3v2Tag.Title

Damit hatte ich noch keine Probleme. Evtl. sind hier auch die Post #48 und #49 interessant.

Edit: laut Bugfix ist mit Version 0.6 "Typ-Gemisch bei GetFrameLength" behoben. Welche Version nutzt du?

Gausi 27. Mai 2013 22:00

AW: Mp3FileUtils
 
Zitat:

Zitat von BlueStarHH (Beitrag 1216576)
Was muss ich machen, damit auch der erste Buchstabe mitkommt? Danke!

3 Möglichkeiten:

1. Auf ein Update von MP3fileUtils warten :stupid:
2. Vernünftige MP3s runterladen und nicht so einen Quatsch (keine Wertung der Musik, die Tags sind nicht valide)
3. Einen vernünftigen Grabber/Encoder nutzen, der standard-konforme Tags erzeugt.

Fehlerdetails: Der Tag in dem File enthält Unicode. Im ID3-Tag wird dazu vor der eigentlichen Text-Info ein Byte für die Kodierung benutzt.

Problem: Im ID3v2.3-Tag (hier vorhanden) gibt es nur "0" (für Ansi) und "1" (für Unicode). Nach ID3-Spezifikation gilt bei ID3v2.3:
Zitat:

Unicode strings must begin with the Unicode BOM ($FF FE or $FE FF) to identify the byte order
In der Datei wird "1" verwendet, also Unicode. Aber: das BOM fehlt. D.h. die ersten 2 Bytes (= der erste Buchstabe) werden als BOM interpretiert und somit verschluckt.

Abhilfe wäre, eine Heuristik einzuführen, d.h. wenn die ersten beiden Bytes weder FF FE noch FE FF sind, die korrekte Byteorder raten. :?

Insofern: Danke für die Datei und die Fehlermeldung. Ich schau mal, was ich da ändern kann. :thumb:

@juergen: Kann man machen, ändert aber nichts. Der getter für den Titel ruft GetText(IDv2_TITEL) auf. ;-)

BlueStarHH 28. Mai 2013 09:17

AW: Mp3FileUtils
 
Hallo Gausi,

danke für die Aufklärung. Die Tags alle nachträglich zu ändern wird nicht möglich sein. Daher würde ich es sehr gut finden, wenn Du eine Heuristik einbauen würdest. Ich habe jetzt noch andere Programm getestet wie z.B. http://www.mp3tag.de Auch die zeigen alle die Tags richtig an. Warum ein auf Mp3FileUtils basierendes Delphi-Programm es dann nicht macht, ist den Endanwendern nur schwer zu vermitteln. Deswegen warte ich gespannte auf ein Mp3FileUtils-Update. Ich bekomme eine Heuristik leider nicht selbst hin, sonst würde ich helfen.

Gausi 21. Jun 2013 20:36

AW: Mp3FileUtils
 
Ich hänge hier mal eine korrigierte Version der betreffenden Unit an. Ich habe es mir leicht gemacht, und die Unit so angepasst, dass die hier genannten Files korrekt eingelesen werden, d.h. wenn das BOM fehlt, obwohl es laut Flag eigentlich da sein sollte, dann wird die Datei so eingelesen, als wäre es richtig, dass es nicht da ist. D.h. als UTF-16BE.
Eine Heuristik, welche Byteorder (BE / LE) wahrscheinlicher ist, habe ich nicht eingeführt - halte ich auch für Overkill. Die Unit gibt es jetzt seit einigen Jahren, mein Player nutzt die auch. Ich bekomme durchaus regelmäßig Mails wegen dem - aber bisher noch nie, dass das erste Zeichen in den Infos fehlt. ;-)

Edit: Anhang entfernt, da fehlerhaft. Korrektur kommt bald :wall:


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:48 Uhr.
Seite 2 von 3     12 3      

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