由于经常涉及到背景音乐等流媒体格式的处理,在codeproject上看到了一篇相关文章,比较不错
在此翻译一下,供后来者参考
原文链接:http://www.codeproject.com/KB/dotnet/Windows7_Mp3_Player.aspx
Introduction
简介
In this article, we will see how we can develop an MP3 player, using C#.NET, which
will use some of the new features of Windows 7.
We will show the progress of the song being played using the "Progress bar" in Taskbar.
We will also show the Album art of the song as the "Thumbnail" and we will also have a
Thumbnail Toolbar which has the Play/Pause, Next and Previous buttons.
在这个文章中,我们将会看到如何开发一个使用到一些win7新特性的MP3播放器,
使用C#.net开发。我们将会使用任务栏中的进度条来显示MP3播放进度,
我们也会使用歌曲唱片集的封面图片,并且我们也有一个具有播放,暂停,
下一首和上一首按钮的工具栏。
Prerequisites
预备知识
- To play MP3 songs, we will be using the BASS Audio Library.播放MP3歌曲,
- 我们将使用BASS Audio Library来完成
- We will also need Bass.net which is the .NET API for BASS. 我们也会用到Bass.net,
- 这个是上者的.net接口
- TagLib Sharp: We will use this library to read tagging information about
- the song being played. TagLib Sharp,我们使用这个库来读取歌曲的标签信息
- Windows® API Code Pack for Microsoft® .NET Framework Windows API 代码包
Developing the Application
开发应用程序
The Player
播放器
- Create a new project in Visual Studio 在Visual Studio中创建一个新项目
- Add the existing projects Shell and Core which can be found under the WindowsAPICodePack\shell and WindowsAPICodePack\core
- folders 添加已存在的工程框架,在WindowsAPICodePack\Shell和WindowsAPICodePack\core文件夹中可以找到。
- Add a reference to the above projects and import the following namespaces:
- 在上面的工程中添加以下引用,并引入以下命名空间
Microsoft.WindowsAPICodePack.Dialogs
Microsoft.WindowsAPICodePack.Taskbar
Microsoft.WindowsAPICodePack.Shell
The first part of the development is developing the player which will have the basic
functionality like Play/Pause, Stop, next Previous/
Next and Add/Remove songs
Buttons. The main form in our application has 7 Buttons, A listbox,
Label and a
Picture Box.
开发的第一个部分是开发具有像播放暂停,停止,下一首和上一首,添加删除歌曲按钮的播放器,
我们的应用程序有7个按钮在主窗体上,还有一个Label,一个listbox,一个picturebox。
We will use the Picture Box to display the Album Art and we will use the Label to
display the seconds remaining while a song is being played.
我们将会使用PictureBox来显示唱片集,我们用label来显示歌曲播放的秒数
Note: Make sure you have added references for Core, Shell, Bass.net and taglib-sharp.
Also add bass.dll to your project (Make sure you have set "Copy to Output Directory"
as "Copy Always".)
注:确定你已经为Core,Shell,Bass.net和taglib-sharp添加了引用,并且添加bass.dll
到你的工程中(确定你已经设定拷贝到输出文件夹项目设定为“一直拷贝”)
Player Class: This class has all the methods which we will be using to play MP3 files.
The first step is to initialize an output device. We useBass.BASS_Init() for this.
Following are the parameters:
Player类:这个类具有所有的播放MP3文件的方法,第一步是初始化一个输出设备,我们使用
Bass.BASS_Init() 来完成这个步骤。按照以下步骤进行
- -1 denotes default device. -1代表默认设备
- 44100 is the frequency. 44100 是频率
BASSInit.BASS_DEVICE_DEFAULT denotes th default device to use BASSInit.BASS_DEVICE_DEFAULT代表使用的默认设备
System.IntPtr.Zero denotes the application's main window which is the current foreground window. System.IntPtr.Zero代表应用程序的主窗口,作为当前的主窗口
Before playing a song, we must first create a stream. We use BASS_StreamCreateFile()
to create a stream from a file. We then useBASS_ChanelPlay() to play the stream which
we created in the LoadSong() function.
在播放一首歌的值钱,我们必须先创建 一个流。我们使用BASS_StreamCreateFile()
来从文件中创建一个流。我们只用使用BASS_ChangelPlay() 来播放通过LoadSong来创建的流。

