全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3343
推到 Plurk!
推到 Facebook!

你的第一個 MP3 Delphi播放器

 
cmf
尊榮會員


發表:84
回覆:918
積分:1032
註冊:2002-06-26

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-09-11 17:29:21 IP:61.218.xxx.xxx 未訂閱
你的第一個 MP3 Delphi播放器
Part 1: Delphi 演奏 MP3?我們需要TMediaPlayer!

你可能知道:
MP3 是一個 inaudible parts of music的音樂格式﹐而且資料是壓縮的
結果相當令人印象深刻。
當變換到 MP3 格式的時候 , 一首 64 MB 歌通常變成 3-4個 MB 。

MP3 是趨勢,而且信不信由你,它似乎是多媒體開發者的第一個作業建築一個MPEG Layer 3 播放器。

我們正在等候什麼?
讓我們看該如何使用Delphi TMediaPlayer 元件建築一個 MP3 播放器。
在這裡讓了我們不停止。
這一個文章將教你該如何摘錄 (和甚至改變)再多一些關於 MP3 的資訊。
最受歡迎的tag encryption 似乎是 ID3 。
這一個tag保存 MP3's 的標題,作家,類和一些其他的資料....
用我們的Delphi 編碼一個 MP3 播放器。
第一:
我們可以寫一個遠端控制另一個應用程式的程式像是 WinAmp 播放器。
第二:
我們可以使用像 XAudio 一樣的一些第三者 MP3 元件;
第三:
我們可以使用 DirectX IMediaControl 建築一個播放器。


TMediaPlayer componentTMediaPlayer icon
VCL 提供 TMediaPlayer 元件 (在元件板的系統 tab)給多媒體程式設計的所有主要的功能。
如果你順便探訪Delphi Help你將看見 "MediaPlayer 元件使你的應用程式能夠控制媒體演奏或錄音 , 像是一個光碟播放器,影像播放機/錄音器或 MIDI ".
MediaPlayer on Screen
MediaPlayer 的屬性 DeviceType 。
這屬性保存/含有可以被 TMediaPlayer 元件開啟的多媒體裝置類型。
一些多媒體裝置類型被定義﹐但是他們沒有詳盡的 MP3 。
預設值﹐當我們把 MediaPlayer 放在form上時﹐這屬性被設定成 dtAutoSelect 使裝置型態被自動地選擇基於副檔名。
在設計時間﹐我們在物件檢查員中使用一個檔案開放的對話盒藉由點一下橢圓按鈕指定檔名屬性(...)
如果我們在設計時間試著指定一個 MP3 檔案 , 我們將看見無 *.MP3 選擇;只有 AVI , MIDI 或WAVE.這將可能引導你走向 TMediaPlayer 不能夠再生 MP3 檔案-錯誤的結論!

Part 2: 建立 MP3 播放器Delphi Project's圖形用戶界面

