Ваш первый MP3-плейер

Статьи » Мультимедиа » Ваш первый MP3-плейер

MP3 сейчас, пожалуй, наиболее популярный формат для хранения музыки. Давайте напишем плейер, способный воспроизводить музыку в этом формате + некоторые дополнительные возможности. Все, что нам для этого понадобится - это компонента TMediaPlayer и немного времени. Вы думаете, TMediaPlayer не умеет проигрывать MP-шки? Вы, к счастью, ошибаетесь.

 Итак, ищем компоненту TMediaPlayer

на вкладке System

палитры компонент Delphi. Если вы посмотрите в помощи, то увидите что-нибудь типа "MediaPlayer component enables your application to control a media playing or recording device such as a CD-ROM player, video player/recorder, or MIDI sequencer." Ни слова о MP3. MediaPlayer

имеет свойство DeviceType

, определяющее тип устройства, которым можно управлять с помощью этой компоненты, но в списке устройств вы опять-таки не найдете что-нибудь похожее на MP3. Однако это не значит, что MP3 не поддерживается.

    Будем считать, что среда Delphi уже запущена и открыта форма по умолчанию form1. Это первая и последняя форма в нашем приложении.    Как и было обещано, наш проигрыватель будет не только воспроизодить MP3-файлы, но и читать (и изменять) так называемый тэг ID3. И даже больше - у нас будет прогресс-бар, показывающий какую часть музыкального произведения мы слушаем.
   На форму добавьте следующие компоненты:

  • Со вкладки Standard

    : компоненту ListBox, назовите ее 'mp3List'; компоненту GroupBox, содержащую 6 компонент Edit (названных: edTitle, edArtist, edAlbum, edYear, edGenre, edComment);

  • Со вкладки Additional

    : компоненту BitBtn, назовите ее 'btnOpenFolder'; компоненту StaticText c именем 'txtFolder';

  • Со вкладки System

    : компоненту Timer, назовите ее 'ProgresTimer'; компоненту ProgressBar, назовите ее 'Progres'; и, конечно, компоненту MediaPlayer, назовите ее 'mp3Player'.

Дизайн - личное дело каждого, можно предложить, например, такой вариант:

Замечание: когда вы помещаете компоненту MediaPlayer на форму, она

Замечание: когда вы помещаете компоненту MediaPlayer

на форму, она содержит 9 кнопок. Так как в нашем приложении используется всего 3 кнопки, измените свойство VisibleButtons

для отображения только трех кнопок (btPlay

, btPause

, btStop

).

   Компоненты BitBtn

и StaticText

служат для определения и отображения каталога, из которого беруться MP3-файлы. Список файлов отображается в компоненте ListBox

. Компоненты Edit

служит для отображения информации тэга ID3. И, наконец, компонента Timer

вместе с ProgressBar

служит для отображения прослушиваемой части музыкальной композиции.

 

Теперь нужно написать код, обеспечивающий функциональность нашего MP3-плейера.

Выбор каталога с MP3-файлами

Как было сказано выше, для выбора и отображением каталога используются компоненты, названные btnOpenFolder

и txtFolder

. Как реализована данная функция, смотрите в полном листинге программы.

Отображение прогресс-бара

Здесь все просто. Свойство Position

компоненты TMediaPlayer

содержит текущую позицию в проигрываемом файле. Свойство Length

содержит длину проигрываемой композиции. Когда пользователь выбирает какую-нибудь песню из списка, выполняется следующий кусок кода:  

...

Progress.Max := 0;
{код для открытия mp3} Progress.Max := mp3player.Length; ...

 

А в обработчике события OnTimer

компоненты Timer

содержится следующий код:  

procedure TForm1.ProgresTimerTimer (Sender: TObject); begin
   if Progress.Max <> 0 then       Progress.Position := mp3player.Position; end;

 

Проигрывание MP3-файла

Вы не поверите, но это простейшая секция во всей программе. Все, что нужно сделать - сформировать имя файла и передать его в MediaPlayer

.
 

procedure TForm1.mp3ListClick(Sender: TObject); var mp3File:string;
begin
//если список пустой - не делать ничего    if mp3List.Items.Count=0 then exit; //имя файла = каталог + FileName    mp3File := Concat(txtFolder.Caption,       mp3List.Items.Strings       [mp3List.ItemIndex]);

//проверить существование файла    if not FileExists(mp3File) then begin       ShowMessage('MP3 file does not exist?!');       exit;    end;

//отобразить информацию ID3    FillID3TagInformation (mp3File,       edTitle,       edArtist,       edAlbum,       edYear,       edGenre,       edComment);

   Progress.Max:=0;

   mp3player.Close;    mp3player.FileName:=mp3File;    mp3player.Open;

   Progress.Max := mp3player.Length; end;

 

Просмотр и редактирование тэга ID3

