Länge einer MP3 Datei ermitteln

Das Drama beginnt von vorne – 8 Jahre später

Ich muss sagen ich habe für mich 2011 mit MCISendString eine ganz passable Lösung gefunden (-> Dauer einer MP3 Datei ermitteln) und bin damit auch ganz gut gefahren. Bis jetzt …

Ich habe vor einigen Monaten auf eine andere Qualitätsstufe im Lame umgestellt. War die alte schlecht? Nein. Warum habe ich mich dann nicht an ’never touch a running system‘ gehalten? Ehrlich gesagt: Ich weiß es nicht. Vermutlich war es einfach das Gewissen, dass gesagt hat: Die neue Methode ist einfach noch besser. Vielleicht hört man ja den Unterschied irgendwann mal. Wie auch immer. Jetzt, Monate später, erweist sich das für mich als großes Problem.

Ich war vor wenigen Tagen auf einem Konzert. Das Album dazu habe ich zu Hause. Ich wollte mir davon nochmal einen Song anhören. Also öffnete ich meinen CD-Manager und suchte einen Track heraus. Ich war etwas erstaunt: 16 Minuten Spieldauer? So lang kam mir der Titel live gar nicht vor. Und auch die anderen Titel der CD wurden oftmals mit 8 Minuten oder mehr dargestellt. Das kann doch theoretisch schon nicht mehr klappen. Ich ziehe die Datei in den Winamp und schwupp. Hat sich die Spieldauer halbiert. F***.

Was das kurz gesagt heißt: Mein Skript, dass Fehler bei der Dauer korrigieren soll (früher primär Tippfehler, als die noch per Hand eingetragen wurden) funktioniert nicht mehr richtig (vermutlich mit dem neuen Format) und liefert falsche Werte. Noch schlimmer: Die falschen Werte wurden in meine Datenbank übernommen, wo bisher annähernd korrekte Werte standen.

Ursache

Die Ursache war klar. MCISendString scheint mit dem neuen VBR Header so seine Probleme zu haben. Aber glücklicherweise habe ich ja noch eine MP3-Tag Bibliothek eingebunden. Warum habe ich die eigentlich nicht zum ermitteln der Länge verwendet? Die Antwort war schnell gefunden: Weil die Bibliothek auch nicht immer korrekte Werte liefert. Die Bibliothek sucht im Header der MP3 Datei nach dem TLEN Frame in dem die Spieldauer in Millisekunden steht. Doch wenn dort 0 steht bekomme ich damit auch keine verlässlichen Werte.

Da stellt sich doch die Frage: Warum steht manchmal 0 und manchmal die korrekte Länge an der Stelle. Und das betrifft jetzt nicht nur aktuelle Dateien. Von 979 Tracks bei meinen Maxi CDs sind 411 Tracks davon betroffen. Manchmal nur ein Track einer CD. Manchmal alle. Hat der LAME Codec die am Ende nicht geschrieben? War es ein Bug im EAC? Beziehungsweise: Ist es immer noch ein Bug im Lame oder EAC? Denn bei der aktuellen CD, bei der ich das Problem entdeckt habe, ist die Information korrekt hinterlegt: Nur nicht beim letzten Track.
Wenn ich eine Tendenz abgeben müsste: Es ist gefühlt entweder die komplette CD oder der letzte Track betroffen.

Jetzt bin ich aber der Lösung noch keinen Schritt näher bekommen. In meiner akkurat gepflegten CD Datenbank stehen jetzt zahlreiche falsche Werte und ich habe keine einfache Möglichkeit das valide zu überprüfen.

Lösungsansätze

Es gibt im Tool MP3Tag diverse Funktionen mit denen man die Länge nachberechnen kann. Sympathisch ist mir hierbei die Variante die angebrochene Sekunden aufrundet. (-> MP3-Tag Forum)

1
2
3
$add($div($mul($div($sub(%_file_size_bytes%,%_tag_size%),%_bitrate%),8)
,1000),$ifgreater($mod($mul($div($sub(%_file_size_bytes%,%_tag_size%)
,%_bitrate%),8),1000),0,1,0))