Step by step...
這是啟動Delphi的時候-
new project 與一個空白form一起建立。(form1,預設值)
這將是主form和 mp3 播放器 project唯一的 form。
如 promissed ﹐我們的播放器將不只演奏 MP3 歌,我們想要播放器顯示 (和甚至改變)關於每個檔案的某些資訊-ID3 tag資料。
Why not even more:
讓我有一個progress bar 看目前的歌演奏進度。
加入下列元件到你的 form:
  • one ListBox component, name it 'mp3List'
  • one GroupBox component containing 6 Edit components (names: edTitle, edArtist, edAlbum, edYear, edGenre, edComment),
  • one BitBtn component, name it 'btnOpenFolder',
  • one StaticText component, name it 'txtFolder',
  • one Timer component, name it 'ProgresTimer'.
  • one ProgressBar component, name it 'Progres'.
  • and of course, one MediaPlayer component, name it 'mp3Player'.
    mp3 player at design time
    注意 當你放 MediaPlayer 元件在form上所有 9個按鈕是看得見的。
    一個簡單的播放器一些按鈕不是必需的。
    因此,除了btPlay , btPause , btStop使用 VisibleButtons 屬性並且影藏所有的按鈕
    BitBtn 和 StaticText 用來選擇並且顯示我們的 MP3 歌儲存的檔案夾。
    ListBox 列出挑選的檔案夾的所有的 MP3 檔案。
    只是因為 BitBtn 有 glyph 屬性 , 我已經選擇 BitBtn 代替標準的按鈕元件-我們可以容易地在它上面顯示圖片。
  • GroupBox 內的所有Edit元件將用來顯示 ID3 tag資料。

    連同 ProgressBar 的計時器元件將用來顯示演奏進行

    <!-- END ARTICLE CONTENT --> <!-- Multi-page feature Navigation. Use this only if the feature has multiple pages. -->
    Part 3: 建立 MP3 播放器Delphi Project's程式碼
    <!-- BEGIN FREQUENCY TEMPLATE -->
    Select the folder with MP3 files
    As stated before, the btnOpenFolder and the txtFolder are used to select and display the Folder where our MP3 songs are stored. To enable a user to select a list of mp3 songs from a directory on a system Delphi provides us with several possibilities. The OpenDialog component located on the Dialogs tab encapsulates the standard Windows dialog box for opening a file. Another approach is to use the SHBrowseForFolder Windows API function and to invoke a Windows system dialog used to browse for files and folders on users hard drive as well as network computers and printers. This second approach is exactly what the btnOpenFolder hides in his OnClick event. For a full code see the last part of this article: Project's Code.
    All the MP3 files from the selected folder are listed in the mp3List (that is the ListBox component). To list all the MP3 files in a given directory we use techniques described in the Searching For Files article.
    Display play progress
    The trick is simple. The TMediaPlayer Position property holds the current position of a song. The Lenght property specifies the length of the song selected by using the current time format, which is specified by the TimeFormat property. When the user selects a song from the list the following assignement is made
    ...
    Progress.Max := 0;
    {code to open a mp3 song}
    Progress.Max := mp3player.Length;
    ...

    and in the OnTimer event for the Timer (named 'ProgresTimer') component we have:
    procedure TForm1.ProgresTimerTimer
    (Sender: TObject);
    begin
    if Progress.Max <> 0 then
    Progress.Position := mp3player.Position;
    end;

    Play the MP3 file
    You would not believe this, but this is the simplest part. Since, by default, TMediaPlayer knows what to do when the user chooses Play or Stop button - everything we have to do is to prepare the MediaPlayer to accept/open a MP3 file. I'll give you here the whole procedure - the one that is executed when the user select's a song from the list:
    procedure TForm1.mp3ListClick(Sender: TObject);
    var mp3File:string;
    begin
    //if the list is empty don't do anything
    if mp3List.Items.Count=0 then exit;
    //file is FolderName FileName
    mp3File := Concat(txtFolder.Caption,
    mp3List.Items.Strings
    [mp3List.ItemIndex]);

    //Chechk again if it exists
    if not FileExists(mp3File) then begin
    ShowMessage('MP3 file does not exist?!');
    exit;
    end;

    //used to display the ID3 tag information
    FillID3TagInformation (mp3File,
    edTitle,
    edArtist,
    edAlbum,
    edYear,
    edGenre,
    edComment);

    Progress.Max:=0;

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


    Progress.Max := mp3player.Length;
    end;


    mp3Player at run time

    Part 4: MP3 ID3 Tag Editing <!-- BEGIN FREQUENCY TEMPLATE -->
    <!--END FREQUENCY TEMPLATE--> <!-- BEGIN ARTICLE CONTENT -->The thing that makes MP3 files even more great are ID3 tags. Every MP3 file has a little blurb of data on it, which is used to give informations about artist, title, album, publishing year and genre about a song. The "ID3" Tag is attached to most MP3 files these days. The tag is always 128 bytes long and is located at very end of the MP3-file.
    The ID3 tag is saved in the last 128 bytes of a MP3 file. ID3 tag should start with a "TAG" string. If this string is absent that means that ID3 information has been removed - or was never set. But don't worry - all we have to do is append it to the file.
    The ID3-Tag structure can be described as follows:
    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;

    Note that genres are determined by one byte of data only. This byte has to be translated into text from the following declaration:
    const
    MaxID3Genre=147;

    ID3Genre: array[0..MaxID3Genre] of string = (
    'Blues', 'Classic Rock', 'Country', 'Dance',
    ...
    'Synthpop' {and probably more to come}
    );

    Read ID3
    To read the ID3 tag from a MP3 song we have to go down to file system and use IO routines. Here goes the code to read the ID3 information:
    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;

    This code uses the TFileStream to access the information in MP3 file. Once we have successfully opened a Mp3 file set the position to EndOfFile-128 bytes and read the ID3 tag. The rest of the code in this procedure simply checks whether there is an ID3 tag information in a file and fills those Edit boxes (parameters in this procedure) with values.
    Write ID3
    The writing part is simple too. This is the function declaration, the whole code can be found in the Project's code part of this article.
    procedure ChangeID3Tag (NewID3: TID3Rec; mp3FileName: string);
    Note that in the Project's code the call to this function is not covered. This is something I'll leave to you to implement.
    Before the end
    Finally, we've made it! You have your own ready-to-play-and-get-some-money MP3 player working. What I want do to here is to suggest to "play" with it a little and modify it a lot. How about adding some kind of skin to this player in the means of custom shaped forms. There are certainly some great ideas you can compose in this project, let the other see what you have made: post you creation to the Free Applications section on this site. <!-- END ARTICLE CONTENT --> <!-- Multi-page feature Navigation. Use this only if the feature has multiple pages. -->
     
    完整程式列表如下
    {
    Article: Your first MP3 Delphi player    http://delphi.about.com/library/weekly/aa112800a.htm    See how to build a full-blown mp3 player with Delphi
    in just a few seconds. Even more: get the ID3 tag
    information from a mp3 file and change it!    For the .zip file of this project click here.    }    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.    {
    ********************************************
    Zarko Gajic
    About.com Guide to Delphi Programming
    http://delphi.about.com
    email: delphi.guide@about.com
    free newsletter: http://delphi.about.com/library/blnewsletter.htm
    forum: http://forums.about.com/ab-delphi/start/
    ********************************************
    }        
    ------
    ︿︿
    系統時間:2024-04-29 20:43:34
    聯絡我們 | Delphi K.Top討論版
    本站聲明
    1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
    2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
    3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!