Тэг ID3 содержит информацию о композиции: исполнитель, жанр и т.п. Этот кусок информации содержится в последних 128 байтах файла. Начинается тэг словом "TAG". Его может и не быть, если тэг удален или не был заполнен при создании. Однако его всегда можно добавить. Тэг ID3 имеет следующий формат:  

type TID3Rec = packed record    Tag : array[0..2] of Char;    Title,    Artist,    Comment,    Album : array[0..29] of Char;    Year : array[0..3] of Char;    Genre : Byte; end;

 

Как видно, жанр кодируется всего байтом, поэтому нужно следующее описание для декодирования этой информации:  

const MaxID3Genre=147;
ID3Genre: array[0..MaxID3Genre] of string = (    'Blues', 'Classic Rock', 'Country', 'Dance',    ...

   'Synthpop' {возможно, список будет расширен} );

 

Для чтения тэга ID3 служит процедура FillID3TagInformation

:  

procedure FillID3TagInformation (mp3File: string; Title,Artist,Album,Year,Genre,Comment:TEdit); var ID3 : TID3Rec;
fmp3: TFileStream;
begin
   fmp3:=TFileStream.Create(mp3File, fmOpenRead);    try       fmp3.position:=fmp3.size-128;       fmp3.Read(ID3,SizeOf(ID3));    finally       fmp3.free; end;

if ID3.Tag <> 'TAG' then begin    Title.Text:='Wrong or no ID3 tag information';    Artist.Text:='Wrong or no ID3 tag information';    Album.Text:='Wrong or no ID3 tag information';    Year.Text:='Wrong or no ID3 tag information';    Genre.Text:='Wrong or no ID3 tag information';    Comment.Text:='Wrong or no ID3 tag information'; end else begin
   Title.Text:=ID3.Title;    Artist.Text:=ID3.Artist;    Album.Text:=ID3.Album;    Year.Text:=ID3.Year;    if ID3.Genre in [0..MaxID3Genre] then       Genre.Text:=ID3Genre[ID3.Genre]    else       Genre.Text:=IntToStr(ID3.Genre);    Comment.Text:=ID3.Comment end;
end;

 

Этот код использует объект TFileStream

для доступа к тэгу ID3. После открытия файла указатель устанавливается на позицию EndOfFile-128. Если в этой позиции найдено слово "TAG", информация копируется в соответствующие поля редактирования, иначе эти поля заполняются сообщениями по умолчанию.

Вот, пожалуй, и все. Запись тэга ID3 предлагается к самостоятельному изучению - пусть хоть что-то напишется вашими руками. На следующей странице вы найдете полный исходный текст приложения.

 

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, MPlayer, ComCtrls, ExtCtrls;

type
TForm1 = class(TForm)
mp3player: TMediaPlayer; mp3List: TListBox;
btnOpenFolder: TBitBtn;
GroupBox1: TGroupBox;
edTitle: TEdit;
edArtist: TEdit;
edAlbum: TEdit;
edYear: TEdit;
edGenre: TEdit;
edComment: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
txtFolder: TStaticText;
Progress: TProgressBar;
ProgresTimer: TTimer;
procedure btnOpenFolderClick(Sender: TObject); procedure mp3ListClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ProgresTimerTimer(Sender: TObject); private
{ Private declarations } public
{ Public declarations }
end;

var
Form1: TForm1;

type
TID3Rec = packed record
Tag : array[0..2] of Char; Title,
Artist,
Comment,
Album : array[0..29] of Char; Year : array[0..3] of Char; Genre : Byte;
end;

const
MaxID3Genre=147;
ID3Genre: array[0..MaxID3Genre] of string = ( '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', 'Psychadelic', 'Rave', 'Showtunes', 'Trailer', 'Lo-Fi', 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro', 'Musical', 'Rock & Roll', 'Hard Rock', 'Folk', 'Folk-Rock', 'National Folk', 'Swing', 'Fast Fusion', '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', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle', 'Duet', 'Punk Rock', 'Drum Solo', 'Acapella', 'Euro-House', 'Dance Hall', 'Goa', 'Drum & Bass', 'Club-House', 'Hardcore', 'Terror', 'Indie', 'BritPop', 'Negerpunk', 'Polsk Punk', 'Beat', 'Christian Gangsta Rap', 'Heavy Metal', 'Black Metal', 'Crossover', 'Contemporary Christian', 'Christian Rock', 'Merengue', 'Salsa', 'Trash Metal', 'Anime', 'Jpop', 'Synthpop' {and probably more to come} );

implementation

uses ShellAPI, ShlObj; // needed for the BrowseForFolder function

{$R *.DFM}

