Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.
Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...
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. И даже больше - у
нас будет прогресс-бар, показывающий какую часть музыкального произведения мы
слушаем.
На форму добавьте следующие компоненты:
: компоненту ListBox, назовите ее 'mp3List'; компоненту GroupBox, содержащую 6 компонент Edit (названных: edTitle, edArtist, edAlbum, edYear, edGenre, edComment);
: компоненту BitBtn, назовите ее 'btnOpenFolder'; компоненту StaticText c именем 'txtFolder';
: компоненту Timer, назовите ее 'ProgresTimer'; компоненту ProgressBar, назовите ее 'Progres'; и, конечно, компоненту MediaPlayer, назовите ее 'mp3Player'.
Дизайн - личное дело каждого, можно предложить, например, такой вариант:
Замечание: когда вы помещаете компоненту MediaPlayer
на форму, она содержит 9 кнопок. Так как в нашем приложении используется всего 3 кнопки, измените свойство VisibleButtons
для отображения только трех кнопок (btPlay
, btPause
, btStop
).
Компоненты BitBtn
и StaticText
служат для определения и отображения каталога, из которого беруться MP3-файлы. Список файлов отображается в компоненте ListBox
. Компоненты Edit
служит для отображения информации тэга ID3. И, наконец, компонента Timer
вместе с ProgressBar
служит для отображения прослушиваемой части музыкальной композиции.
Теперь нужно написать код, обеспечивающий функциональность нашего MP3-плейера.
Выбор каталога с MP3-файлами
Как было сказано выше, для выбора и отображением каталога используются компоненты, названные btnOpenFolder
и txtFolder
. Как реализована данная функция, смотрите в полном листинге программы.
Отображение прогресс-бара
Здесь все просто. Свойство Position
компоненты TMediaPlayer
содержит текущую позицию в проигрываемом файле. Свойство Length
содержит длину проигрываемой композиции. Когда пользователь выбирает какую-нибудь песню из списка, выполняется следующий кусок кода:
...
|
А в обработчике события OnTimer
компоненты Timer
содержится следующий код:
procedure TForm1.ProgresTimerTimer (Sender: TObject);
begin
|
Проигрывание MP3-файла
Вы не поверите, но это простейшая секция во всей программе. Все, что нужно сделать - сформировать имя файла и передать его в MediaPlayer
.
procedure TForm1.mp3ListClick(Sender: TObject);
var mp3File:string;
|
Просмотр и редактирование тэга 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;
|
Для чтения тэга ID3 служит процедура FillID3TagInformation
:
procedure FillID3TagInformation (mp3File: string;
Title,Artist,Album,Year,Genre,Comment:TEdit);
var ID3 : TID3Rec;
|
Этот код использует объект 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/