class player
{
int stream;
public player()
{
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, System.IntPtr.Zero);
}
public void LoadSong(string location)
{
stream = Bass.BASS_StreamCreateFile
(location, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT);
}
public void PlaySong()
{
Bass.BASS_ChannelPlay(stream,false);
}
public void StopSong()
{
Bass.BASS_ChannelStop(stream);
}
public void PauseSong()
{
Bass.BASS_ChannelPause(stream);
}
~player()
{
Bass.BASS_Free();
}
}
Song Length and Album Art
歌曲长度及唱片集
Once the player is ready, we will use Taglib sharp to get the length of the song and
album art. We will use the picture box to display the album art. We will also use
this picture box's location and size to create the Thumbnail.
一旦播放器准备就绪,我们使用Taglib sharp来获取歌曲的长度和专辑封面。
我们将会使用picturebox来显示唱片集封面。我们激昂会也使用picture box的地点
和调整封面的大小。
Once we create the TagLib file from a file (in this case, the selected item in the
playlist listbox), we will use Properties.Duration.TotalSeconds to get the
length of the song in seconds. We will be using this value to populate the Label
and the set the progressbar value.
一旦我们从文件中创建了TagLib文件(在这时,选择的项目显示在播放列表listbox中),我们将要使用Properties.duration.TotalSeconds来以秒为单位得到歌曲的长度。我们将要好用这个值来设置Label和设定进度条值。

private void GetSongLength()
{
if (playlist.SelectedItem != null)
{
TagLib.File f = TagLib.File.Create(playlist.SelectedItem.ToString());
songLength = (int)f.Properties.Duration.TotalSeconds;
}
}
We will also be using taglib sharp to get the album art of the song which is being
currently played. Some songs may not have an Album art so we will useTagLibfile.Tag.Pictures.Length to get the numbers of pictures associated
with the song. If it is more than zero, then we load the picture box with the album art.
我们将要也使用taglibsharp来获取正在播放的歌曲的唱片集封面,一些歌曲可能不会有唱片集封面,
所以我们会使用TagLibfile.Tag.Pictures.Length来获取图片的数目。入股必0打,那么我们在picturebox中显示唱片集封面。

private void SetAlbumArt()
{
if (playlist.SelectedItem != null)
{
TagLib.File file = TagLib.File.Create(playlist.SelectedItem.ToString());
if (file.Tag.Pictures.Length > 0)
{
var bin = (byte[])(file.Tag.Pictures[0].Data.Data);
albumart.Image =
Image.FromStream(new MemoryStream(bin)).GetThumbnailImage
(100, 100, null, IntPtr.Zero);
}
else
{
albumart.Image = Properties.Resources.gramophone;
}
}
}
Progressbar, Thumbnail Toolbar and Player Buttons
Create Taskbar buttons and instance of TaskbarManager.

player player;
int playState, songLength, timerCount;
private ThumbnailToolbarButton buttonPlayPause;
private ThumbnailToolbarButton buttonNext;
private ThumbnailToolbarButton buttonPrevious;
TaskbarManager tbManager = TaskbarManager.Instance;
public Form1()
{
InitializeComponent();
player = new player();
playState = 1;
songLength = 0;
timerCount = 1;
}
This is the main function which will play the song. First we call the SetAlbumArt()
function which will set the album art. We use SetTaskBarthumbnail()function to
the set the thumbnail. Explanation for this function comes later in this article.
We will use GetSongLength() and SetTimerforPlay() to get the song length and
activate the timer respectively.
这个主函数用来播放歌曲,首先我们调用SetAlbumArt()函数来设置唱片集封面,
我们是用SetTaskBarthumbnail()函数来设置thumbnail。这个函数我们将在后文解释。
我们将要使用GetSongLength函数和SetTimerforPlay()函数来获得歌曲长度,
并且激活计时器。

private void PlaySelectedSong()
{
SetAlbumArt();
SetTaskbarthumbnail();
GetSongLength();
timerCount = 1;
SetTimerforPlay();
if (playlist.SelectedItem != null)
{
buttonPlayPause.Icon = Properties.Resources.Pause;
player.StopSong();
player.LoadSong(playlist.SelectedItem.ToString());
player.PlaySong();
this.Text = playlist.SelectedItem.ToString().Substring
(playlist.SelectedItem.ToString().LastIndexOf("\\") + 1,
(playlist.SelectedItem.ToString().Length -
(playlist.SelectedItem.ToString().LastIndexOf("\\") + 1)));
}
}

