请教一个读取MP3的格式问题!(50分)

  • 主题发起人 主题发起人 yuzhizhi
  • 开始时间 开始时间
Y

yuzhizhi

Unregistered / Unconfirmed
GUEST, unregistred user!
谁能够说出MP3的文件格式!
就是说:存放MP3的长度放在那儿!和其它一些信息!(时间!歌名等)
 
关注此题!!
 
有很多现成的控件可用
多数带有源代码
第一版本的Tag是放在Mp3文件头,第二版本是加在MP3文件后面的。
 
{
Title: TMP3Info component
Version: 1.2
Date: 28.JAN.1999

Description: Component MP3Info extracts/saves any ID3 Tag into/from it's properties from/to MP3 file.
Keywords: MP3 ID3 TAG INFO

Author: Rok Krulec (Rok@fpp.edu) (http://Rok.fpp.edu)
Primary site: ftp://ftp.fpp.edu/pub/people/Rok_Krulec/mp3i-v12.zip
Alternate sites: http://www.delphipages.com
http://www.delphiexchange.com
http://sunsite.icm.edu.pl/delphi/
Delphi version: 1.0, 2.0, 3.0, 4.0
Policy: 1Dollarware
Comment: If you use this component, I would like to get 1 Americando
llar to Rok Krulec, Zagrad 6, 3000 Celje, Slovenia, Europe.

CHANGES from v1.0 to 1.1: (24.MAY.1998)
- Genre and GenreID property implemented
- GENRE Global variable is public, so you can use it in ListBoxes, DropDowns e.t.c.
- onChangeFile, onChange, onError events added and Error property

CHANGES from v1.1 to 1.2: (28.JAN.1999)
- RemoveID3 method added
- Modified Save method
- Added Genres TStrings and removed array of Strings for Genre names. Now Genres can be assigned to ComboBox-es and ListBox-es with Assign method

Contributors:
Michael Schuster - schuster@pool.informatik.rwth-aachen.de - (RemoveID3 method, Save method additions)

TODO:
- Retrieve other MP3 info like sampling speed, stereo/mono properties, song length e.t.c.
- I can't find any freeware MP3 decoding-playing/encoding-recording components arround =do
I really have todo
all things by myself
- What about MP3-s with WAV extension ?

Description of Variables, Properties, Methods and Events:
Genres: TStrings;
- List of Genres
constructor Create(AOwner: TComponent);
- Creates an instance
destructor Destroy;
override;
- Destroys an instance
method Save;
- Saves ID3 Tag to file
method RemoveID3;
- Removes ID3 Tag form file
property Filename: TFilename;
- Filename of MP3 file, when changed it opens a new MP3 file
property Artist: String;
- Artist (30 Chars)
property Title: String;
- Title (30 Chars)
property Album: String;
- Album (30 Chars)
property Year: String;
- Year ( 4 chars)
property Comment: String;
- Comment (30 Chars)
property Genre: String;
- Genre [Read Only]
Property GenreID: Byte;
- Genre ID
property Valid: Boolean;
- Is ID3 valid [Read Only]
property Saved: Boolean;
- Save success [Read Only]
property Error: String;
- Error Message [Read Only]
property onChangeFile:TNotifyEvent;
- Triggers when other file is openned
property onChange:TNotifyEvent;
- Triggers when one of propertis is changed (Artist, Title, Album, Year, Comment, GenreID)
property onError:TNotifyEvent;
- Triggers when errors ocure (Wrong filename, Frong fileformat)
}

unit MP3Info;

interface

uses
SysUtils, Classes;

const
TAGLEN = 127;

type
TMP3Info = class(TComponent)
private
{ Private declarations }
vFilename: TFilename;
vMP3Tag, vArtist, vTitle, vAlbum, vComment, vYear, vGenre, vError: string;
vGenreID: Byte;
vValid: Boolean;
vSaved: Boolean;
vChangeFileEvent, vChangeEvent, vErrorEvent: TNotifyEvent;
procedure SetFilename(Filename: TFilename);
procedure SetArtist(Artist: string);
procedure SetTitle(Title: string);
procedure SetAlbum(Album: string);
procedure SetYear(Year: string);
procedure SetComment(Comment: string);
procedure SetGenreID(ID: Byte);
procedure Open;
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
Genres: TStrings;
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
procedure Save;
procedure RemoveID3;
property Filename: TFilename read vFilename write SetFilename;
property Artist: string read vArtist write SetArtist;
property Title: string read vTitle write SetTitle;
property Album: string read vAlbum write SetAlbum;
property Year: string read vYear write SetYear;
property Comment: string read vComment write SetComment;
property Genre: string read vGenre;
property GenreID: Byte read vGenreID write SetGenreID;
property Valid: Boolean read vValid;
property Saved: Boolean read vSaved;
property Error: string read vError;
property onChangeFile: TNotifyEvent read vChangeFileEvent write vChangeFileEvent;
property onChange: TNotifyEvent read vChangeEvent write vChangeEvent;
property onError: TNotifyEvent read vErrorEvent write vErrorEvent;
end;


procedure Register;

implementation

constructor TMP3Info.Create(AOwner: TComponent);
begin

inherited Create(AOwner);
Genres := TStringList.Create;
vGenreID := 12;
vValid := false;
vSaved := false;

{ Fill the Genres String List so one can use it combo boxes e.t.c. Example: ComboBox.Items.Assign(MP3Info.Genres) }
Genres.CommaText :=
'"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop","Jazz","Metal","New Age","Oldies",'
+ '"Other","Pop","R&B","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death Metal","Pranks",'
+ '"Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal","Jazz+Funk","Fusion","Trance","Classical","Instrumental",'
+ '"Acid","House","Game","Sound Clip","Gospel","Noise","AlternRock","Bass","Soul","Punk","Space","Meditative",'
+ '"Instrumental Pop","Instrumental Rock","Ethnic","Gothic","Darkwave","Techno-Industrial","Electronic","Pop-Folk",'
+ '"Eurodance","Dream","Southern Rock","Comedy","Cult","Gangsta","Top 40","Christian Rap","Pop/Funk","Jungle",'
+ '"Native American","Cabaret","New Wave","Psychedelic","Rave","Showtunes","Trailer","Lo-Fi","Tribal","Acid Punk",'
+ '"Acid Jazz","Polka","Retro","Musical","Rock &
Roll","Hard Rock","Folk","Folk/Rock","National Folk","Swing","Bebob",'
+ '"Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic Rock","Progressive Rock","Psychedelic Rock","Symphonic Rock",'
+ '"Slow Rock","Big Band","Chorus","Easy Listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber Music","Sonata",'
+ '"Symphony","Booty Bass","Primus","Porn Groove","Satire","Slow Jam","Club","Tango","Samba","Folklore"'

end;


destructor TMP3Info.Destroy;
begin

inherited Destroy;
end;


{ Procedure to run when Filename property is changed }

procedure TMP3Info.SetFilename(Filename: TFilename);
begin

vFilename := Filename;
Open;
end;


procedure TMP3Info.SetArtist(Artist: string);
begin

vArtist := Copy(Artist, 0, 30);
if Assigned(onChange) then
onChange(Self);
end;


procedure TMP3Info.SetTitle(Title: string);
begin

vTitle := Copy(Title, 0, 30);
if Assigned(onChange) then
onChange(Self);
end;


procedure TMP3Info.SetAlbum(Album: string);
begin

vAlbum := Copy(Album, 0, 30);
if Assigned(onChange) then
onChange(Self);
end;


procedure TMP3Info.SetYear(Year: string);
begin

vYear := Copy(Year, 0, 4);
if Assigned(onChange) then
onChange(Self);
end;


procedure TMP3Info.SetComment(Comment: string);
begin

vComment := Copy(Comment, 0, 30);
if Assigned(onChange) then
onChange(Self);
end;


procedure TMP3Info.SetGenreID(ID: Byte);
begin

if ((ID > 255) or (ID > Genres.Count - 1)) then
ID := 12;
vGenreID := ID;
vGenre := Genres[vGenreID];
//this line is important because after changing
//vGenreID whitout it vGenre will be the same like before !!!
if Assigned(onChange) then
onChange(Self);
end;


{ Opens file with Filename property, reads ID3 Tag and sets properties }

procedure TMP3Info.Open;

{ Strips empty spaces at the end of word }
function Strip(WordToStrip: string;
CharToStripAway: Char): string;
var i: Integer;
begin

for i := length(WordToStrip)do
wnto 1do
begin

if WordToStrip <> ' ' then
begin

Strip := Copy(WordToStrip, 0, i);
exit;
end;

end;

Strip := '';
end;


var dat: file of char;
id3: array[0..TAGLEN] of char;
begin

vSaved := false;
vValid := True;
if FileExists(vFilename) then
begin

assignfile(dat, vFilename);
reset(dat);
seek(dat, FileSize(dat) - 128);
blockread(dat, id3, 128);
closefile(dat);
vMP3tag := copy(id3, 1, 3);
if vMP3Tag = 'TAG' then
begin

vTitle := strip(copy(id3, 4, 30), ' ');
vArtist := strip(copy(id3, 34, 30), ' ');
vAlbum := strip(copy(id3, 64, 30), ' ');
vComment := strip(copy(id3, 98, 30), ' ');
vYear := strip(copy(id3, 94, 4), ' ');
vGenreID := ord(id3[127]);
if vGenreID > Genres.Count then
vGenreID := 12;
vGenre := Genres[vGenreID];
{ Trigger OnChange Event }
if Assigned(onChangeFile) then
onChangeFile(Self);
end else
begin

vValid := False;
vTitle := '';
vArtist := '';
vAlbum := '';
vComment := '';
vYear := '';
vGenreID := 12;
vError := 'Wrong file format or no ID3 Tag !';
if Assigned(onError) then
onError(Self);
end;

end else
begin

vValid := False;
vError := 'Filedo
esn`t exist !';
if Assigned(onError) then
onError(Self);
end;

end;


{ Removes the ID3-tag from currently open file }

procedure TMP3Info.RemoveID3;
var dat: file of char;
begin

//do
es the file exist ?
if not FileExists(vFilename) then

begin

vError := 'Filedo
esn`t exist !';
if Assigned(onError) then
onError(Self);
exit;
end;

// is the file already untagged ?
if (vValid = false) then

begin

vError := 'File is already untagged !';
if Assigned(onError) then
onError(Self);
exit;
end;

// remove readonly-attribute
if (FileGetAttr(vFilename) and faReadOnly > 0) then

FileSetAttr(vFileName, FileGetAttr(vFilename) - faReadOnly);
// if readonly attr. already exists it cannot be removed to cut ID3 Tag
if (FileGetAttr(vFilename) and faReadOnly > 0) then

begin

vError := 'Can磘 write ID3 tag information !';
if Assigned(onError) then
onError(Self);
exit;
end;

// open current mp3 file if ID3 tag exists
if (vValid = true) then

begin

{I-}
assignfile(dat, vFilename);
reset(dat);
{I+}
if IOResult <> 0 then

begin

vError := 'Could not open file !';
if Assigned(onError) then
onError(Self);
exit;
end;

seek(dat, FileSize(dat) - 128);
truncate(dat);
// cut all 128 bytes of file
closefile(dat);
vValid := false;
// set vValid to false because the tag has been removed
end;

end;


{ Saves ID3 Tag to currently opened file }

procedure TMP3Info.Save;

{ Empties 128 character array }{do
n't tell me that there is a function for this in Pascal }
procedure EmptyArray(var Destination: array of char);
var i: Integer;
begin

for i := 0 to TAGLENdo
begin

Destination := ' ';
end;

end;


{ Insert a substring into character array at index position of array }
procedure InsertToArray(Source: string;
var Destination: array of char;
Index: Integer);
var i: Integer;
begin

for i := 0 to length(Source) - 1do
begin

Destination[Index + i] := Source[i + 1];
end;

end;


var dat: file of char;
id3: array[0..TAGLEN] of char;
begin

vSaved := true;
//do
es the filename exist ?
if FileExists(vFilename) then
begin

// fill 128 bytes long array with ID3 Tag information
EmptyArray(id3);
InsertToArray('TAG', id3, 0);
InsertToArray(vTitle, id3, 3);
InsertToArray(vArtist, id3, 33);
InsertToArray(vAlbum, id3, 63);
InsertToArray(vComment, id3, 97);
InsertToArray(vYear, id3, 93);
id3[127] := chr(vGenreID);
// remove readonly-attribute
if (FileGetAttr(vFilename) and faReadOnly > 0) then

FileSetAttr(vFileName, FileGetAttr(vFilename) - faReadOnly);
// if readonly attr. already exists it cannot be removed to write ID3
if (FileGetAttr(vFilename) and faReadOnly > 0) then

begin

vSaved := False;
vError := 'Can磘 write ID3 tag information !';
if Assigned(onError) then
onError(Self);
exit;
end;

// if valid then
overwrite existing ID3 Tag, else
append to file
if (vValid = True) then
begin

{I-}
assignfile(dat, vFilename);
reset(dat);
seek(dat, FileSize(dat) - 128);
blockwrite(dat, id3, 128);
closefile(dat);
{I+}
if IOResult <> 0 then
vSaved := false;
end else
begin

{I-}
assignfile(dat, vFilename);
reset(dat);
seek(dat, FileSize(dat));
blockwrite(dat, id3, 128);
closefile(dat);
{I+}
if IOResult <> 0 then
vSaved := false;
end
end else
begin

vValid := False;
vSaved := False;
vError := 'Filedo
esn`t exist or is not valid !';
if Assigned(onError) then
onError(Self);
end;

end;


procedure Register;
begin

RegisterComponents('Samples', [TMP3Info]);
end;


end.


{
The ID3 Information is stored in the last 128 bytes of an MP3 file.
The ID3 has the following fields, and the offsets given here, are from 0-127

Field Length offsets
-------------------------------------
Tag 3 0-2
Songname 30 3-32
Artist 30 33-62
Album 30 63-92
Year 4 93-96
Comment 30 97-126
Genre 1 127
}

 
请问?:xianjun
<<存放MP3的长度放在那儿?>>
 
FileSize就可以了!上面就这样定位的!
 
我记得有一个公式,现在找不到了,[:(]
 
:YB_unique
可能没有看清楚问题!
《存放MP3的长度放在那儿?》
不是这个文件的长度!我的意思是一个播放器在播放MP3时这个文件长度!
如果有了这个MP3长度的话,就可以知道它有多长的播放时间了!
 
GetFileSize()获得MP3长度!SetFilePosition()对播放长度定位!
还需要知道什么?
你可以播放一段长度,然后计算所用的时间,就知道长度和时间之间的转换关系了!
 
多人接受答案了。
 
后退
顶部