如何得到Vql和Wma文件的内部信息??(100分)

  • 主题发起人 主题发起人 chen  bin
  • 开始时间 开始时间
C

chen  bin

Unregistered / Unconfirmed
GUEST, unregistred user!
像mp3中的TAG一样,这些内容在wma和vqf中是如何定义的?
 
记得有一个控件可以实现.写过一次.<br>具体我也忘记了.<br>gz^_^
 
有没有人知道呀?!! &nbsp;能告诉我吗??
 
我也想知道!
 
如何修改WMA文件中的信息?
 
WMA:<br><br>------------------------------<br>unit WMAfile;<br><br>interface<br><br>uses<br>&nbsp; Classes, SysUtils;<br><br>const<br>&nbsp; { Channel modes }<br>&nbsp; WMA_CM_UNKNOWN = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Unknown }<br>&nbsp; WMA_CM_MONO = 1; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Mono }<br>&nbsp; WMA_CM_STEREO = 2; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Stereo }<br><br>&nbsp; { Channel mode names }<br>&nbsp; WMA_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo');<br><br>type<br>&nbsp; { Class TWMAfile }<br>&nbsp; TWMAfile = class(TObject)<br>&nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; &nbsp; FValid: Boolean;<br>&nbsp; &nbsp; &nbsp; FFileSize: Integer;<br>&nbsp; &nbsp; &nbsp; FChannelModeID: Byte;<br>&nbsp; &nbsp; &nbsp; FSampleRate: Integer;<br>&nbsp; &nbsp; &nbsp; FDuration: Double;<br>&nbsp; &nbsp; &nbsp; FBitRate: Integer;<br>&nbsp; &nbsp; &nbsp; FTitle: WideString;<br>&nbsp; &nbsp; &nbsp; FArtist: WideString;<br>&nbsp; &nbsp; &nbsp; FAlbum: WideString;<br>&nbsp; &nbsp; &nbsp; FTrack: Integer;<br>&nbsp; &nbsp; &nbsp; FYear: WideString;<br>&nbsp; &nbsp; &nbsp; FGenre: WideString;<br>&nbsp; &nbsp; &nbsp; FComment: WideString;<br>&nbsp; &nbsp; &nbsp; procedure FResetData;<br>&nbsp; &nbsp; &nbsp; function FGetChannelMode: string;<br>&nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; { Public declarations }<br>&nbsp; &nbsp; &nbsp; constructor Create; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Create object }<br>&nbsp; &nbsp; &nbsp; function ReadFromFile(const FileName: string): Boolean; &nbsp; &nbsp; { Load data }<br>&nbsp; &nbsp; &nbsp; property Valid: Boolean read FValid; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { True if valid data }<br>&nbsp; &nbsp; &nbsp; property FileSize: Integer read FFileSize; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ File size (bytes) }<br>&nbsp; &nbsp; &nbsp; property ChannelModeID: Byte read FChannelModeID; &nbsp; { Channel mode code }<br>&nbsp; &nbsp; &nbsp; property ChannelMode: string read FGetChannelMode; &nbsp;{ Channel mode name }<br>&nbsp; &nbsp; &nbsp; property SampleRate: Integer read FSampleRate; &nbsp; &nbsp; &nbsp; { Sample rate (hz) }<br>&nbsp; &nbsp; &nbsp; property Duration: Double read FDuration; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Duration (seconds) }<br>&nbsp; &nbsp; &nbsp; property BitRate: Integer read FBitRate; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Bit rate (kbit) }<br>&nbsp; &nbsp; &nbsp; property Title: WideString read FTitle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Song title }<br>&nbsp; &nbsp; &nbsp; property Artist: WideString read FArtist; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Artist name }<br>&nbsp; &nbsp; &nbsp; property Album: WideString read FAlbum; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Album name }<br>&nbsp; &nbsp; &nbsp; property Track: Integer read FTrack; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Track number }<br>&nbsp; &nbsp; &nbsp; property Year: WideString read FYear; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Year }<br>&nbsp; &nbsp; &nbsp; property Genre: WideString read FGenre; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Genre name }<br>&nbsp; &nbsp; &nbsp; property Comment: WideString read FComment; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Comment }<br>&nbsp; end;<br><br>implementation<br><br>const<br>&nbsp; { Object IDs }<br>&nbsp; WMA_HEADER_ID =<br>&nbsp; &nbsp; #48#38#178#117#142#102#207#17#166#217#0#170#0#98#206#108;<br>&nbsp; WMA_FILE_PROPERTIES_ID =<br>&nbsp; &nbsp; #161#220#171#140#71#169#207#17#142#228#0#192#12#32#83#101;<br>&nbsp; WMA_STREAM_PROPERTIES_ID =<br>&nbsp; &nbsp; #145#7#220#183#183#169#207#17#142#230#0#192#12#32#83#101;<br>&nbsp; WMA_CONTENT_DESCRIPTION_ID =<br>&nbsp; &nbsp; #51#38#178#117#142#102#207#17#166#217#0#170#0#98#206#108;<br>&nbsp; WMA_EXTENDED_CONTENT_DESCRIPTION_ID =<br>&nbsp; &nbsp; #64#164#208#210#7#227#210#17#151#240#0#160#201#94#168#80;<br><br>&nbsp; { Max. number of supported comment fields }<br>&nbsp; WMA_FIELD_COUNT = 7;<br><br>&nbsp; { Names of supported comment fields }<br>&nbsp; WMA_FIELD_NAME: array [1..WMA_FIELD_COUNT] of WideString =<br>&nbsp; &nbsp; ('WM/TITLE', 'WM/AUTHOR', 'WM/ALBUMTITLE', 'WM/TRACK', 'WM/YEAR',<br>&nbsp; &nbsp; &nbsp;'WM/GENRE', 'WM/DESCRIPTION');<br><br>&nbsp; { Max. number of characters in tag field }<br>&nbsp; WMA_MAX_STRING_SIZE = 250;<br><br>type<br>&nbsp; { Object ID }<br>&nbsp; ObjectID = array [1..16] of Char;<br><br>&nbsp; { Tag data }<br>&nbsp; TagData = array [1..WMA_FIELD_COUNT] of WideString;<br><br>&nbsp; { File data - for internal use }<br>&nbsp; FileData = record<br>&nbsp; &nbsp; FileSize: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ File size (bytes) }<br>&nbsp; &nbsp; MaxBitRate: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Max. bit rate (bps) }<br>&nbsp; &nbsp; Channels: Word; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Number of channels }<br>&nbsp; &nbsp; SampleRate: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Sample rate (hz) }<br>&nbsp; &nbsp; ByteRate: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Byte rate }<br>&nbsp; &nbsp; Tag: TagData; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { WMA tag information }<br>&nbsp; end;<br><br>{ ********************* Auxiliary functions &amp; procedures ******************** }<br><br>function ReadFieldString(const Source: TStream; DataSize: Word): WideString;<br>var<br>&nbsp; Iterator, StringSize: Integer;<br>&nbsp; FieldData: array [1..WMA_MAX_STRING_SIZE * 2] of Byte;<br>begin<br>&nbsp; { Read field data and convert to Unicode string }<br>&nbsp; Result := '';<br>&nbsp; StringSize := DataSize div 2;<br>&nbsp; if StringSize &gt; WMA_MAX_STRING_SIZE then StringSize := WMA_MAX_STRING_SIZE;<br>&nbsp; Source.ReadBuffer(FieldData, StringSize * 2);<br>&nbsp; Source.Seek(DataSize - StringSize * 2, soFromCurrent);<br>&nbsp; for Iterator := 1 to StringSize do<br>&nbsp; &nbsp; Result := Result +<br>&nbsp; &nbsp; &nbsp; WideChar(FieldData[Iterator * 2 - 1] + (FieldData[Iterator * 2] shl 8));<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>procedure ReadTagStandard(const Source: TStream; var Tag: TagData);<br>var<br>&nbsp; Iterator: Integer;<br>&nbsp; FieldSize: array [1..5] of Word;<br>&nbsp; FieldValue: WideString;<br>begin<br>&nbsp; { Read standard tag data }<br>&nbsp; Source.ReadBuffer(FieldSize, SizeOf(FieldSize));<br>&nbsp; for Iterator := 1 to 5 do<br>&nbsp; &nbsp; if FieldSize[Iterator] &gt; 0 then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; { Read field value }<br>&nbsp; &nbsp; &nbsp; FieldValue := ReadFieldString(Source, FieldSize[Iterator]);<br>&nbsp; &nbsp; &nbsp; { Set corresponding tag field if supported }<br>&nbsp; &nbsp; &nbsp; case Iterator of<br>&nbsp; &nbsp; &nbsp; &nbsp; 1: Tag[1] := FieldValue;<br>&nbsp; &nbsp; &nbsp; &nbsp; 2: Tag[2] := FieldValue;<br>&nbsp; &nbsp; &nbsp; &nbsp; 4: Tag[7] := FieldValue;<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>procedure ReadTagExtended(const Source: TStream; var Tag: TagData);<br>var<br>&nbsp; Iterator1, Iterator2, FieldCount, DataSize, DataType: Word;<br>&nbsp; FieldName, FieldValue: WideString;<br>begin<br>&nbsp; { Read extended tag data }<br>&nbsp; Source.ReadBuffer(FieldCount, SizeOf(FieldCount));<br>&nbsp; for Iterator1 := 1 to FieldCount do<br>&nbsp; begin<br>&nbsp; &nbsp; { Read field name }<br>&nbsp; &nbsp; Source.ReadBuffer(DataSize, SizeOf(DataSize));<br>&nbsp; &nbsp; FieldName := ReadFieldString(Source, DataSize);<br>&nbsp; &nbsp; { Read value data type }<br>&nbsp; &nbsp; Source.ReadBuffer(DataType, SizeOf(DataType));<br>&nbsp; &nbsp; { Read field value only if string }<br>&nbsp; &nbsp; if DataType = 0 then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Source.ReadBuffer(DataSize, SizeOf(DataSize));<br>&nbsp; &nbsp; &nbsp; FieldValue := ReadFieldString(Source, DataSize);<br>&nbsp; &nbsp; end<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; Source.Seek(DataSize, soFromCurrent);<br>&nbsp; &nbsp; { Set corresponding tag field if supported }<br>&nbsp; &nbsp; for Iterator2 := 1 to WMA_FIELD_COUNT do<br>&nbsp; &nbsp; &nbsp; if UpperCase(Trim(FieldName)) = WMA_FIELD_NAME[Iterator2] then<br>&nbsp; &nbsp; &nbsp; &nbsp; Tag[Iterator2] := FieldValue;<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>procedure ReadObject(const ID: ObjectID; Source: TStream; var Data: FileData);<br>begin<br>&nbsp; { Read data from header object if supported }<br>&nbsp; if ID = WMA_FILE_PROPERTIES_ID then<br>&nbsp; begin<br>&nbsp; &nbsp; { Read file properties }<br>&nbsp; &nbsp; Source.Seek(80, soFromCurrent);<br>&nbsp; &nbsp; Source.ReadBuffer(Data.MaxBitRate, SizeOf(Data.MaxBitRate));<br>&nbsp; end;<br>&nbsp; if ID = WMA_STREAM_PROPERTIES_ID then<br>&nbsp; begin<br>&nbsp; &nbsp; { Read stream properties }<br>&nbsp; &nbsp; Source.Seek(60, soFromCurrent);<br>&nbsp; &nbsp; Source.ReadBuffer(Data.Channels, SizeOf(Data.Channels));<br>&nbsp; &nbsp; Source.ReadBuffer(Data.SampleRate, SizeOf(Data.SampleRate));<br>&nbsp; &nbsp; Source.ReadBuffer(Data.ByteRate, SizeOf(Data.ByteRate));<br>&nbsp; end;<br>&nbsp; if ID = WMA_CONTENT_DESCRIPTION_ID then<br>&nbsp; begin<br>&nbsp; &nbsp; { Read standard tag data }<br>&nbsp; &nbsp; Source.Seek(4, soFromCurrent);<br>&nbsp; &nbsp; ReadTagStandard(Source, Data.Tag);<br>&nbsp; end;<br>&nbsp; if ID = WMA_EXTENDED_CONTENT_DESCRIPTION_ID then<br>&nbsp; begin<br>&nbsp; &nbsp; { Read extended tag data }<br>&nbsp; &nbsp; Source.Seek(4, soFromCurrent);<br>&nbsp; &nbsp; ReadTagExtended(Source, Data.Tag);<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function ReadData(const FileName: string; var Data: FileData): Boolean;<br>var<br>&nbsp; Source: TFileStream;<br>&nbsp; ID: ObjectID;<br>&nbsp; Iterator, ObjectCount, ObjectSize, Position: Integer;<br>begin<br>&nbsp; { Read file data }<br>&nbsp; try<br>&nbsp; &nbsp; Source := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);<br>&nbsp; &nbsp; Data.FileSize := Source.Size;<br>&nbsp; &nbsp; { Check for existing header }<br>&nbsp; &nbsp; Source.ReadBuffer(ID, SizeOf(ID));<br>&nbsp; &nbsp; if ID = WMA_HEADER_ID then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Source.Seek(8, soFromCurrent);<br>&nbsp; &nbsp; &nbsp; Source.ReadBuffer(ObjectCount, SizeOf(ObjectCount));<br>&nbsp; &nbsp; &nbsp; Source.Seek(2, soFromCurrent);<br>&nbsp; &nbsp; &nbsp; { Read all objects in header and get needed data }<br>&nbsp; &nbsp; &nbsp; for Iterator := 1 to ObjectCount do<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; Position := Source.Position;<br>&nbsp; &nbsp; &nbsp; &nbsp; Source.ReadBuffer(ID, SizeOf(ID));<br>&nbsp; &nbsp; &nbsp; &nbsp; Source.ReadBuffer(ObjectSize, SizeOf(ObjectSize));<br>&nbsp; &nbsp; &nbsp; &nbsp; ReadObject(ID, Source, Data);<br>&nbsp; &nbsp; &nbsp; &nbsp; Source.Seek(Position + ObjectSize, soFromBeginning);<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; Source.Free;<br>&nbsp; &nbsp; Result := true;<br>&nbsp; except<br>&nbsp; &nbsp; Result := false;<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function IsValid(const Data: FileData): Boolean;<br>begin<br>&nbsp; { Check for data validity }<br>&nbsp; Result :=<br>&nbsp; &nbsp; (Data.MaxBitRate &gt; 0) and (Data.MaxBitRate &lt; 320000) and<br>&nbsp; &nbsp; ((Data.Channels = WMA_CM_MONO) or (Data.Channels = WMA_CM_STEREO)) and<br>&nbsp; &nbsp; (Data.SampleRate &gt;= 8000) and (Data.SampleRate &lt;= 96000) and<br>&nbsp; &nbsp; (Data.ByteRate &gt; 0) and (Data.ByteRate &lt; 40000);<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function ExtractTrack(const TrackString: WideString): Integer;<br>var<br>&nbsp; Value, Code: Integer;<br>begin<br>&nbsp; { Extract track from string }<br>&nbsp; Result := 0;<br>&nbsp; Val(TrackString, Value, Code);<br>&nbsp; if Code = 0 then Result := Value;<br>end;<br><br>{ ********************** Private functions &amp; procedures ********************* }<br><br>procedure TWMAfile.FResetData;<br>begin<br>&nbsp; { Reset variables }<br>&nbsp; FValid := false;<br>&nbsp; FFileSize := 0;<br>&nbsp; FChannelModeID := WMA_CM_UNKNOWN;<br>&nbsp; FSampleRate := 0;<br>&nbsp; FDuration := 0;<br>&nbsp; FBitRate := 0;<br>&nbsp; FTitle := '';<br>&nbsp; FArtist := '';<br>&nbsp; FAlbum := '';<br>&nbsp; FTrack := 0;<br>&nbsp; FYear := '';<br>&nbsp; FGenre := '';<br>&nbsp; FComment := '';<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function TWMAfile.FGetChannelMode: string;<br>begin<br>&nbsp; { Get channel mode name }<br>&nbsp; Result := WMA_MODE[FChannelModeID];<br>end;<br><br>{ ********************** Public functions &amp; procedures ********************** }<br><br>constructor TWMAfile.Create;<br>begin<br>&nbsp; { Create object }<br>&nbsp; inherited;<br>&nbsp; FResetData;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function TWMAfile.ReadFromFile(const FileName: string): Boolean;<br>var<br>&nbsp; Data: FileData;<br>begin<br>&nbsp; { Reset variables and load file data }<br>&nbsp; FResetData;<br>&nbsp; FillChar(Data, SizeOf(Data), 0);<br>&nbsp; Result := ReadData(FileName, Data);<br>&nbsp; { Process data if loaded and valid }<br>&nbsp; if Result and IsValid(Data) then<br>&nbsp; begin<br>&nbsp; &nbsp; FValid := true;<br>&nbsp; &nbsp; { Fill properties with loaded data }<br>&nbsp; &nbsp; FFileSize := Data.FileSize;<br>&nbsp; &nbsp; FChannelModeID := Data.Channels;<br>&nbsp; &nbsp; FSampleRate := Data.SampleRate;<br>&nbsp; &nbsp; FDuration := Data.FileSize * 8 / Data.MaxBitRate;<br>&nbsp; &nbsp; FBitRate := Data.ByteRate * 8 div 1000;<br>&nbsp; &nbsp; FTitle := Trim(Data.Tag[1]);<br>&nbsp; &nbsp; FArtist := Trim(Data.Tag[2]);<br>&nbsp; &nbsp; FAlbum := Trim(Data.Tag[3]);<br>&nbsp; &nbsp; FTrack := ExtractTrack(Trim(Data.Tag[4]));<br>&nbsp; &nbsp; FYear := Trim(Data.Tag[5]);<br>&nbsp; &nbsp; FGenre := Trim(Data.Tag[6]);<br>&nbsp; &nbsp; FComment := Trim(Data.Tag[7]);<br>&nbsp; end;<br>end;<br><br>end.<br><br>------------------------------<br><br>VQF<br><br>-------------------------------<br>unit TwinVQ;<br><br>interface<br><br>uses<br>&nbsp; Classes, SysUtils;<br><br>const<br>&nbsp; { Used with ChannelModeID property }<br>&nbsp; TWIN_CM_MONO = 1; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Index for mono mode }<br>&nbsp; TWIN_CM_STEREO = 2; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Index for stereo mode }<br><br>&nbsp; { Channel mode names }<br>&nbsp; TWIN_MODE: array [0..2] of string = ('Unknown', 'Mono', 'Stereo');<br><br>type<br>&nbsp; { Class TTwinVQ }<br>&nbsp; TTwinVQ = class(TObject)<br>&nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; &nbsp; FValid: Boolean;<br>&nbsp; &nbsp; &nbsp; FChannelModeID: Byte;<br>&nbsp; &nbsp; &nbsp; FBitRate: Byte;<br>&nbsp; &nbsp; &nbsp; FSampleRate: Word;<br>&nbsp; &nbsp; &nbsp; FFileSize: Cardinal;<br>&nbsp; &nbsp; &nbsp; FDuration: Double;<br>&nbsp; &nbsp; &nbsp; FTitle: string;<br>&nbsp; &nbsp; &nbsp; FComment: string;<br>&nbsp; &nbsp; &nbsp; FAuthor: string;<br>&nbsp; &nbsp; &nbsp; FCopyright: string;<br>&nbsp; &nbsp; &nbsp; FOriginalFile: string;<br>&nbsp; &nbsp; &nbsp; FAlbum: string;<br>&nbsp; &nbsp; &nbsp; procedure FResetData;<br>&nbsp; &nbsp; &nbsp; function FGetChannelMode: string;<br>&nbsp; &nbsp; &nbsp; function FIsCorrupted: Boolean;<br>&nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; { Public declarations }<br>&nbsp; &nbsp; &nbsp; constructor Create; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Create object }<br>&nbsp; &nbsp; &nbsp; function ReadFromFile(const FileName: string): Boolean; &nbsp; { Load header }<br>&nbsp; &nbsp; &nbsp; property Valid: Boolean read FValid; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { True if header valid }<br>&nbsp; &nbsp; &nbsp; property ChannelModeID: Byte read FChannelModeID; &nbsp; { Channel mode code }<br>&nbsp; &nbsp; &nbsp; property ChannelMode: string read FGetChannelMode; &nbsp;{ Channel mode name }<br>&nbsp; &nbsp; &nbsp; property BitRate: Byte read FBitRate; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Total bit rate }<br>&nbsp; &nbsp; &nbsp; property SampleRate: Word read FSampleRate; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Sample rate (hz) }<br>&nbsp; &nbsp; &nbsp; property FileSize: Cardinal read FFileSize; &nbsp; &nbsp; &nbsp; &nbsp; { File size (bytes) }<br>&nbsp; &nbsp; &nbsp; property Duration: Double read FDuration; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Duration (seconds) }<br>&nbsp; &nbsp; &nbsp; property Title: string read FTitle; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Title name }<br>&nbsp; &nbsp; &nbsp; property Comment: string read FComment; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Comment }<br>&nbsp; &nbsp; &nbsp; property Author: string read FAuthor; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Author name }<br>&nbsp; &nbsp; &nbsp; property Copyright: string read FCopyright; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Copyright }<br>&nbsp; &nbsp; &nbsp; property OriginalFile: string read FOriginalFile; &nbsp;{ Original file name }<br>&nbsp; &nbsp; &nbsp; property Album: string read FAlbum; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Album title }<br>&nbsp; &nbsp; &nbsp; property Corrupted: Boolean read FIsCorrupted; { True if file corrupted }<br>&nbsp; end;<br><br>implementation<br><br>const<br>&nbsp; { Twin VQ header ID }<br>&nbsp; TWIN_ID = 'TWIN';<br>&nbsp; <br>&nbsp; { Max. number of supported tag-chunks }<br>&nbsp; TWIN_CHUNK_COUNT = 6;<br><br>&nbsp; { Names of supported tag-chunks }<br>&nbsp; TWIN_CHUNK: array [1..TWIN_CHUNK_COUNT] of string =<br>&nbsp; &nbsp; ('NAME', 'COMT', 'AUTH', '(c) ', 'FILE', 'ALBM');<br><br>type<br>&nbsp; { TwinVQ chunk header }<br>&nbsp; ChunkHeader = record<br>&nbsp; &nbsp; ID: array [1..4] of Char; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Chunk ID }<br>&nbsp; &nbsp; Size: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Chunk size }<br>&nbsp; end;<br><br>&nbsp; { File header data - for internal use }<br>&nbsp; HeaderInfo = record<br>&nbsp; &nbsp; { Real structure of TwinVQ file header }<br>&nbsp; &nbsp; ID: array [1..4] of Char; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Always "TWIN" }<br>&nbsp; &nbsp; Version: array [1..8] of Char; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Version ID }<br>&nbsp; &nbsp; Size: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Header size }<br>&nbsp; &nbsp; Common: ChunkHeader; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Common chunk header }<br>&nbsp; &nbsp; ChannelMode: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Channel mode: 0 - mono, 1 - stereo }<br>&nbsp; &nbsp; BitRate: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Total bit rate }<br>&nbsp; &nbsp; SampleRate: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Sample rate (khz) }<br>&nbsp; &nbsp; SecurityLevel: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Always 0 }<br>&nbsp; &nbsp; { Extended data }<br>&nbsp; &nbsp; FileSize: Cardinal; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { File size (bytes) }<br>&nbsp; &nbsp; Tag: array [1..TWIN_CHUNK_COUNT] of string; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Tag information }<br>&nbsp; end;<br><br>{ ********************* Auxiliary functions &amp; procedures ******************** }<br><br>function ReadHeader(const FileName: string; var Header: HeaderInfo): Boolean;<br>var<br>&nbsp; SourceFile: file;<br>&nbsp; Transferred: Integer;<br>begin<br>&nbsp; try<br>&nbsp; &nbsp; Result := true;<br>&nbsp; &nbsp; { Set read-access and open file }<br>&nbsp; &nbsp; AssignFile(SourceFile, FileName);<br>&nbsp; &nbsp; FileMode := 0;<br>&nbsp; &nbsp; Reset(SourceFile, 1);<br>&nbsp; &nbsp; { Read header and get file size }<br>&nbsp; &nbsp; BlockRead(SourceFile, Header, 40, Transferred);<br>&nbsp; &nbsp; Header.FileSize := FileSize(SourceFile);<br>&nbsp; &nbsp; CloseFile(SourceFile);<br>&nbsp; &nbsp; { if transfer is not complete }<br>&nbsp; &nbsp; if Transferred &lt; 40 then Result := false;<br>&nbsp; except<br>&nbsp; &nbsp; { Error }<br>&nbsp; &nbsp; Result := false;<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function GetChannelModeID(const Header: HeaderInfo): Byte;<br>begin<br>&nbsp; { Get channel mode from header }<br>&nbsp; case Swap(Header.ChannelMode shr 16) of<br>&nbsp; &nbsp; 0: Result := TWIN_CM_MONO;<br>&nbsp; &nbsp; 1: Result := TWIN_CM_STEREO<br>&nbsp; &nbsp; else Result := 0;<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function GetBitRate(const Header: HeaderInfo): Byte;<br>begin<br>&nbsp; { Get bit rate from header }<br>&nbsp; Result := Swap(Header.BitRate shr 16);<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function GetSampleRate(const Header: HeaderInfo): Word;<br>begin<br>&nbsp; { Get real sample rate from header }<br>&nbsp; Result := Swap(Header.SampleRate shr 16);<br>&nbsp; case Result of<br>&nbsp; &nbsp; 11: Result := 11025;<br>&nbsp; &nbsp; 22: Result := 22050;<br>&nbsp; &nbsp; 44: Result := 44100;<br>&nbsp; &nbsp; else Result := Result * 1000;<br>&nbsp; end;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function GetDuration(const Header: HeaderInfo): Double;<br>begin<br>&nbsp; { Get duration from header }<br>&nbsp; Result := Abs((Header.FileSize - Swap(Header.Size shr 16) - 20)) / 125 /<br>&nbsp; &nbsp; Swap(Header.BitRate shr 16);<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function HeaderEndReached(const Chunk: ChunkHeader): Boolean;<br>begin<br>&nbsp; { Check for header end }<br>&nbsp; Result := (Ord(Chunk.ID[1]) &lt; 32) or<br>&nbsp; &nbsp; (Ord(Chunk.ID[2]) &lt; 32) or<br>&nbsp; &nbsp; (Ord(Chunk.ID[3]) &lt; 32) or<br>&nbsp; &nbsp; (Ord(Chunk.ID[4]) &lt; 32) or<br>&nbsp; &nbsp; (Chunk.ID = 'DATA');<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>procedure SetTagItem(const ID, Data: string; var Header: HeaderInfo);<br>var<br>&nbsp; Iterator: Byte;<br>begin<br>&nbsp; { Set tag item if supported tag-chunk found }<br>&nbsp; for Iterator := 1 to TWIN_CHUNK_COUNT do<br>&nbsp; &nbsp; if TWIN_CHUNK[Iterator] = ID then Header.Tag[Iterator] := Data;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>procedure ReadTag(const FileName: string; var Header: HeaderInfo);<br>var<br>&nbsp; SourceFile: file;<br>&nbsp; Chunk: ChunkHeader;<br>&nbsp; Data: array [1..250] of Char;<br>begin<br>&nbsp; try<br>&nbsp; &nbsp; { Set read-access, open file }<br>&nbsp; &nbsp; AssignFile(SourceFile, FileName);<br>&nbsp; &nbsp; FileMode := 0;<br>&nbsp; &nbsp; Reset(SourceFile, 1);<br>&nbsp; &nbsp; Seek(SourceFile, 16);<br>&nbsp; &nbsp; repeat<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; FillChar(Data, SizeOf(Data), 0);<br>&nbsp; &nbsp; &nbsp; { Read chunk header }<br>&nbsp; &nbsp; &nbsp; BlockRead(SourceFile, Chunk, 8);<br>&nbsp; &nbsp; &nbsp; { Read chunk data and set tag item if chunk header valid }<br>&nbsp; &nbsp; &nbsp; if HeaderEndReached(Chunk) then break;<br>&nbsp; &nbsp; &nbsp; BlockRead(SourceFile, Data, Swap(Chunk.Size shr 16) mod SizeOf(Data));<br>&nbsp; &nbsp; &nbsp; SetTagItem(Chunk.ID, Data, Header);<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; until EOF(SourceFile);<br>&nbsp; &nbsp; CloseFile(SourceFile);<br>&nbsp; except<br>&nbsp; end;<br>end;<br><br>{ ********************** Private functions &amp; procedures ********************* }<br><br>procedure TTwinVQ.FResetData;<br>begin<br>&nbsp; FValid := false;<br>&nbsp; FChannelModeID := 0;<br>&nbsp; FBitRate := 0;<br>&nbsp; FSampleRate := 0;<br>&nbsp; FFileSize := 0;<br>&nbsp; FDuration := 0;<br>&nbsp; FTitle := '';<br>&nbsp; FComment := '';<br>&nbsp; FAuthor := '';<br>&nbsp; FCopyright := '';<br>&nbsp; FOriginalFile := '';<br>&nbsp; FAlbum := '';<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function TTwinVQ.FGetChannelMode: string;<br>begin<br>&nbsp; Result := TWIN_MODE[FChannelModeID];<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function TTwinVQ.FIsCorrupted: Boolean;<br>begin<br>&nbsp; { Check for file corruption }<br>&nbsp; Result := (FValid) and<br>&nbsp; &nbsp; ((FChannelModeID = 0) or<br>&nbsp; &nbsp; (FBitRate &lt; 8) or (FBitRate &gt; 192) or<br>&nbsp; &nbsp; (FSampleRate &lt; 8000) or (FSampleRate &gt; 44100) or<br>&nbsp; &nbsp; (FDuration &lt; 0.1) or (FDuration &gt; 10000));<br>end;<br><br>{ ********************** Public functions &amp; procedures ********************** }<br><br>constructor TTwinVQ.Create;<br>begin<br>&nbsp; inherited;<br>&nbsp; FResetData;<br>end;<br><br>{ --------------------------------------------------------------------------- }<br><br>function TTwinVQ.ReadFromFile(const FileName: string): Boolean;<br>var<br>&nbsp; Header: HeaderInfo;<br>begin<br>&nbsp; { Reset data and load header from file to variable }<br>&nbsp; FResetData;<br>&nbsp; Result := ReadHeader(FileName, Header);<br>&nbsp; { Process data if loaded and header valid }<br>&nbsp; if (Result) and (Header.ID = TWIN_ID) then<br>&nbsp; begin<br>&nbsp; &nbsp; FValid := true;<br>&nbsp; &nbsp; { Fill properties with header data }<br>&nbsp; &nbsp; FChannelModeID := GetChannelModeID(Header);<br>&nbsp; &nbsp; FBitRate := GetBitRate(Header);<br>&nbsp; &nbsp; FSampleRate := GetSampleRate(Header);<br>&nbsp; &nbsp; FFileSize := Header.FileSize;<br>&nbsp; &nbsp; FDuration := GetDuration(Header);<br>&nbsp; &nbsp; { Get tag information and fill properties }<br>&nbsp; &nbsp; ReadTag(FileName, Header);<br>&nbsp; &nbsp; FTitle := Trim(Header.Tag[1]);<br>&nbsp; &nbsp; FComment := Trim(Header.Tag[2]);<br>&nbsp; &nbsp; FAuthor := Trim(Header.Tag[3]);<br>&nbsp; &nbsp; FCopyright := Trim(Header.Tag[4]);<br>&nbsp; &nbsp; FOriginalFile := Trim(Header.Tag[5]);<br>&nbsp; &nbsp; FAlbum := Trim(Header.Tag[6]);<br>&nbsp; end;<br>end;<br><br>end.<br>-------------------------------
 