Was aber auch heißen würde, ich müsste mit dem MP3Tag alle ID Tags nochmal neu schreiben bei den Tracks bei denen der Wert fehlt. Allerdings ist das auch der Vorschlag in vielen anderen Foren auch wenn die dafür vorgeschlagenen Tools immer andere sind.

Aber eigentlich habe ich ja ein Tool, dass für mich das ganze übernehmen soll. Ich will mich eigentlich nicht mit fehlenden Tag Informationen in der Datei herum ärgern. Und wenn ich ich das Skrip für den MP3-Tag so sehe, dann denke ich mir: An die Informationen müsste ich doch auch über die MP3-Bibliothek heran kommen, die ich im Moment nutze. Dann könnte ich dort, falls die Dauer im Tag nicht hinterlegt ist, diese anhand der vorliegenden Informationen berechnen? Ja, das geht in der Tat! Dabei ist mir auch aufgefallen, was scheinbar das Problem von MCISendString ist. Hier wird nur die Standard-Bitrate der MP3 zur Berechnung verwendet aber nicht die VBR Bitrate. Bei meiner Test-Datei war der Standard wohl 128 Kbit/s die VBR Bitrate 261 Kbits/s. Somit erklärt sich auch warum sich die Spieldauer in etwa immer verdoppelt.

Doch zurück zur Berechnung. Als ich die MP3 Bibliothek 2011 eingebunden habe ist mir ein Property in einer anderen Klasse nicht aufgefallen: „Duration“. Dort werden die Werte wohl auch berechnet oder der TLEN Tag genutzt oder dann am Ende eben 0 zurückgegeben.

Alte Fehler neu aufgewärmt

Ich dachte eigentlich, damit ist die Lösung klar. Ich nutzte die Länge, wenn sie vorhanden ist, ansonsten greife ich auf den berechneten Wert zurück, da dieser schon mal eine Sekunde mehr sein kann (durch die Berechnung anhand der Bitrate und der Bytes). Woran ich allerdings nicht mehr gedacht habe – und das war ja der Grund, warum ich auf MCISendString gegangen bin: Bei Enhanced CDs hat man beim letzten Track immer noch eine Differenz von 152 Sekunden – daran hatte ich nicht mehr gedacht. Gut, dass ich das vorher nochmal validiert habe, bevor ich das produktiv gestartet habe! Leider wird das aber sowohl bei der Property Lenght als auch bei der Property Duration falsch berechnet. Die Ursache ist schnell gefunden: Duration wird im Regelfall über die Property Length ermittelt.

Die Lösung für mich

Es war nicht einfach, doch ich habe jetzt eine Lösung, mit der ich leben kann. Der einzige Grund, warum ich diese Methode bei mir überhaupt implementiert habe war ja eigentlich um Tippfehler von damals automatisch zu korrigieren. Da ich jetzt aber beim digitalisieren die Dauer direkt von der CD auslese, ist die ‚Kontrolle‘ eigentlich nicht mehr notwendig. Allerdings finde ich es gut die Möglichkeit zu haben.
Daher sieht das Ganze nun wie folgt aus:

Hat die MP3 Datei einen VBR Header? Ja, dann nehmen wir den Wert aus der MP3 Bibliothek, sofern der nicht 0 ist. Liefert die Bibliothek keinen Wert zurück habe ich Pech gehabt.

Die MP3 hat keinen VBR Header? Dann nehmen wir den Wert der Bibliothek. Ist dieser 0 Sekunden, greife ich auf die klassische Methode über MCISendString zurück. Gibt es einen Wert, dann prüfen ich ob der vielleicht nur um eine Sekunde von MCISendString abweicht. Wenn dem so ist, nehme ich wieder den von MCISendString. Anderfalls nehme ich keine Änderung vor.

Für den Fall mit den 152 Sekunden prüfe ich einfach ob sich um den letzten Titel auf der CD handelt und der Wert um 151 – 153 Sekunden abweicht. Wenn dem so ist, nehme ich keine Änderung vor.

Am Ende hier nochmal der Links zur MP3-Bibliothek: https://sourceforge.net/projects/csid3lib/files/csid3lib/

Das nächste Projekt wäre dann zu prüfen ob ich bei den MP3 Dateien, die keine TLEN Tag haben, diesen ergänze 😉

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.