//Play song when the song is double clicked in the Listbox
private void playlist_DoubleClick(object sender, EventArgs e)
{
PlaySelectedSong();
}

private void btnPrevious_Click(object sender, EventArgs e)
{
PlayPreviousSong();
}

private void PlayPreviousSong()
{
if ((playlist.SelectedIndex - 1) >= 0)
{
playlist.SelectedItem = playlist.Items[playlist.SelectedIndex - 1];
PlaySelectedSong();
}
}

private void btnNext_Click(object sender, EventArgs e)
{
PlayNextSong();
}

private void PlayNextSong()
{
if ((playlist.SelectedIndex + 1) < playlist.Items.Count)
{
playlist.SelectedItem =
playlist.Items[playlist.SelectedIndex + 1];
PlaySelectedSong();
}
}

private void btnAddSong_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
playlist.Items.Add(openFileDialog.FileName);
}
}

private void btnRemoveSong_Click(object sender, EventArgs e)
{
playlist.Items.Remove(playlist.SelectedItem);
}
In the below function, we first check whether the song is paused. We use the value
of playState for this. Value zero means the song is paused and we use the PlaySong()
function to continue playing the song. If the value is not zero, then it denotes that
the song should be played from the beginning. In this case, we load the song and
then play it.
在这个函数的中,我们首先检查歌曲是否暂停。我们使用playState的值来确定。
0值代表歌曲暂停,我们使用PlaySong()函数来继续播放歌曲。如果值非0,
代表歌曲应该从头播放。在这个情况,我们读取歌曲然后播放。

private void btnPlay_Click(object sender, EventArgs e)
{
if (playState == 0)
{
//Paused state so start playing
player.PlaySong();
playState = 1;
SetTimerforPlay();
}
else
{
//Play from Beginning
PlaySelectedSong();
}
buttonPlayPause.Icon = Properties.Resources.Pause;
}

private void btnPause_Click(object sender, EventArgs e)
{
buttonPlayPause.Icon = Properties.Resources.play;
player.PauseSong();
playState = 0;
SetTimerforPause();
}
This function is called just before playing the song to enable the timer and set the
progress bar style. TaskbarProgressBarState.Normal denotes that the progress
will be normal. Timer's interval is set as 1000 ms.
这个函数在开始播放歌曲,开启计时器和设置进度条风格之前调用。TaskbarProgressBarState.Normal代表进度将会被初始化。计时器间隔设置为1000ms。

//Set progressbar Style and Enable Timer
private void SetTimerforPlay()
{
tbManager.SetProgressState(TaskbarProgressBarState.Normal);
progressbarTimer.Enabled = true;
}
This is similar to SetTimerforPlay() but we will disable the timer to stop the
progress in the progress bar. At the same time, we will also set its style toTaskbarProgressBarState.Error so that the color is set as Red. This function
is called when the song is paused.
这个与SetTimerforPlay()类似,但是我们将会禁止计时器来停止进度条。在同时,
我们将会设置这个风格到TaskbarProgressBarState.Error,这样颜色被设置为红色。
这个函数当歌曲暂停时调用。

private void SetTimerforPause()
{
tbManager.SetProgressState(TaskbarProgressBarState.Error);
progressbarTimer.Enabled = false;
}

private void btnStop_Click(object sender, EventArgs e)
{
player.StopSong();
}
We will be using TabbedThumbnail.SetThumbnailClip to set the thumbnail for
our MP3 player. For this, we create a new Rectangle selection inside the main
form and then set it as the thumbnail clip. Our motive is to use the Album art
which we have already loaded in the Picture Box. Note: I had to make some
adjustments in the Height and Width of the rectangle selection to get a proper thumbnail.
我们将会使用TabbedThumbnail.SetThumbnailClip来设置thumbnail为我们的mp3播放器。
为了这个目的,我们创建一个新的矩形选框在主窗口中,然后设置作为thumbnail clip.
我们的目的是是使用已经加载到图片框中的唱片集封面。
注意:我已经做了一些宽度和高度的优化在矩形选框中。

