Hinweis: An dieser Stelle stand eine ganze Zeitlang ein anderer Beitrag. Im Laufe der Zeit habe ich diese Methode weiterentwickelt, Fehler ausgemerzt, große Teile neu oder umgeschrieben und die Verwendung vereinfacht. In der alten Fassung war immer noch eine gewisse Beschäftigung mit der Materie "mp3-Datei" nötig - das ist jetzt nicht mehr so.
Die alte Methode habe ich als .pas Datei im Anhang angefügt - kompilierfähig ist sie so aber nicht (es ist einfach nur ne Kopie des alten Beitrags). Dies nur für den unwahrscheinlichen Fall, dass sie noch von jemandem gebraucht wird.
In Absprache mit den Bibliothekaren habe ich diesen Beitrag hier komplett neu geschrieben.
Grundlage hierfür ist die Unit MP3FileUtils (die sich übrigens u.a. aus dem alten FAQ-Beitrag entwickelt hat). Diese Unit liest aus einem MP3File die ID3-Tags und die MPEG-Audio-Eigenschaften aus. Diese Unit steht unter der LGPL, daher unterliegt die Software, die diese Unit verwendet, gewissen Einschränkungen.
Man könnte hier auch einfach andere ID3- und MPEG-Units verwenden (ggf. muss man den dann Code leicht modifizieren oder einige Properties löschen), die ggf. nicht unter der LGPL oder Lizenzen mit ähnlichen Einschränkungen stehen.
Als Alternativen seien hier UltimaTag von tommie-lie oder die AudioToolsLibrary genannt (allerdings stehen auch diese unter der LGPL).
Die hier vorgestellte Klasse TAudioFile darf aber beliebig verwendet, modifiziert und verbreitet werden. Insbesondere dürfen weitere "GetXXXInfo"-Proceduren eingefügt werden.
Die Frage "Wie ermittle ich den Titel einer mp3-Datei?" ist insofern nicht ganz so einfach zu beantworten, weil in vielen mp3-Files der Titel und andere Infos zweimal gespeichert wird, und beide Versionen müssen nicht übereinstimmen. Es gibt einmal den ID3Tag in der Version 1, und dann gibt es den ID3Tag in der Version 2.
Dass es gewisse Unterschiede bei den Tags gibt, kann man z.B. dann bemerken, wenn eine mp3-CD im Mediaplayer "schöne Titel" hat, aber das Display des Autoradios nur den Dateinamen anzeigt, obwohl es eine ID3-Tag-Anzeige hat. Diese beschränkt sich nämlich häufig auf die Version 1, oftmals ist in mp3-Dateien aber nur der weitaus flexiblere v2-Tag vorhanden.
Häufig interessiert es einen aber nicht, ob der Titel nun im ID3v1, oder im ID3v2-Tag steht, oder ob der eine oder der andere enthalten ist. Wenn man z.B. einfach einen Player schreiben möchte, dann möchte man nur den "Titel" wissen, nicht den ID3v1-Titel.
Oftmals ist es sogar egal, ob man gerade ein Mp3-File, oder eine Ogg-Datei abspielt. In beiden Fällen möchte man in seinem Player grundlegende Eigenschaften dieser Audio-Datei ermitteln um diese anzuzeigen.
Ich habe mich daher entschieden, eine Klasse TAudioFile zu schreiben:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| TAudioFile = class private FPfad: string; FDateiname: string; FOrdner: string; FDateiGroesse: Integer;
FArtist: string; FTitel: string; FAlbum: string; FYear: string; FGenre: string; FKommentar: string; FLyrics: string;
FDauer: Integer; FBitrate: word; Fvbr: boolean; FChannelMode: String; FSamplerate:Integer;
procedure SetNA(filename: String);
procedure GetMp3Info(filename:string); public property Pfad: string read FDateiname; property Dateiname: string read FDateiname; property Ordner: string read FOrdner; property DateiGroesse: Integer read FDateiGroesse; property Artist: string read FArtist; property Titel: string read FTitel; property Album: string read FAlbum; property Year: string read FYear; property Genre: string read FGenre; property Kommentar: string read FKommentar; property Lyrics: string read FLyrics; property Dauer: Integer read FDauer; property Bitrate: word read FBitrate; property vbr: boolean read Fvbr; property ChannelMode: String read FChannelMode; property Samplerate:Integer read FSamplerate;
constructor create; destructor destroy; override; procedure GetAudioData(filename:string); end; |
Diese Klasse kann natürlich um weitere Eigenschaften erweitert werden, je nachdem, was man so für nötig hält.
Schon hier kann man erkennen, dass ich es darauf angelegt habe, die Klasse einfach erweiterbar zu halten.
Public ist nur eine Routine:
GetAudioData. Diese Routine ruft dann die richtige private-Routine auf, um aus einer Audio-Datei die gewünschten Informationen zu ermitteln - je nachdem, um welchen Dateityp es sich handelt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| procedure TAudioFile.GetAudioData(filename:string); begin try if (AnsiLowerCase(ExtractFileExt(filename)) = '.mp3') or (AnsiLowerCase(ExtractFileExt(filename)) = '.mp2') or (AnsiLowerCase(ExtractFileExt(filename)) = '.mp1') then GetMp3Info(Filename) else SetNA(filename);
except SetNA(filename); end; end; |
Wir beschränken uns hier auf Mp3-Dateien:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115:
| procedure TAudioFile.GetMp3Info(filename:String); var MpegInfo:TMpegInfo; ID3v2Tag:TID3V2Tag; ID3v1tag:TID3v1Tag; Stream: TFilestream; begin FPfad := filename; FOrdner := ExtractFileDir(filename); FDateiname := ExtractFileName(Pfad); if NOT FileExists(filename) then exit;
MpegInfo := TMpegInfo.Create; ID3v2Tag := TID3V2Tag.Create; ID3v1tag := TID3v1Tag.Create;
stream := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite); 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;
if mpeginfo.FirstHeaderPosition>-1 then begin if ID3v2Tag.artist <> '' then FArtist := ID3v2Tag.artist else if ID3v1tag.artist <> '' then FArtist := ID3v1tag.artist else FArtist := '';
if ID3v2Tag.title <> '' then FTitel := ID3v2Tag.title else if ID3v1tag.title <> '' then FTitel := ID3v1tag.title else FTitel := Dateiname;
if ID3v2Tag.album <> '' then FAlbum := ID3v2Tag.album else if ID3v1tag.album <> '' then FAlbum := ID3v1tag.album else FAlbum := '';
if ID3v2Tag.Year <> '' then FYear := ID3v2Tag.Year else if ID3v1tag.Year <> '' then FYear := ID3v1tag.Year else FYear := '';
if ID3v2Tag.genre <> '' then Fgenre := ID3v2Tag.genre else Fgenre := ID3v1tag.genre;
if ID3v2Tag.Comment <> '' then FKommentar := ID3v2Tag.Comment else if ID3v1tag.Comment <> '' then FKommentar := ID3v1tag.Comment else FKommentar := '';
FLyrics := ID3v2Tag.GetLyrics('*','*');
FDauer := MpegInfo.dauer; FBitrate := MpegInfo.bitrate; Fvbr := MpegInfo.vbr; FDateiGroesse := MpegInfo.FileSize; FSampleRate := MpegInfo.samplerate;
case MpegInfo.channelmode of 0: FChannelmode := 'Stereo'; 1: FChannelmode := 'Joint Stereo'; 2: FChannelmode := 'Dual Channel Stereo'; 3: FChannelmode := 'Mono'; else FChannelmode := 'Unknown'; end; end else begin SetNA(filename); end; MpegInfo.Free; Id3v2Tag.Free; Id3v1Tag.Free; end; |
Um nun in einer Anwendung den Titel eines Liedes anzeigen zu lassen, genügen vier einfache Zeilen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.Button1Click(Sender: TObject); var aAudioFile: tAudioFile; begin aAudioFile := TAudioFile.create; aAudioFile.GetAudioData('Test1.mp3'); showmessage(aAudioFile.Artist + ' - ' + aAudioFile.Titel); aAudioFile.Free; end; |
Die komplette Unit ist im Anhang, dort sind auch die Konstruktor, Destruktor und die SetNA-Prozedur mit drin. Einfach diese Unit im Projekt-Ordner speichern, in die Uses-Klausel aufnehmen und benutzen. Einfacher gehts kaum, oder?
Außerdem benötigt wird die Unit
MP3FileUtils.
We are, we were and will not be.