procedure FillID3TagInformation(mp3File:string; Title,Artist,Album,Year,Genre,Comment:TEdit); var //fMP3: file of Byte; ID3 : TID3Rec;
fmp3: TFileStream;
begin
fmp3:=TFileStream.Create(mp3File, fmOpenRead); try
fmp3.position:=fmp3.size-128; fmp3.Read(ID3,SizeOf(ID3)); finally
fmp3.free;
end;

{ or the non Stream approach - as in ChangeID3Tag procedure try
AssignFile(fMP3, mp3File); Reset(fMP3);
try
Seek(fMP3, FileSize(fMP3) - 128); BlockRead(fMP3, ID3, SizeOf(ID3)); finally
end;
finally
CloseFile(fMP3);
end;
}

if ID3.Tag <> 'TAG' then begin Title.Text:='Wrong or no ID3 tag information'; Artist.Text:='Wrong or no ID3 tag information'; Album.Text:='Wrong or no ID3 tag information'; Year.Text:='Wrong or no ID3 tag information'; Genre.Text:='Wrong or no ID3 tag information'; Comment.Text:='Wrong or no ID3 tag information'; end else begin
Title.Text:=ID3.Title;
Artist.Text:=ID3.Artist; Album.Text:=ID3.Album;
Year.Text:=ID3.Year;
if ID3.Genre in [0..MaxID3Genre] then Genre.Text:=ID3Genre[ID3.Genre] else
Genre.Text:=IntToStr(ID3.Genre); Comment.Text:=ID3.Comment end;
end;


procedure ChangeID3Tag(NewID3: TID3Rec; mp3FileName: string); var
fMP3: file of Byte;
OldID3 : TID3Rec;
begin
try
AssignFile(fMP3, mp3FileName); Reset(fMP3);
try
Seek(fMP3, FileSize(fMP3) - 128); BlockRead(fMP3, OldID3, SizeOf(OldID3)); if OldID3.Tag = 'TAG' then { Replace old tag }
Seek(fMP3, FileSize(fMP3) - 128) else
{ Append tag to file because it doesn't exist } Seek(fMP3, FileSize(fMP3)); BlockWrite(fMP3, NewID3, SizeOf(NewID3)); finally
end;
finally
CloseFile(fMP3);
end;
end;


procedure FillMP3FileList(Folder: string; sl: TStrings); var Rec : TSearchRec;
begin
sl.Clear;
if SysUtils.FindFirst(Folder + '*.mp3', faAnyFile, Rec) = 0 then try
repeat
sl.Add(Rec.Name);
until SysUtils.FindNext(Rec) <> 0; finally
SysUtils.FindClose(Rec); end;
end;

function BrowseDialog(const Title: string; const Flag: integer): string; var
lpItemID : PItemIDList;
BrowseInfo : TBrowseInfo; DisplayName : array[0..MAX_PATH] of char; TempPath : array[0..MAX_PATH] of char; begin
Result:='';
FillChar(BrowseInfo, sizeof(TBrowseInfo), #0); with BrowseInfo do begin hwndOwner := Application.Handle; pszDisplayName := @DisplayName; lpszTitle := PChar(Title); ulFlags := Flag;
end;
lpItemID := SHBrowseForFolder(BrowseInfo); if lpItemId <> nil then begin SHGetPathFromIDList(lpItemID, TempPath); Result := IncludeTrailingBackslash(TempPath); GlobalFreePtr(lpItemID); end;
end;


procedure TForm1.btnOpenFolderClick(Sender: TObject); var mp3Folder : string;
begin
mp3Folder := BrowseDialog('Choose a folder with mp3 files', BIF_RETURNONLYFSDIRS); if mp3Folder = '' then Exit;

txtFolder.Caption := mp3Folder;

FillMP3FileList(mp3Folder, mp3List.Items); end;

procedure TForm1.mp3ListClick(Sender: TObject); var mp3File: string;
begin
if mp3List.Items.Count=0 then exit; mp3File := Concat(txtFolder.Caption, mp3List.Items.Strings[mp3List.ItemIndex]); if not FileExists(mp3File) then begin ShowMessage('MP3 file '+#13#10+ mp3File +#13#10+'does not exist!'); exit;
end;

FillID3TagInformation(mp3File, edTitle, edArtist, edAlbum, edYear, edGenre, edComment);

Progress.Max:=0;

mp3player.Close; mp3player.FileName:=mp3File; mp3player.Open;

Progress.Max := mp3player.Length; end;

procedure TForm1.FormCreate(Sender: TObject); begin
txtFolder.Caption := ExtractFilePath(Application.ExeName); FillMP3FileList(txtFolder.Caption, mp3List.Items); Progress.Max:=0;
end;

procedure TForm1.ProgresTimerTimer(Sender: TObject); begin
if Progress.Max<>0 then Progress.Position := mp3player.Position; end;
end.

Источник http://www.realcoding.net/

Другое по теме:

Категории

Статьи

Советы

Copyright © 2022 - All Rights Reserved - www.delphirus.com