private void SetTaskbarthumbnail()
{
TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip
(this.Handle,new Rectangle(albumart.Location.X+4,
albumart.Location.Y,albumart.Size.Width-1,albumart.Size.Height-4));
}
Thumbnail Toolbar should be created during the Form's Shown event.
ThumbnailToolbarButton accepts two parameters:
Thumbnail工具来应该在窗体show事件时创建,ThumbnailToolbarButton有以下两个参数
Icon: The Icon to be used for the button. 图标:为按钮使用的图标
Tooltip: The tool tip for the button. 工具条:为按钮的工具条提示
We also add an Event Handler for each of the Button's Click events.
我们也会添加一个事件响应为每个按钮的点击事件。

private void Form1_Shown(object sender, EventArgs e)
{
buttonPlayPause = new ThumbnailToolbarButton
(Properties.Resources.play, "Play");
buttonPlayPause.Enabled = true;
buttonPlayPause.Click +=
new EventHandler<thumbnailbuttonclickedeventargs>(buttonPlay_Click);
buttonNext = new ThumbnailToolbarButton
(Properties.Resources.nextArrow, "Next");
buttonNext.Enabled = true;
buttonNext.Click +=
new EventHandler<thumbnailbuttonclickedeventargs>(buttonNext_Click);
buttonPrevious = new ThumbnailToolbarButton
(Properties.Resources.prevArrow, "Previous");
buttonPrevious.Click +=
new EventHandler<thumbnailbuttonclickedeventargs>(buttonPrevious_Click);
TaskbarManager.Instance.ThumbnailToolbars.AddButtons
(this.Handle, buttonPrevious, buttonPlayPause, buttonNext);
TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip
(this.Handle, new Rectangle(albumart.Location, albumart.Size));
}
Thumbnail Toolbars : Play/Pause, Next and Previous Buttons

void buttonPlay_Click(object sender, EventArgs e)
{
if (playState == 0)
{
player.PlaySong();
playState = 1;
buttonPlayPause.Icon = Properties.Resources.Pause;
buttonPlayPause.Tooltip = "Pause";
SetTimerforPlay();
}
else
{
player.PauseSong();
playState = 0;
buttonPlayPause.Icon = Properties.Resources.play;
buttonPlayPause.Tooltip = "Play";
SetTimerforPause();
}
}

void buttonNext_Click(object sender, EventArgs e)
{
PlayNextSong();
}

void buttonPrevious_Click(object sender, EventArgs e)
{
PlayPreviousSong();
}
Progressbar
进度条
Timer's interval is set to 1000ms and it will be enabled as soon as the play button is
pressed. We use the SongLength to set the maximum value of the progressbar. and
increment the progress value every second. Timer will be disabled as soon as the
pause button is pressed.
计时器响应间隔被设置为1000ms,一旦播放按钮按下去就会被激活,我们使用
SongLength来设置进度条的最大值,并且每秒度增加进度条值,计时器将会在暂停按钮
单击时停止。

private void progressbarTimer_Tick(object sender, EventArgs e)
{
if (timerCount <= songLength)
{
tbManager.SetProgressValue(timerCount, songLength);
}
lblSeconds.Text = (songLength - timerCount).ToString() + " seconds";
timerCount += 1;
}
Player in Action
响应时的播放器
Play
Thumbnail
Thumbnail while Paused
Thumbnail while Playing
Progressbar while Paused
Conclusion
总结
This is a basic MP3 player which was developed in few hours. The idea was to use
progress bar differently. Comments and suggestions are always welcome.
这个简易的MP3播放器可以在若干小时内就能开发成功,开发初衷是用不同的方式使用进度条,
欢迎大家提出建议和参加评论。
References and Useful Links
参考链接
History
- Initial release: 31st January, 2010
License
This article, along with any associated source code and files, is licensed under
The Code Project Open License (CPOL)
About the Author
Shoban Kumar
Member
Shoban Kumar currently works with Allianz Cornhill India in Trivandrum as
a Senior Software Engineer. He is one of the core member of Kerala Microsoft User's Group http://www.k-mug.org.
He actively writes .net articles in his blog http://www.codegeeks.net and http://www.dotnetcurry.com.
He has also written many open source applications which can be found in Codeplex :http://www.codeplex.com/site/users/view/shobankr
Occupation:
Software Developer (Senior)
Company:
Allianz Cornhill
Location:
India