![]() |
ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo erstmal,
ich schon wieder :-) Naja, wie gestern versprochen, hier der Source für mein Programm ![]() Nur mal kurz zu meinem Beweggründen, warum ich den Source hier rein stelle. Ihr (DP) habt mir schon ziemlich oft geholfen und ich hoffe natürlich das ihr das weiter so macht :-) Daher will ich anderen genauso die Chance geben etwas zu lernen bzw. zu verbessern. Schließlich muss man sich in einem solchen Forum helfen und helfen lassen (Nobody is perfect...) Ich habe den Source ein wenig abgespeckt, weil dort meine Kompos und ein ziemlich großer Standard von mir drinne war aber in dem nachfolgenden Beispiel ist alles gezeigt. Lesen und Schreiben des ID3v1 + ID3v2-Tag's und lesen des MPEG-Headers. Ihr werdet sicher damit etwas anfangen können (nachdem so viele gestern schon nach den Source gefragt haben :-) ) Wenn ihr Verbesserungen oder Änderungen am Source vornehmt, könnt ihr mir ja Bescheid sagen.Vielleicht hat es ja auch Nutzen für mich. MFG Alex ID3v1.pas
Delphi-Quellcode:
ID3v2.pas
unit ID3v1;
interface uses Classes, SysUtils; const MAX_MUSIC_GENRES = 148; DEFAULT_GENRE = 255; TAG_VERSION_1_0 = 1; TAG_VERSION_1_1 = 2; var MusicGenre: array [0..MAX_MUSIC_GENRES - 1] of string; type String04 = String[4]; String30 = String[30]; TID3v1 = class(TObject) private { Private declarations } FExists : Boolean; FVersionID : Byte; FTitle : String30; FArtist : String30; FAlbum : String30; FYear : String04; FComment : String30; FTrack : Byte; FGenreID : Byte; procedure FSetTitle (const NewTitle : String30); procedure FSetArtist (const NewArtist : String30); procedure FSetAlbum (const NewAlbum : String30); procedure FSetYear (const NewYear : String04); procedure FSetComment(const NewComment : String30); procedure FSetTrack (const NewTrack : Byte); procedure FSetGenreID(const NewGenreID : Byte); function FGetGenre: String; public { Public declarations } constructor Create; procedure ResetData; function ReadFromFile (const FileName: string): Boolean; function RemoveFromFile(const FileName: string): Boolean; function SaveToFile (const FileName: string): Boolean; property Exists : Boolean read FExists; property VersionID : Byte read FVersionID; property Title : String30 read FTitle write FSetTitle; property Artist : String30 read FArtist write FSetArtist; property Album : String30 read FAlbum write FSetAlbum; property Year : String04 read FYear write FSetYear; property Comment : String30 read FComment write FSetComment; property Track : Byte read FTrack write FSetTrack; property GenreID : Byte read FGenreID write FSetGenreID; property Genre : String read FGetGenre; end; { --------------------------------------------------------------------------- } implementation { --------------------------------------------------------------------------- } type TagRecord = record Header : array [1..3] of Char; Title : array [1..30] of Char; Artist : array [1..30] of Char; Album : array [1..30] of Char; Year : array [1..4] of Char; Comment : array [1..30] of Char; Genre : Byte; end; { --------------------------------------------------------------------------- } function ReadTag(const FileName: string; var TagData: TagRecord): Boolean; var SourceFile : File; begin try Result := true; AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); Seek(SourceFile, FileSize(SourceFile) - 128); BlockRead(SourceFile, TagData, 128); CloseFile(SourceFile); except Result := false; end; end; { --------------------------------------------------------------------------- } function RemoveTag(const FileName: string): Boolean; var SourceFile : File; begin {$IFDEF MSWINDOWS} try Result := true; FileSetAttr(FileName, 0); AssignFile(SourceFile, FileName); FileMode := 2; Reset(SourceFile, 1); Seek(SourceFile, FileSize(SourceFile) - 128); Truncate(SourceFile); CloseFile(SourceFile); except Result := false; end; {$ENDIF} end; { --------------------------------------------------------------------------- } function SaveTag(const FileName: String; TagData: TagRecord): Boolean; var SourceFile : File; begin try Result := true; FileSetAttr(FileName, 0); AssignFile(SourceFile, FileName); FileMode := 2; Reset(SourceFile, 1); Seek(SourceFile, FileSize(SourceFile)); BlockWrite(SourceFile, TagData, SizeOf(TagData)); CloseFile(SourceFile); except Result := false; end; end; { --------------------------------------------------------------------------- } function GetTagVersion(const TagData: TagRecord): Byte; begin Result := TAG_VERSION_1_0; if ((TagData.Comment[29] = #0) and (TagData.Comment[30] <> #0)) or ((TagData.Comment[29] = #32) and (TagData.Comment[30] <> #32)) then Result := TAG_VERSION_1_1; end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetTitle(const NewTitle: String30); begin FTitle := TrimRight(NewTitle); end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetArtist(const NewArtist: String30); begin FArtist := TrimRight(NewArtist); end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetAlbum(const NewAlbum: String30); begin FAlbum := TrimRight(NewAlbum); end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetYear(const NewYear: String04); begin FYear := TrimRight(NewYear); end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetComment(const NewComment: String30); begin FComment := TrimRight(NewComment); end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetTrack(const NewTrack: Byte); begin FTrack := NewTrack; end; { --------------------------------------------------------------------------- } procedure TID3v1.FSetGenreID(const NewGenreID: Byte); begin FGenreID := NewGenreID; end; { --------------------------------------------------------------------------- } function TID3v1.FGetGenre : String; begin Result := ''; if FGenreID in [0..MAX_MUSIC_GENRES - 1] then Result := MusicGenre[FGenreID]; end; { --------------------------------------------------------------------------- } constructor TID3v1.Create; begin inherited; ResetData; end; { --------------------------------------------------------------------------- } procedure TID3v1.ResetData; begin FExists := false; FVersionID := TAG_VERSION_1_0; FTitle := ''; FArtist := ''; FAlbum := ''; FYear := ''; FComment := ''; FTrack := 0; FGenreID := DEFAULT_GENRE; end; { --------------------------------------------------------------------------- } function TID3v1.ReadFromFile(const FileName: String): Boolean; var TagData : TagRecord; begin ResetData; Result := ReadTag(FileName, TagData); if (Result) and (TagData.Header = 'TAG') then begin FExists := true; FVersionID := GetTagVersion(TagData); FTitle := TrimRight(TagData.Title); FArtist := TrimRight(TagData.Artist); FAlbum := TrimRight(TagData.Album); FYear := TrimRight(TagData.Year); if FVersionID = TAG_VERSION_1_0 then FComment := TrimRight(TagData.Comment) else begin FComment := TrimRight(Copy(TagData.Comment, 1, 28)); FTrack := Ord(TagData.Comment[30]); end; FGenreID := TagData.Genre; end; end; { --------------------------------------------------------------------------- } function TID3v1.RemoveFromFile(const FileName: String): Boolean; var TagData : TagRecord; begin Result := ReadTag(FileName, TagData); if (Result) and (TagData.Header = 'TAG') then Result := RemoveTag(FileName); end; { --------------------------------------------------------------------------- } function TID3v1.SaveToFile(const FileName: String): Boolean; var TagData : TagRecord; begin FillChar(TagData, SizeOf(TagData), 0); TagData.Header := 'TAG'; Move(FTitle[1], TagData.Title, Length(FTitle)); Move(FArtist[1], TagData.Artist, Length(FArtist)); Move(FAlbum[1], TagData.Album, Length(FAlbum)); Move(FYear[1], TagData.Year, Length(FYear)); Move(FComment[1], TagData.Comment, Length(FComment)); if FTrack > 0 then begin TagData.Comment[29] := #0; TagData.Comment[30] := Chr(FTrack); end; TagData.Genre := FGenreID; Result := (RemoveFromFile(FileName)) and (SaveTag(FileName, TagData)); end; { --------------------------------------------------------------------------- } initialization begin MusicGenre[0] := 'Blues'; MusicGenre[1] := 'Classic Rock'; MusicGenre[2] := 'Country'; MusicGenre[3] := 'Dance'; MusicGenre[4] := 'Disco'; MusicGenre[5] := 'Funk'; MusicGenre[6] := 'Grunge'; MusicGenre[7] := 'Hip-Hop'; MusicGenre[8] := 'Jazz'; MusicGenre[9] := 'Metal'; MusicGenre[10] := 'New Age'; MusicGenre[11] := 'Oldies'; MusicGenre[12] := 'Other'; MusicGenre[13] := 'Pop'; MusicGenre[14] := 'R&B'; MusicGenre[15] := 'Rap'; MusicGenre[16] := 'Reggae'; MusicGenre[17] := 'Rock'; MusicGenre[18] := 'Techno'; MusicGenre[19] := 'Industrial'; MusicGenre[20] := 'Alternative'; MusicGenre[21] := 'Ska'; MusicGenre[22] := 'Death Metal'; MusicGenre[23] := 'Pranks'; MusicGenre[24] := 'Soundtrack'; MusicGenre[25] := 'Euro-Techno'; MusicGenre[26] := 'Ambient'; MusicGenre[27] := 'Trip-Hop'; MusicGenre[28] := 'Vocal'; MusicGenre[29] := 'Jazz+Funk'; MusicGenre[30] := 'Fusion'; MusicGenre[31] := 'Trance'; MusicGenre[32] := 'Classical'; MusicGenre[33] := 'Instrumental'; MusicGenre[34] := 'Acid'; MusicGenre[35] := 'House'; MusicGenre[36] := 'Game'; MusicGenre[37] := 'Sound Clip'; MusicGenre[38] := 'Gospel'; MusicGenre[39] := 'Noise'; MusicGenre[40] := 'AlternRock'; MusicGenre[41] := 'Bass'; MusicGenre[42] := 'Soul'; MusicGenre[43] := 'Punk'; MusicGenre[44] := 'Space'; MusicGenre[45] := 'Meditative'; MusicGenre[46] := 'Instrumental Pop'; MusicGenre[47] := 'Instrumental Rock'; MusicGenre[48] := 'Ethnic'; MusicGenre[49] := 'Gothic'; MusicGenre[50] := 'Darkwave'; MusicGenre[51] := 'Techno-Industrial'; MusicGenre[52] := 'Electronic'; MusicGenre[53] := 'Pop-Folk'; MusicGenre[54] := 'Eurodance'; MusicGenre[55] := 'Dream'; MusicGenre[56] := 'Southern Rock'; MusicGenre[57] := 'Comedy'; MusicGenre[58] := 'Cult'; MusicGenre[59] := 'Gangsta'; MusicGenre[60] := 'Top 40'; MusicGenre[61] := 'Christian Rap'; MusicGenre[62] := 'Pop/Funk'; MusicGenre[63] := 'Jungle'; MusicGenre[64] := 'Native American'; MusicGenre[65] := 'Cabaret'; MusicGenre[66] := 'New Wave'; MusicGenre[67] := 'Psychadelic'; MusicGenre[68] := 'Rave'; MusicGenre[69] := 'Showtunes'; MusicGenre[70] := 'Trailer'; MusicGenre[71] := 'Lo-Fi'; MusicGenre[72] := 'Tribal'; MusicGenre[73] := 'Acid Punk'; MusicGenre[74] := 'Acid Jazz'; MusicGenre[75] := 'Polka'; MusicGenre[76] := 'Retro'; MusicGenre[77] := 'Musical'; MusicGenre[78] := 'Rock & Roll'; MusicGenre[79] := 'Hard Rock'; MusicGenre[80] := 'Folk'; MusicGenre[81] := 'Folk-Rock'; MusicGenre[82] := 'National Folk'; MusicGenre[83] := 'Swing'; MusicGenre[84] := 'Fast Fusion'; MusicGenre[85] := 'Bebob'; MusicGenre[86] := 'Latin'; MusicGenre[87] := 'Revival'; MusicGenre[88] := 'Celtic'; MusicGenre[89] := 'Bluegrass'; MusicGenre[90] := 'Avantgarde'; MusicGenre[91] := 'Gothic Rock'; MusicGenre[92] := 'Progessive Rock'; MusicGenre[93] := 'Psychedelic Rock'; MusicGenre[94] := 'Symphonic Rock'; MusicGenre[95] := 'Slow Rock'; MusicGenre[96] := 'Big Band'; MusicGenre[97] := 'Chorus'; MusicGenre[98] := 'Easy Listening'; MusicGenre[99] := 'Acoustic'; MusicGenre[100]:= 'Humour'; MusicGenre[101]:= 'Speech'; MusicGenre[102]:= 'Chanson'; MusicGenre[103]:= 'Opera'; MusicGenre[104]:= 'Chamber Music'; MusicGenre[105]:= 'Sonata'; MusicGenre[106]:= 'Symphony'; MusicGenre[107]:= 'Booty Bass'; MusicGenre[108]:= 'Primus'; MusicGenre[109]:= 'Porn Groove'; MusicGenre[110]:= 'Satire'; MusicGenre[111]:= 'Slow Jam'; MusicGenre[112]:= 'Club'; MusicGenre[113]:= 'Tango'; MusicGenre[114]:= 'Samba'; MusicGenre[115]:= 'Folklore'; MusicGenre[116]:= 'Ballad'; MusicGenre[117]:= 'Power Ballad'; MusicGenre[118]:= 'Rhythmic Soul'; MusicGenre[119]:= 'Freestyle'; MusicGenre[120]:= 'Duet'; MusicGenre[121]:= 'Punk Rock'; MusicGenre[122]:= 'Drum Solo'; MusicGenre[123]:= 'A capella'; MusicGenre[124]:= 'Euro-House'; MusicGenre[125]:= 'Dance Hall'; MusicGenre[126]:= 'Goa'; MusicGenre[127]:= 'Drum & Bass'; MusicGenre[128]:= 'Club-House'; MusicGenre[129]:= 'Hardcore'; MusicGenre[130]:= 'Terror'; MusicGenre[131]:= 'Indie'; MusicGenre[132]:= 'BritPop'; MusicGenre[133]:= 'Negerpunk'; MusicGenre[134]:= 'Polsk Punk'; MusicGenre[135]:= 'Beat'; MusicGenre[136]:= 'Christian Gangsta Rap'; MusicGenre[137]:= 'Heavy Metal'; MusicGenre[138]:= 'Black Metal'; MusicGenre[139]:= 'Crossover'; MusicGenre[140]:= 'Contemporary Christian'; MusicGenre[141]:= 'Christian Rock'; MusicGenre[142]:= 'Merengue'; MusicGenre[143]:= 'Salsa'; MusicGenre[144]:= 'Trash Metal'; MusicGenre[145]:= 'Anime'; MusicGenre[146]:= 'JPop'; MusicGenre[147]:= 'Synthpop'; end; { --------------------------------------------------------------------------- } end.
Delphi-Quellcode:
MPEG-Header.pas
unit ID3v2;
interface uses Classes, SysUtils; const TAG_VERSION_2_2 = 2; TAG_VERSION_2_3 = 3; TAG_VERSION_2_4 = 4; type TID3v2 = class(TObject) private { Private declarations } FExists: Boolean; FVersionID: Byte; FSize: Integer; FTitle: string; FArtist: string; FAlbum: string; FTrack: Word; FTrackString: string; FYear: string; FGenre: string; FComment: string; FComposer: string; FEncoder: string; FCopyright: string; FLanguage: string; FLink: string; procedure FSetTitle(const NewTitle: string); procedure FSetArtist(const NewArtist: string); procedure FSetAlbum(const NewAlbum: string); procedure FSetTrack(const NewTrack: Word); procedure FSetYear(const NewYear: string); procedure FSetGenre(const NewGenre: string); procedure FSetComment(const NewComment: string); procedure FSetComposer(const NewComposer: string); procedure FSetEncoder(const NewEncoder: string); procedure FSetCopyright(const NewCopyright: string); procedure FSetLanguage(const NewLanguage: string); procedure FSetLink(const NewLink: string); public { Public declarations } constructor Create; procedure ResetData; function ReadFromFile (const FileName: string): Boolean; function SaveToFile (const FileName: string): Boolean; function RemoveFromFile(const FileName: string): Boolean; property Exists : Boolean read FExists; property VersionID : Byte read FVersionID; property Size : Integer read FSize; property Title : String read FTitle write FSetTitle; property Artist : String read FArtist write FSetArtist; property Album : String read FAlbum write FSetAlbum; property Track : Word read FTrack write FSetTrack; property TrackString : String read FTrackString; property Year : String read FYear write FSetYear; property Genre : String read FGenre write FSetGenre; property Comment : String read FComment write FSetComment; property Composer : String read FComposer write FSetComposer; property Encoder : String read FEncoder write FSetEncoder; property Copyright : String read FCopyright write FSetCopyright; property Language : String read FLanguage write FSetLanguage; property Link : String read FLink write FSetLink; end; { --------------------------------------------------------------------------- } implementation { --------------------------------------------------------------------------- } const ID3V2_ID = 'ID3'; ID3V2_FRAME_COUNT = 16; ID3V2_FRAME_NEW: array [1..ID3V2_FRAME_COUNT] of string = ('TIT2', 'TPE1', 'TALB', 'TRCK', 'TYER', 'TCON', 'COMM', 'TCOM', 'TENC', 'TCOP', 'TLAN', 'WXXX', 'TDRC', 'TOPE', 'TIT1', 'TOAL'); ID3V2_FRAME_OLD: array [1..ID3V2_FRAME_COUNT] of string = ('TT2', 'TP1', 'TAL', 'TRK', 'TYE', 'TCO', 'COM', 'TCM', 'TEN', 'TCR', 'TLA', 'WXX', 'TOR', 'TOA', 'TT1', 'TOT'); ID3V2_MAX_SIZE = 4096; UNICODE_ID = #1; { --------------------------------------------------------------------------- } type FrameHeaderNew = record ID : array [1..4] of Char; Size : Integer; Flags : Word; end; FrameHeaderOld = record ID : array [1..3] of Char; Size : array [1..3] of Byte; end; TagInfo = record ID : array [1..3] of Char; Version : Byte; Revision : Byte; Flags : Byte; Size : array [1..4] of Byte; FileSize : Integer; Frame : array [1..ID3V2_FRAME_COUNT] of string; NeedRewrite : Boolean; PaddingSize : Integer; end; { --------------------------------------------------------------------------- } function ReadHeader(const FileName: string; var Tag: TagInfo): Boolean; var SourceFile: file; Transferred: Integer; begin try Result := true; AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); BlockRead(SourceFile, Tag, 10, Transferred); Tag.FileSize := FileSize(SourceFile); CloseFile(SourceFile); if Transferred < 10 then Result := false; except Result := false; end; end; { --------------------------------------------------------------------------- } function GetTagSize(const Tag: TagInfo): Integer; begin Result := Tag.Size[1] * $200000 + Tag.Size[2] * $4000 + Tag.Size[3] * $80 + Tag.Size[4] + 10; if Tag.Flags and $10 = $10 then Inc(Result, 10); if Result > Tag.FileSize then Result := 0; end; { --------------------------------------------------------------------------- } procedure SetTagItem(const ID, Data: string; var Tag: TagInfo); var Iterator: Byte; FrameID: string; begin for Iterator := 1 to ID3V2_FRAME_COUNT do begin if Tag.Version > TAG_VERSION_2_2 then FrameID := ID3V2_FRAME_NEW[Iterator] else FrameID := ID3V2_FRAME_OLD[Iterator]; if (FrameID = ID) and (Data[1] <= UNICODE_ID) then Tag.Frame[Iterator] := Data; end; end; { --------------------------------------------------------------------------- } function Swap32(const Figure: Integer): Integer; var ByteArray: array [1..4] of Byte absolute Figure; begin Result := ByteArray[1] * $1000000 + ByteArray[2] * $10000 + ByteArray[3] * $100 + ByteArray[4]; end; { --------------------------------------------------------------------------- } procedure ReadFramesNew(const FileName: string; var Tag: TagInfo); var SourceFile: file; Frame: FrameHeaderNew; Data: array [1..500] of Char; DataPosition, DataSize: Integer; begin try AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); Seek(SourceFile, 10); while (FilePos(SourceFile) < GetTagSize(Tag)) and (not EOF(SourceFile)) do begin FillChar(Data, SizeOf(Data), 0); BlockRead(SourceFile, Frame, 10); if not (Frame.ID[1] in ['A'..'Z']) then break; DataPosition := FilePos(SourceFile); if Swap32(Frame.Size) > SizeOf(Data) then DataSize := SizeOf(Data) else DataSize := Swap32(Frame.Size); BlockRead(SourceFile, Data, DataSize); if Frame.Flags and $8000 <> $8000 then SetTagItem(Frame.ID, Data, Tag); Seek(SourceFile, DataPosition + Swap32(Frame.Size)); end; CloseFile(SourceFile); except end; end; { --------------------------------------------------------------------------- } procedure ReadFramesOld(const FileName: string; var Tag: TagInfo); var SourceFile: file; Frame: FrameHeaderOld; Data: array [1..500] of Char; DataPosition, FrameSize, DataSize: Integer; begin try AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); Seek(SourceFile, 10); while (FilePos(SourceFile) < GetTagSize(Tag)) and (not EOF(SourceFile)) do begin FillChar(Data, SizeOf(Data), 0); BlockRead(SourceFile, Frame, 6); if not (Frame.ID[1] in ['A'..'Z']) then break; DataPosition := FilePos(SourceFile); FrameSize := Frame.Size[1] shl 16 + Frame.Size[2] shl 8 + Frame.Size[3]; if FrameSize > SizeOf(Data) then DataSize := SizeOf(Data) else DataSize := FrameSize; BlockRead(SourceFile, Data, DataSize); SetTagItem(Frame.ID, Data, Tag); Seek(SourceFile, DataPosition + FrameSize); end; CloseFile(SourceFile); except end; end; { --------------------------------------------------------------------------- } function GetANSI(const Source: string): string; var Index: Integer; FirstByte, SecondByte: Byte; UnicodeChar: WideChar; begin if (Length(Source) > 0) and (Source[1] = UNICODE_ID) then begin Result := ''; for Index := 1 to ((Length(Source) - 1) div 2) do begin FirstByte := Ord(Source[Index * 2]); SecondByte := Ord(Source[Index * 2 + 1]); UnicodeChar := WideChar(FirstByte or (SecondByte shl 8)); if UnicodeChar = #0 then break; if FirstByte < $FF then Result := Result + UnicodeChar; end; Result := Trim(Result); end else Result := Trim(Source); end; { --------------------------------------------------------------------------- } function GetContent(const Content1, Content2: string): string; begin Result := GetANSI(Content1); if Result = '' then Result := GetANSI(Content2); end; { --------------------------------------------------------------------------- } function ExtractTrack(const TrackString: string): Word; var Track: string; Index, Value, Code: Integer; begin Track := GetANSI(TrackString); Index := Pos('/', Track); if Index = 0 then Val(Track, Value, Code) else Val(Copy(Track, 1, Index - 1), Value, Code); if Code = 0 then Result := Value else Result := 0; end; { --------------------------------------------------------------------------- } function ExtractYear(const YearString, DateString: string): string; begin Result := GetANSI(YearString); if Result = '' then Result := Copy(GetANSI(DateString), 1, 4); end; { --------------------------------------------------------------------------- } function ExtractGenre(const GenreString: string): string; begin Result := GetANSI(GenreString); if Pos(')', Result) > 0 then Delete(Result, 1, LastDelimiter(')', Result)); end; { --------------------------------------------------------------------------- } function ExtractText(const SourceString: string; LanguageID: Boolean): string; var Source, Separator: string; EncodingID: Char; begin Source := SourceString; Result := ''; if Length(Source) > 0 then begin EncodingID := Source[1]; if EncodingID = UNICODE_ID then Separator := #0#0 else Separator := #0; if LanguageID then Delete(Source, 1, 4) else Delete(Source, 1, 1); Delete(Source, 1, Pos(Separator, Source) + Length(Separator) - 1); Result := GetANSI(EncodingID + Source); end; end; { --------------------------------------------------------------------------- } procedure BuildHeader(var Tag: TagInfo); var Iterator, TagSize: Integer; begin TagSize := 10; for Iterator := 1 to ID3V2_FRAME_COUNT do if Tag.Frame[Iterator] <> '' then Inc(TagSize, Length(Tag.Frame[Iterator]) + 11); Tag.NeedRewrite := (Tag.ID <> ID3V2_ID) or (GetTagSize(Tag) < TagSize) or (GetTagSize(Tag) > ID3V2_MAX_SIZE); if Tag.NeedRewrite then Tag.PaddingSize := ID3V2_MAX_SIZE - TagSize else Tag.PaddingSize := GetTagSize(Tag) - TagSize; if Tag.PaddingSize > 0 then Inc(TagSize, Tag.PaddingSize); Tag.ID := ID3V2_ID; Tag.Version := TAG_VERSION_2_3; Tag.Revision := 0; Tag.Flags := 0; for Iterator := 1 to 4 do Tag.Size[Iterator] := ((TagSize - 10) shr ((4 - Iterator) * 7)) and $7F; end; { --------------------------------------------------------------------------- } function ReplaceTag(const FileName: string; TagData: TStream): Boolean; var Destination: TFileStream; begin Result := false; if (not FileExists(FileName)) or (FileSetAttr(FileName, 0) <> 0) then exit; try TagData.Position := 0; Destination := TFileStream.Create(FileName, fmOpenReadWrite); Destination.CopyFrom(TagData, TagData.Size); Destination.Free; Result := true; except end; end; { --------------------------------------------------------------------------- } function RebuildFile(const FileName: string; TagData: TStream): Boolean; var Tag: TagInfo; Source, Destination: TFileStream; BufferName: string; begin Result := false; if (not FileExists(FileName)) or (FileSetAttr(FileName, 0) <> 0) then exit; if not ReadHeader(FileName, Tag) then exit; if (TagData = nil) and (Tag.ID <> ID3V2_ID) then exit; try BufferName := FileName + '~'; Source := TFileStream.Create(FileName, fmOpenRead); Destination := TFileStream.Create(BufferName, fmCreate); if Tag.ID = ID3V2_ID then Source.Seek(GetTagSize(Tag), soFromBeginning); if TagData <> nil then Destination.CopyFrom(TagData, 0); Destination.CopyFrom(Source, Source.Size - Source.Position); Source.Free; Destination.Free; if (DeleteFile(FileName)) and (RenameFile(BufferName, FileName)) then Result := true else raise Exception.Create(''); except if FileExists(BufferName) then DeleteFile(BufferName); end; end; { --------------------------------------------------------------------------- } function SaveTag(const FileName: string; Tag: TagInfo): Boolean; var TagData: TStringStream; Iterator, FrameSize: Integer; Padding: array [1..ID3V2_MAX_SIZE] of Byte; begin TagData := TStringStream.Create(''); BuildHeader(Tag); TagData.Write(Tag, 10); for Iterator := 1 to ID3V2_FRAME_COUNT do if Tag.Frame[Iterator] <> '' then begin TagData.WriteString(ID3V2_FRAME_NEW[Iterator]); FrameSize := Swap32(Length(Tag.Frame[Iterator]) + 1); TagData.Write(FrameSize, SizeOf(FrameSize)); TagData.WriteString(#0#0#0 + Tag.Frame[Iterator]); end; FillChar(Padding, SizeOf(Padding), 0); if Tag.PaddingSize > 0 then TagData.Write(Padding, Tag.PaddingSize); if Tag.NeedRewrite then Result := RebuildFile(FileName, TagData) else Result := ReplaceTag(FileName, TagData); TagData.Free; end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetTitle(const NewTitle: string); begin FTitle := Trim(NewTitle); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetArtist(const NewArtist: string); begin FArtist := Trim(NewArtist); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetAlbum(const NewAlbum: string); begin FAlbum := Trim(NewAlbum); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetTrack(const NewTrack: Word); begin FTrack := NewTrack; end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetYear(const NewYear: string); begin FYear := Trim(NewYear); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetGenre(const NewGenre: string); begin FGenre := Trim(NewGenre); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetComment(const NewComment: string); begin FComment := Trim(NewComment); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetComposer(const NewComposer: string); begin FComposer := Trim(NewComposer); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetEncoder(const NewEncoder: string); begin FEncoder := Trim(NewEncoder); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetCopyright(const NewCopyright: string); begin FCopyright := Trim(NewCopyright); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetLanguage(const NewLanguage: string); begin FLanguage := Trim(NewLanguage); end; { --------------------------------------------------------------------------- } procedure TID3v2.FSetLink(const NewLink: string); begin FLink := Trim(NewLink); end; { --------------------------------------------------------------------------- } constructor TID3v2.Create; begin inherited; ResetData; end; { --------------------------------------------------------------------------- } procedure TID3v2.ResetData; begin FExists := false; FVersionID := 0; FSize := 0; FTitle := ''; FArtist := ''; FAlbum := ''; FTrack := 0; FTrackString := ''; FYear := ''; FGenre := ''; FComment := ''; FComposer := ''; FEncoder := ''; FCopyright := ''; FLanguage := ''; FLink := ''; end; { --------------------------------------------------------------------------- } function TID3v2.ReadFromFile(const FileName: string): Boolean; var Tag: TagInfo; begin ResetData; Result := ReadHeader(FileName, Tag); if (Result) and (Tag.ID = ID3V2_ID) then begin FExists := true; FVersionID := Tag.Version; FSize := GetTagSize(Tag); if (FVersionID in [TAG_VERSION_2_2..TAG_VERSION_2_4]) and (FSize > 0) then begin if FVersionID > TAG_VERSION_2_2 then ReadFramesNew(FileName, Tag) else ReadFramesOld(FileName, Tag); FTitle := GetContent(Tag.Frame[1], Tag.Frame[15]); FArtist := GetContent(Tag.Frame[2], Tag.Frame[14]); FAlbum := GetContent(Tag.Frame[3], Tag.Frame[16]); FTrack := ExtractTrack(Tag.Frame[4]); FTrackString := GetANSI(Tag.Frame[4]); FYear := ExtractYear(Tag.Frame[5], Tag.Frame[13]); FGenre := ExtractGenre(Tag.Frame[6]); FComment := ExtractText(Tag.Frame[7], true); FComposer := GetANSI(Tag.Frame[8]); FEncoder := GetANSI(Tag.Frame[9]); FCopyright := GetANSI(Tag.Frame[10]); FLanguage := GetANSI(Tag.Frame[11]); FLink := ExtractText(Tag.Frame[12], false); end; end; end; { --------------------------------------------------------------------------- } function TID3v2.SaveToFile(const FileName: string): Boolean; var Tag: TagInfo; begin FillChar(Tag, SizeOf(Tag), 0); ReadHeader(FileName, Tag); Tag.Frame[1] := FTitle; Tag.Frame[2] := FArtist; Tag.Frame[3] := FAlbum; if FTrack > 0 then Tag.Frame[4] := IntToStr(FTrack); Tag.Frame[5] := FYear; Tag.Frame[6] := FGenre; if FComment <> '' then Tag.Frame[7] := 'eng' + #0 + FComment; Tag.Frame[8] := FComposer; Tag.Frame[9] := FEncoder; Tag.Frame[10] := FCopyright; Tag.Frame[11] := FLanguage; if FLink <> '' then Tag.Frame[12] := #0 + FLink; Result := SaveTag(FileName, Tag); end; { --------------------------------------------------------------------------- } function TID3v2.RemoveFromFile(const FileName: string): Boolean; begin Result := RebuildFile(FileName, nil); end; { --------------------------------------------------------------------------- } end.
Delphi-Quellcode:
Beispielprogramm zum laden und speichern füge ich an.
unit MPEGHeader;
interface { ---------------------------------------------------------------------------- } type TMPEGInfo = record Position: integer; Version: integer; Layer: integer; Protection: boolean; Bitrate: integer; Samplerate: integer; ChannelMode: byte; Extension: byte; Copyright: boolean; Original: boolean; Emphasis: byte; Frames: longint; Dauer: longint; VBR: boolean; end; { ---------------------------------------------------------------------------- } const MPEG_BIT_RATES: array[1..3] of array[1..3] of array[0..15] of word = (( { Version 1, Layer I } (0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0), { Version 1, Layer II } (0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0), { Version 1, Layer III } (0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0)), { Version 2, Layer I } ((0,32,48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,0), { Version 2, Layer II } (0, 8,16,24, 32, 40, 48, 56, 64, 80, 96, 112,128,144,160,0), { Version 2, Layer III } (0, 8,16,24, 32, 40, 48, 56, 64, 80, 96, 112,128,144,160,0)), { Version 2.5, Layer I } ((0,32,48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,0), { Version 2.5, Layer II } (0, 8,16,24, 32, 40, 48, 56, 64, 80, 96, 112,128,144,160,0), { Version 2.5, Layer III } (0, 8,16,24, 32, 40, 48, 56, 64, 80, 96, 112,128,144,160,0) )); MPEG_SAMPLE_RATES: array[1..3] of array [0..3] of word = ( (44100, 48000, 32000, 0), (22050, 24000, 16000, 0), (11025, 12000, 8000, 0) ); { ---------------------------------------------------------------------------- } type TMPEGHeader = class(TObject) private { Private declarations } F : File; id3v1_tag : array[1..128] of char; mp3_header : array[1..4] of char; buffer : array of char; fsize : longint; id3v1_size : integer; xing_header_size : integer; id3_size : longint; bitrateindex, versionindex : byte; valid : boolean; position : integer; padding,samplerateindex : byte; framelength : longint; Xing_Offset : integer; Xing_Flags : byte; public { Public declarations } MPEGInfo : TMpeginfo; constructor Create; procedure MPEG_Header(FileName : String); { liest alle Informationen einer MP3 aus } end; { ---------------------------------------------------------------------------- } implementation { ---------------------------------------------------------------------------- } { TMPEGHeader } { ---------------------------------------------------------------------------- } constructor TMPEGHeader.Create; begin inherited Create; end; { ---------------------------------------------------------------------------- } procedure TMPEGHeader.MPEG_Header(FileName: String); begin xing_header_size := 0; id3_size := 0; id3v1_size := 0; AssignFile(F, filename); FileMode := 0; Reset(F,1); fsize := filesize(f); if fsize>=6000 then setlength(buffer,6000) else setlength(buffer,fsize); blockread(f,buffer[0],length(buffer)); Seek(F,FileSize(F)-128); BlockRead(F, id3v1_tag, 128); CloseFile(F); //*******************Start des MPEG-Headers*********************** valid := false; mpeginfo.position := - 1; position := id3_size - 1; while NOT ((valid) or (position>length(buffer)+4)) do begin inc(position); if (ord(buffer[position]) = $FF) AND (ord(buffer[position + 1]) >= $E0) then begin valid := true; Versionindex := ((ord(buffer[position+1]) shr 3) and 3); case versionindex of 0: mpeginfo.version := 3; 1: mpeginfo.version := 0; 2: mpeginfo.version := 2; 3: mpeginfo.version := 1; end; mpeginfo.Layer := 4 - ((ord(buffer[position + 1]) shr 1) and 3); mpeginfo.protection := ((ord(buffer[position + 1]) AND 1) =0); bitrateindex := ((ord(buffer[position + 2]) shr 4) AND $F); mpeginfo.bitrate := MPEG_BIT_RATES[mpeginfo.version][mpeginfo.layer][bitrateindex]; if bitrateindex = $F then valid := false; samplerateindex := ((ord(buffer[position + 2]) shr 2) AND 3); mpeginfo.samplerate := MPEG_SAMPLE_RATES[mpeginfo.version][samplerateindex]; padding := ((ord(buffer[position + 2]) shr 1) AND 1); mpeginfo.channelmode :=((ord(buffer[position + 3]) shr 6) AND 3); mpeginfo.extension :=((ord(buffer[position + 3]) shr 4) AND 3); mpeginfo.copyright :=((ord(buffer[position + 3]) shr 3) AND 1) = 1; mpeginfo.original :=((ord(buffer[position + 3]) shr 2) AND 1) = 1; mpeginfo.emphasis :=(ord(buffer[position + 3]) AND 3); if mpeginfo.layer = 2 then begin if (mpeginfo.bitrate = 32) AND (mpeginfo.channelmode <> 3) then valid := false; if (mpeginfo.bitrate = 48) AND (mpeginfo.channelmode <> 3) then valid := false; if (mpeginfo.bitrate = 56) AND (mpeginfo.channelmode <> 3) then valid := false; if (mpeginfo.bitrate = 80) AND (mpeginfo.channelmode <> 3) then valid := false; if (mpeginfo.bitrate = 224) AND (mpeginfo.channelmode = 3) then valid := false; if (mpeginfo.bitrate = 256) AND (mpeginfo.channelmode = 3) then valid := false; if (mpeginfo.bitrate = 320) AND (mpeginfo.channelmode = 3) then valid := false; if (mpeginfo.bitrate = 384) AND (mpeginfo.channelmode = 3) then valid := false; end; //***************damit ist der MPEG Header komplett eingelesen*********************************** //**************Einlesen des XING-Headers*************************** if mpeginfo.version = 1 then if mpeginfo.channelmode <> 3 then xing_offset := 32 + 4 else xing_offset := 17 + 4 else if mpeginfo.channelmode <> 3 then xing_offset := 17 + 4 else xing_offset := 9 + 4; if (buffer[position + xing_offset] = 'X') AND (buffer[position + xing_offset + 1] = 'i') AND (buffer[position + xing_offset + 2] = 'n') AND (buffer[position + xing_offset + 3] = 'g') then begin Xing_flags := ord(buffer[position + xing_offset + 7]); if (Xing_flags AND 1) = 1 then begin mpeginfo.frames := 16777216 * ord(buffer[position + xing_offset + 8]) + 65536 * ord(buffer[position + xing_offset + 9]) + 256 * ord(buffer[position + xing_offset + 10]) + ord(buffer[position + xing_offset + 11]); end; if mpeginfo.layer = 1 then xing_header_size := trunc(((12 * MPEG_BIT_RATES[mpeginfo.version][mpeginfo.layer][bitrateindex] * 1000 / mpeginfo.samplerate) + padding) * 4) else xing_header_size := trunc(144 * (MPEG_BIT_RATES[mpeginfo.version][mpeginfo.layer][bitrateindex]* 1000 / mpeginfo.samplerate) + padding); framelength := xing_header_size; mpeginfo.bitrate := trunc((mpeginfo.samplerate / 1000 * (fsize - id3_size - id3v1_size - xing_header_size)) / (mpeginfo.frames * 144)); mpeginfo.vbr := true; end else begin if mpeginfo.layer = 1 then framelength := trunc(((12 * MPEG_BIT_RATES[mpeginfo.version][mpeginfo.layer][bitrateindex] * 1000 / mpeginfo.samplerate) + padding) * 4) else framelength := trunc(144 * (MPEG_BIT_RATES[mpeginfo.version][mpeginfo.layer][bitrateindex] * 1000 / mpeginfo.samplerate) + padding); mpeginfo.frames := trunc((fsize - id3_size - id3v1_size - xing_header_size) / framelength); mpeginfo.vbr := false; xing_header_size := 0; end; //**************XING-Header Ende*************************** if (position + framelength > length(buffer) - 2) AND (position + framelength + 4 < fsize) then begin Reset(F,1); Seek(F,position + framelength); blockread(f,mp3_header,4); CloseFile(F); end else begin try mp3_header[1] := buffer[position + framelength]; mp3_header[2] := buffer[position + framelength + 1]; except mp3_header[1] := '0'; mp3_header[2] := '0'; end; end; if (ord(mp3_header[1]) <> $FF) or (ord(mp3_header[2]) < $E0) then valid := false; if valid then begin mpeginfo.dauer := ((fsize - id3_size - id3v1_size - xing_header_size) * 8) div ((mpeginfo.bitrate) * 1000); mpeginfo.position := position; end; end; end; end; { ---------------------------------------------------------------------------- } end. Grüße an alle. MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Moin!
Könntest du uns auch sagen, woher du diese Units hast? |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Warum hast du aus dem Array MusicGenre eine Variable gemacht? Hätte da ne Konstante nich besser gepasst?
Außerdem wäre es so viel platzsparender gegangen:
Delphi-Quellcode:
Außerdem wäre es evtl komfortabel, dieses Array auch im ID3v2 zur Verfügung zu stellen, so daß man da auch darauf zugreifen kann, wenn man es braucht.
const MusicGenre : Array[1..MAX_MUSIC_GENRES - 1] =
('Blues','Classic Rock','Country','Dance',... ... ... 'Trash Metal','Anime','JPop','Synthpop'); |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
@Sharky: Sorry tut mir leid um dein Mausrad und dein warmen Finger :-)
Ich wusste nicht, wie ich es am besten mache und habe daher alles gepostet. @Matze: Ich habe diese Units schon seit bestimmt 1,5Jahren und habe sie zwischendurch immer mal in ein paar Sachen geändert bzw. verfeinert. Ich kann dir ehrlich nicht sagen, wo ich damals das Grundgerüst gefunden habe. Das hat nichts damit zu tun, dass ich keine Namen nennen will sondern das ich es ganz einfach nicht mehr weiß.Sorry @leddl: Ja hätte ich so machen können aber es ist nunmal so gewachsen :-) Kannst es gerne ändern... ;-) MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
ID3v1.pas: - ![]() - ![]() - oder ![]()
Delphi-Quellcode:
D3v2.pas:
{ *************************************************************************** }
{ } { Audio Tools Library (Freeware) } { Class TID3v1 - for manipulating with ID3v1 tags } { } { Copyright (c) 2001,2002 by Jurgen Faul } { E-mail: [email]jfaul@gmx.de[/email] } { [url]http://jfaul.de/atl[/url] } { } { Version 1.0 (25 July 2001) } { - Full support for ID3v1.0 & ID3v1.1 tags (read/write) } { } { *************************************************************************** } - ![]() MPEG-Header.pas: - ![]() Wir müssen das helt wissen, wegen den Copyright-Bestimmungen. :? |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Ja, ich verstehe das mit den Copyright-Bestimmungen aber ich kann dir sagen, dass die ID3v1 und ID3v2 nicht von den obrigen Seiten sind. Ich will ja damit keinen ärgern oder seinen Namen nicht sagen aber wie gesagt, ich habe diese Units schon ziemlich lange und habe kein Copyright entfernt (falls eins vorhanden war).
Bei der MPEG.pas bin ich mir nicht ganz sicher ob sie aus dem DF ist. Falls es so ist, sage ich einfach mal Gausi aus dem DF danke schön! (Copyright ist aber nicht auf dem Source,oder?) Aber wie oben schon gesagt, ich weiß es nicht. MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Also die ID3v1.pas sieht schon sehr ähnlich aus, allerdings scheint die andere Variante (die 2. von Matze) späteren Datums zu sein und einige Verbesserungen/Korrekturen zu haben (Kommentare, Eigenschaft "Changed", Korrekte Versionen von "RemoveTag" und "SaveTag", etc.).
Beide Units haben auf jeden Fall denselben Ursprung, die vielen Gemeinsamkeiten können nicht zufällig sein. |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Warum eigentlich zwei Klasse für die Tag-Versionen? Wie soll man denn das jetzt anwenden? Erst mit der einen versuchen die Tags auszulesen und wenn das nicht klappt mit der anderen? Warum nicht eine Klasse die die Tag-Version bestimmt und dann entsprechend die Tags ausliest?
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
@Luckie: weil vielleicht nicht jeder alle Tag's braucht und nur z.B. die von ID3v1 haben will...
@Flocke: Ich habe auch nirgendwo gesagt, dass alles selber programmiert ist.Ich weiß nur ehrlich nicht mehr, woher ich sie habe.Aber ich weiß garantiert, dass ich kein Copyright verletzt habe bzw. gelöscht habe. MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Hinweis: Der ID3v2 Code verhält sich falsch, wenn eine Exception beim Schreiben auftritt: der Stream wird niemals geschlossen. Nutze Try / Finally um die Streams ordentlich zu schliessen, dann kannst du sie auch löschen.
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Beim Schreiben sollte die Klasse natürlich automatisch die richtige Tag-Version nehmen, wenn schon Daten vorhanden sind und wenn nicht eben die Version, die man als Standard angibt und / oder man gibt eine Tag-Version beim Schreiben vor und wenn schon Tags einer der anderen Version vorhanden sind, werden diese mit der vorgegebenen Version neu geschrieben.
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Ich hab mir jetzt den Code hier nicht ganz so genau angeschaut, aber bei der TMEPGAudio war es so, daß die ID3v1- und ID3v2- Klassen Properties der Hauptklasse waren. Und die beiden hatten jeweils eine Property "TagExists" oder so ähnlich. So konnte man recht schnell herausfinden, wo man schreiben/lesen mußte/sollte/konnte.
Aus Gründen der Abwärtskompatibiliät finde ich das absolut in Ordnung, dem Nutzer absolut freie Hand zu geben, welche Tags er lesen/schreiben will. Allerdings braucht es dann natürlich auch entsprechende Properties und Funktionen. //Edit: Ok, das is ja hier ähnlich. Wo is dann das Problem, Luckie?
Delphi-Quellcode:
if id3v1.Exists then
//Lesen aus id3v1-Tag else if id3v2.Exists then //Lesen aus id3v2-Tag else //nix wird gelesen |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Aber ich finde es für den Benutzer schon sehr angenehm, wenn er selbst Einfluss hat und das nicht der Klasse überlassen muß. Zur Not kann man sich das ganze ja noch recht schnell mit dieser Funktionalität erweitern. Wenn aber alles darauf ausgerichtet ist, dürfte es relativ schwer sein, wieder zu so einer Trennung der Tag-Varianten zurückzukommen. Insofern ist das meiner Meinung nach absolut in Ordnung so. ;)
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
Was ich sagen wollte ist, dass in deinem Code keine Codezeile neu ist! (kannst dir ja beides mal mit KDiff3 ansehen) Du kannst also ebenso gut die Unit aus Matzes Links nehmen, zumal da einige Korrekturen drin sind (so geht z.B. SaveTag ohne vorheriges RemoveTag). Die top-aktuelle Version der Datei findest du übrigens unter ![]() |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Guten Morgen erstmal,
ich möchte jetzt mal folgendes dazu sagen: 1) Es ist nirgendwo ein Copyright (außer auf die ID3v1.pas aber dies auch nur einmal komischerweise) auf den Source versehen 2) ich habe demzufolge auch gegen kein Copyright verstoßen 3) Warum fragen mich so viele Leute (per PN oder im Thread selber), nach dem Source? 3a) Entweder kannten alle die Links nicht die Matze so schnell bereit hatte 3b) oder wenn nach solchen Source gefragt wurde (sogar hier im Forum) wurden die Links nicht preisgegeben 3c) oder alle die mich gefragt haben waren einfach nur zu "blind" zum Source suchen... Da kann man jetzt eine Menge spekulieren aber ich habe ein fertiges Programm geschrieben und ich sollte es in die CodeLib stellen. Das habe ich gemacht. Jetzt hat man wenigstens den kompletten Source (alle TAG's die auslesbar sind) hintereinander weg stehen und man kann sich jetzt selber überlegen was man braucht (ob alles in einer Unit like Luckie oder eben alles schön übersichtlich like leddl. Mich erst "minutenlang" (oder vielleicht sogar ohne Erfolg) durch's I-Net zu quälen und den Source auf 3-4 verschiedenen Seiten zu suchen ist vielleicht nicht so die schönste Art und Weise. Also ich wünsche euch dann noch ein schönen Tag. MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
Wir freuen und sehr, dass du uns den Code mit deinen Änderungen offenbarst, nicht, dass du das falsch verstehst, wir werden schon eine Lösung finden. :) |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Okay, ich verstehe das Matze.
Nein, dass ihr Probleme wegen Urheberrechten bekommt will keiner hier! Ich werde heute auch mal im Netz rumgucken ob da irgendwo noch mehr davon rumschwirrt :-) und gucken ob ein Copyright drauf ist. Jup, werden schon eine passende Lösung finden. MFG Alex |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Hai ihr,
ich bin mir jetzt nicht sicher... Aber wenn Alex versichert das die relevanten Codeabschnitte von ihm sind ist doch alles okay? Sicher ist doch das die meisten der in der Delphi-PRAXiS vorgestellten Codes nicht von dem "Autor" stammen. Dies finde ich nicht schlimm wenn es sich dabei um eine elementare Weiterentwicklung geht oder der Name des Authors genannt wird. Immerhin könnte auch ich an zumindest einen "link" zu einem Tutorial mein (c) anmelden da ich dem Author ca. 60% dessen was beschrieben wird erklärte. Lange Rede kurzer Sinn: Wenn jemand etwas in der CL schreibt und selber sagt das er einen Teil der Informationen aus anderen Codes hat ist dies, so denke ich es, okay. |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Und da es im Moment eh fast unmöglich zu sein scheint, daß er "das is von dem... und das von dem ..." reinschreiben kann
und anscheinend ja wenigstens ein/zwei Quellen entdeckt wurden, würde es doch auch reichen, wenn zumindestens das Bekannte aufgeführt wird. So nach dem Motto "hier is was von dem, dem, dem und weitern drin." Und falls sich doch irgendwann mal jemand meldet, der "sauer is, weil er/sie net aufgeführt wird, dann wird es doch wohl keine große Sache sein den/die noch mit einzufügen (zumindestens dagegen wird dann wohl keiner was haben). |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Heyho!
Wie verwend ich denn den Code? Ich hab bisher noch nie Klassen benutzt und weiß deshalb noch nix darüber.. googlen und ausprobiern hat mir nich weitergeholfen... gruß |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Welchen Code?
|
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Zitat:
gruß |
Re: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
[Werbung]Ich habe für genau einen solchen Fall mal meine (auch Klassen benutzende) ID3 Library um ein einfaches Interface erweitert. Mit dem EasyInterface kommst du an diese Informationen ran, ohne dich um irgendwelche Klassen kümmern zu müssen.
![]() |
AW: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Hallo,
ich habe versucht die Units in meinem kleinen MediaPlayer zu benutzen, aber mein Delphi 3 gibt mir haufenweise Fehlermeldungen in der MPEGHeader.pas, haupsächlich etwas wie "inkompatible Typen" und dann größtenteils "inkompatible Typen Char und Integer". Es wäre echt nett, wenn mir da jemand helfen könnte. Danke. |
AW: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Bedenke bitte, daß dein D3 nicht grade das Jüngste ist und es demnach mit vielen "neueren" Compilerfeatures nicht zurecht kommt.
So, aber da ich (und auch viele Andere) selber kein D3 installiert hab, kann ich ohne detailiertere Fehlermeldung nichts ausrichten. Also Fehlermeldungen und die zugehörigen Fehlerzeilen/-stellen. Aber wenn ich dann sowas wie das seh (aus Post #1)
Delphi-Quellcode:
Dann rate ich von einer Verwendung dieses Codes eher ab.
function ReadTag(const FileName: string; var TagData: TagRecord): Boolean;
var SourceFile : File; begin try Result := true; AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); Seek(SourceFile, FileSize(SourceFile) - 128); BlockRead(SourceFile, TagData, 128); CloseFile(SourceFile); except Result := false; end; end; Wenn, dann eigentlich so
Delphi-Quellcode:
eventuell auch so
function ReadTag(const FileName: string; var TagData: TagRecord): Boolean;
var SourceFile : File; begin AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); try try Seek(SourceFile, FileSize(SourceFile) - 128); BlockRead(SourceFile, TagData, 128); Result := true; except Result := false; end; finally CloseFile(SourceFile); end; end;
Delphi-Quellcode:
oder ganz ohne Exceptions:
function ReadTag(const FileName: string; var TagData: TagRecord): Boolean;
var SourceFile : File; begin AssignFile(SourceFile, FileName); FileMode := 0; Reset(SourceFile, 1); try Seek(SourceFile, FileSize(SourceFile) - 128); BlockRead(SourceFile, TagData, 128); Result := true; except Result := false; end; CloseFile(SourceFile); end;
Delphi-Quellcode:
function ReadTag(const FileName: string; var TagData: TagRecord): Boolean;
var SourceFile : File; begin AssignFile(SourceFile, FileName); FileMode := 0; {$I-} Reset(SourceFile, 1); Seek(SourceFile, FileSize(SourceFile) - 128); BlockRead(SourceFile, TagData, 128); CloseFile(SourceFile); Result := IOResult = 0; {$I+} end; Vom Codeaufbau her würde ich eher die in Beitrag #6 und #27 verlinkten Codes empfehlen, aber diese laufen teilweise nichtmal in D7/D2006 und demnach erst Recht nicht in einem D3. |
AW: ID3v1-Tag, ID3v2-Tag und MPEG-Header einer MP3 auslesen
Danke für den Tipp
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:17 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 by Thomas Breitkreuz