![]() |
AW: Mp3FileUtils
Eventuell hilft es...
bei id3v2Tag.WriteToFile(Edit1.Text); kommt er mir MP3ERR_Cache zurück. |
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. ;-) |
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. |
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 |
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. |
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" |
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. |
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:
Bitte sieh mir meine nicht vollständige Überprüfung meines Codes nach.:stupid:
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; Danke! Ich wünsche allen ein schönes Wochenende! |
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: |
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 |
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?
|
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.
|
AW: Mp3FileUtils
Hier ist mein Code:
Delphi-Quellcode:
in meiner haupunit habe ich dann unter private ein TMainConfig-Objekt deklariert(ProConfig). Beim Programmstart werden die StringListen erstelt uns aus Dateien geladen.
//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; Bei dieser Prozedur steigt dann der Speicherbedarf enorm an:
Delphi-Quellcode:
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.
//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; 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. ??? |
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?
|
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.
|
AW: Mp3FileUtils
Wird Action im OnClose von FrmMakeUp auf caFree gestellt?
|
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.
|
AW: Mp3FileUtils
Wird noch an anderer Stelle dynamisch Speicher angefordert?
|
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.
|
AW: Mp3FileUtils
Dann würde ich gern mal die Klasse TAudioInf sehen.
|
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; |
AW: Mp3FileUtils
Und die Implementation?
|
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; |
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?
|
AW: Mp3FileUtils
In jeder Prozedur, in der ich Titelinformationen auslesen will, deklariere ich eine Instanz von TAudioInf, und gebe sie wieder frei.
|
AW: Mp3FileUtils
Da kann ich Dir nur noch raten,
![]() |
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 |
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. |
AW: Mp3FileUtils
Ich glaube schon das es gehen muss. Da ja auch für jeden Thread ein TId3v2Tag erzeugt wird.
|
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: |
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: |
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! |
AW: Mp3FileUtils
Hallo,
das sollte der Text-Frame ID "IDv2_PARTOFASET" sein, meine ich? Bsp. GetText(IDv2_PARTOFASET) gruß ereetzer |
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)
|
AW: Mp3FileUtils
ich kam erst jetzt zum Lesen...
Vielen Dank für die Hilfestellung und den Hinweis bezügl. der Schreibweise! :dp: |
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 ![]()
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! |
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? |
AW: Mp3FileUtils
Zitat:
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:
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. ;-) |
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. ![]() |
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. |
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