<br>&nbsp; ScanMP3Folder (Edit1.Text, ListBox1.Items); <br><br>procedure ScanMP3Folder (const AFolder : string; AMP3List : TStrings); <br>var <br>&nbsp; ds : TDirectoryScanner; <br>&nbsp; a : TAudioInfo; <br>&nbsp; Descr : string; <br>&nbsp; i : integer; <br>begin <br>&nbsp; ds := TDirectoryScanner.Create; <br>&nbsp; a := TAudioInfo.Create; <br>&nbsp; try <br>&nbsp; &nbsp; &nbsp;ds.Recursive := True; <br>&nbsp; &nbsp; &nbsp;ds.RegExprMask := '/.mp[23]'; <br>&nbsp; &nbsp; &nbsp;ds.BuildFileList (AFolder); <br>&nbsp; &nbsp; &nbsp;for i := 0 to ds.Count - 1 do begin <br>&nbsp; &nbsp; &nbsp; &nbsp;a.LoadFromFile (ds.Item .Name); <br>&nbsp; &nbsp; &nbsp; &nbsp;if a.ID3.Ok <br>&nbsp; &nbsp; &nbsp; &nbsp; then Descr := a.ID3.Artist + ' - ' + a.ID3.Title <br>&nbsp; &nbsp; &nbsp; &nbsp; else Descr := ExtractFileName (ds.Item .Name); <br>&nbsp; &nbsp; &nbsp; &nbsp;Descr := Descr + Format (' (%d sec)', [a.MpegDuration div 1000]); <br>&nbsp; &nbsp; &nbsp; &nbsp;AMP3List.Add (Descr); <br>&nbsp; &nbsp; &nbsp; end; <br>&nbsp; &nbsp; finally begin <br>&nbsp; &nbsp; &nbsp; a.Free; <br>&nbsp; &nbsp; &nbsp; ds.Free; <br>&nbsp; &nbsp; &nbsp;end; <br>&nbsp; &nbsp;end; <br>end; <br><br>需要使用两个控件<br>http://anso.virtualave.net/delphi_stuff.htm#TAudioInfo(TAudioInfo)<br>http://www.delphi3000.com/article.asp?id=1083(TDirectoryScanner)<br>
 
后退
顶部