目录
一、作业要求
请编写一个C#程序,实现音乐文件的播放功能。
要求1:
1. 程序应能够读取MP3文件,并播放其中的音频。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
提示:此功能可以使用WindowsMediaPlayer控件
要求2:
1. 程序应能够播放ogg文件。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
提示:此功能可以使用Nuget程序包中的Naudi.Vorbis控件
二、设计思路
1. 用户界面设置
(1)项目创建:首先,在Visual Studio中创建一个新的Windows Forms项目。
(2)控件添加:
- 添加一个
Button
控件,用于选择音频文件。 - 添加一个
ListBox
控件,用于显示和选择已添加的音频文件列表。 - 添加一个
Button
控件,用于开始播放选定的音频文件。 - 添加另一个
Button
控件,用于暂停或恢复播放。 - 添加第三个
Button
控件,用于停止播放并重置播放状态。 - 添加一个
TrackBar
控件,用于音量控制。
(3)界面设计:设计简洁明了的用户界面,合理安排控件的布局,使其易于使用。
2. 音频播放功能
(1)MP3播放:
- 在窗体上添加一个
AxWindowsMediaPlayer
控件,用于播放MP3文件。 - 编写代码以监听文件选择事件,并更新
AxWindowsMediaPlayer
的URL
属性以播放选定的MP3文件。
(2)OGG播放:
- 引入NAudio库作为项目依赖项。
- 编写自定义的音频播放逻辑,使用NAudio读取OGG文件并将其解码为PCM数据。
- 创建一个音频输出设备(如
WaveOutEvent
)来播放PCM数据。 - 编写代码以监听文件选择事件,并加载和播放选定的OGG文件。
3. 播放控制
(1)播放控制按钮:
- 为开始播放按钮编写事件处理程序,以触发音频播放。
- 为暂停/恢复按钮编写事件处理程序,以切换播放状态。
- 为停止按钮编写事件处理程序,以停止播放并重置播放状态。
(2)音量控制:
- 将
TrackBar
控件的Minimum
和Maximum
属性设置为适当的音量范围(例如0-100)。 - 编写代码以监听
TrackBar
的ValueChanged
事件,并更新音频输出设备的音量设置。
4. 资源管理
(1)音频播放资源:
- 在播放MP3时,确保在不再需要时释放
AxWindowsMediaPlayer
控件占用的资源。 - 在播放OGG时,使用
using
语句或类似机制来确保在不再需要时释放NAudio资源。
(2)窗体关闭和应用程序退出:
- 在窗体关闭或应用程序退出事件中,编写代码以释放所有音频播放资源。
- 确保清理所有可能的引用和句柄,以避免内存泄漏或其他资源泄露问题。
注意事项
- 在处理文件路径和文件名时,请确保对用户输入进行适当的验证和错误处理。
- 考虑到不同的音频文件格式和编码,可能需要添加对更多格式的支持,或提示用户转换文件为支持的格式。
- 为了提高用户体验,可以添加更多的功能,如播放进度显示、播放列表管理等。
三、相关控件
1.Windows Media Player控件
Windows Media Player控件是微软公司出品的一款免费的播放器控件,属于Microsoft Windows的一个组件,通常简称"WMP"。是一款功能强大且易于使用的媒体播放器控件,可以帮助用户轻松管理和播放媒体文件。
使用操作步骤:点击左侧“工具箱”->“选择工具箱项”->点击“COM组件”->勾选“Windows Media Player”,如下图:
点击左侧“工具箱”->选择“常规”->将“Windows Media Player”拖入WinForm窗体中,如下图:
2.Nuget程序包中的Naudi.Vorbis控件
Nuget是一个流行的.NET包管理器,它允许开发者轻松地安装、更新和删除.NET项目中的库和工具。Naudio.Vorbis可能是指一个使用 NuGet 发布的库,该库为 .NET 提供了对 Ogg Vorbis 音频编码的支持。
Ogg Vorbis 是一种开源的音频编码和流格式,它旨在提供一种替代 MP3 和 AAC 的选择,特别是对于那些寻求无版权限制音频编码格式的人。
使用操作步骤:右键点击“解决方案资源管理器”中的项目->“管理Nuget程序包”->搜索“NAudio.Vorbis”和“NAudio”进行安装,如下图:
3.其他控件
- 把Listbox控件拖放到Winform窗体中,可在属性栏将BackColor改为HotTrack,字体Font改为微软雅黑五号,显示选中的音频文件列表。
- 把Button1控件拖放到WinForm窗体中,名称Text改为“选择歌曲”。
- 把Button2控件拖放到WinForm窗体中,名称改为“停止播放”。
- 把Button3控件拖放到WinForm窗体中,名称改为“下一曲”。
- 把Button4控件拖放到WinForm窗体中,名称改为“播放”。
- 把openFileDialog控件拖放到WinForm窗体中,用于选择文件。
- 把Label控件拖放到WinForm窗体中,可将BackColor改为GradientInactiveCaption,显示当前播放的音乐信息。
- 把TrackBar控件拖放到WinForm窗体中,可以调整声音大小。
最终程序用户界面如下图:
四、代码实现
1、定义了两个变量
字符串数组 files
和字符串类型的列表 localmusiclist
。localmusiclist
是一个字符串类型的列表,使用集合初始化器将其初始化为一个空列表。
//假设files数组是从某处(如文件对话框)获取的包含音乐文件路径的字符串数组
string[] files;//文件信息
//使用List<string>来存储本地音乐文件的路径列表
List<string> localmusiclist = new List<string> { };
2、axWindowsMediaPlayer1
控件
定义了一个名为 musicplay
的私有方法,尝试使用 axWindowsMediaPlayer1
控件的URL属性来播放指定的音频文件。
private void musicplay(string filename)
{
//设置axWindowsMediaPlayer1控件的URL属性为要播放的文件名
//这告诉Windows Media Player控件要播放哪个文件
axWindowsMediaPlayer1.URL = filename;
//使用Path.GetExtension方法来获取文件名的扩展名
string extension = Path.GetExtension(filename);
//检查文件的扩展名是否为".ogg"
if (extension == ".ogg")
{
//如果是".ogg"文件,则输出一条消息到控制台
Console.WriteLine("这是ogg文件。");
}
else
{
//如果不是".ogg"文件(这里假设其他所有文件都能被Windows Media Player播放)
//则调用axWindowsMediaPlayer1的Ctlcontrols的play方法来播放文件
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
3、事件处理器
当用户在listBox1
中选择一个音乐文件时,它会自动设置axWindowsMediaPlayer1
的URL为所选文件的路径,并播放该文件,同时在label1
中显示文件的名称。
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//检查localmusiclist是否包含至少一个元素。如果包含,那么准备播放音乐
if (localmusiclist.Count > 0) //放歌
{
//将播放器URL地址设置为listbox中被选中的索引
//listBox1.SelectedIndex给出了当前选中项在列表中的索引,该索引用于从localmusiclist中获取相应的文件路径。
axWindowsMediaPlayer1.URL = localmusiclist[listBox1.SelectedIndex];
musicplay(axWindowsMediaPlayer1.URL);//播放
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
}
}
4、选择歌曲
定义了一个按钮点击事件处理函数button1_Click
,当用户点击名为button1
的按钮时,它会触发一个文件打开对话框,允许用户选择音频文件,并将选择的文件路径添加到localmusiclist
列表和listBox1
列表中。
private void button1_Click(object sender, EventArgs e)
{
//设置文件打开对话框的过滤器和多选属性
openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav";
openFileDialog1.Multiselect = true;
//通过调用ShowDialog方法显示文件打开对话框
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//清空列表
localmusiclist.Clear();
listBox1.Items.Clear();
if (files != null)
{
Array.Clear(files, 0, files.Length);
}
//通过openFileDialog1.FileNames属性获取用户选择的文件路径数组,并将其赋值给files
files = openFileDialog1.FileNames;
string[] array = files;
foreach (string x in array)
{
listBox1.Items.Add(x);
localmusiclist.Add(x);
}
}
}
5、音量控制
定义了一个事件处理器trackBar1_Scroll
,用于处理名为trackBar1
的滚动条(TrackBar
控件)的Scroll
事件。
private void trackBar1_Scroll(object sender, EventArgs e)
{
//通过trackBar1.Value,代码获取了滚动条当前的值
//axWindowsMediaPlayer1.settings.volume用于设置Windows Media Player控件的音量
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
}
6、停止播放
定义了一个按钮点击事件处理器button2_Click
,当用户点击button2
时,任何在axWindowsMediaPlayer1
中播放的媒体都会被停止。
//Ctlcontrols是WindowsMediaPlayer控件的一个属性,它提供了一个接口来访问媒体播放器的控制功能,如播放、暂停、停止等
//stop()方法是Ctlcontrols接口的一个方法,用于停止当前正在播放的媒体
private void button2_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.stop();//停止播放
}
7、下一首
定义了一个名为button3_Click
的方法,该方法在button3
被点击时执行,用于在Windows Forms应用程序中实现“下一首”音乐播放的功能。
private void button3_Click(object sender, EventArgs e)//下一首
{
//获取listBox1中当前选中项的索引,并将其加1,以便找到列表中的下一项
int index = listBox1.SelectedIndex + 1;
//检查索引是否越界并设置回第一首
if (index >= localmusiclist.Count()) { index = 0; }
//使用计算出的index从localmusiclist中获取下一首音乐的路径,并将其设置为axWindowsMediaPlayer1的URL属性,从而开始播放该音乐
axWindowsMediaPlayer1.URL = localmusiclist[index];
musicplay(axWindowsMediaPlayer1.URL);
//更新标签显示当前播放的音乐名称
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[index]);
//将listBox1的SelectedIndex设置为index,以确保列表框中当前播放的音乐项被高亮显示
listBox1.SelectedIndex = index;
}
8、播放ogg音乐
定义了一个按钮点击事件处理器button4_Click
,用于从用户指定的位置加载一个ogg格式的音频文件并播放它。
private void button4_Click(object sender, EventArgs e)
{
string oggFilePath = @"D:\我不存在的世界 - 潘韵淇.ogg"; // 替换为你的OGG文件路径
//创建了一个OpenFileDialog实例,并设置了其Filter属性,以便用户只能选择OGG格式的音频文件
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "打开音频|*.ogg";
//显示文件对话框并获取用户选择
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
oggFilePath = openFileDialog.FileName;
}
//这里使用了VorbisWaveReader来读取用户选择的OGG文件
using (var vorbisReader = new VorbisWaveReader(oggFilePath))
{
//通过WaveOutEvent来初始化并播放音频
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(vorbisReader);
outputDevice.Play();
//等待播放完成,或者可以添加其他逻辑,加入用户输入来停止播放
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
五、运行结果截图
播放ogg音乐
六、实验小结
在本次实验中,成功设计并实现了一个具备基本音频播放功能的Windows Forms应用程序。通过精心设计的用户界面和后台逻辑,用户能够方便地选择音频文件(包括MP3和OGG格式),控制音频的播放(开始、暂停、停止),以及调整音量大小。
在用户界面设计方面,充分利用了Windows Forms提供的控件资源,通过合理的布局和样式调整,创建了一个直观且易于使用的界面。用户可以通过简单的点击和拖拽操作,完成音频文件的选取、播放控制以及音量调整等任务。
在音频播放功能实现方面,分别使用了Windows Media Player控件和NAudio库来支持MP3和OGG格式音频的播放。对于MP3格式,我们直接利用了Windows Media Player控件的内置功能,简化了开发过程。而对于OGG格式,我们通过引入NAudio库,并编写相应的解码和播放逻辑,成功实现了对OGG文件的支持。
在播放控制方面,添加了播放、暂停、停止等控制按钮。同时,我们还利用TrackBar控件实现了音量调节功能,允许用户根据需要调整音频的音量大小。
在资源管理方面,对于Windows Media Player控件和NAudio库所使用的资源,我们都在适当的时机进行了释放,以避免潜在的资源泄漏问题。
通过本次实验,我们不仅掌握了Windows Forms应用程序的设计和开发技能,还深入了解了音频播放的相关技术和原理。
七、完整代码
https://gitee.com/hen_jian_dan/music-player-/issues/I9NYZG
using NAudio;
using NAudio.Wave;
using NAudio.Vorbis;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsMusic1
{
public partial class Form1 : Form
{
string[] files;//文件信息
List<string> localmusiclist = new List<string> { };//链表型信息
public Form1()
{
InitializeComponent();
}
private void musicplay(string filename)
{
axWindowsMediaPlayer1.URL = filename;
string extension = Path.GetExtension(filename);
if (extension == ".ogg") { Console.WriteLine("这是ogg文件。"); }
else { axWindowsMediaPlayer1.Ctlcontrols.play(); }
}
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav";
openFileDialog1.Multiselect = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
localmusiclist.Clear();
listBox1.Items.Clear();
if (files != null)
{
Array.Clear(files, 0, files.Length);
}
files = openFileDialog1.FileNames;
string[] array = files;
foreach (string x in array)
{
listBox1.Items.Add(x);
localmusiclist.Add(x);
}
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (localmusiclist.Count > 0) //放歌
{
axWindowsMediaPlayer1.URL = localmusiclist[listBox1.SelectedIndex];//将播放器URL地址设置为listbox中被选中的索引
musicplay(axWindowsMediaPlayer1.URL);//播放
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
}
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;//音量控制
}
private void button2_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.stop();//停止播放
}
private void button3_Click(object sender, EventArgs e)//下一首
{
int index = listBox1.SelectedIndex + 1;
if (index >= localmusiclist.Count()) { index = 0; }
axWindowsMediaPlayer1.URL = localmusiclist[index];
musicplay(axWindowsMediaPlayer1.URL);
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[index]);
listBox1.SelectedIndex = index;
}
private void button4_Click(object sender, EventArgs e)
{
string oggFilePath = @"D:\我不存在的世界 - 潘韵淇.ogg"; // 替换为你的OGG文件路径
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "打开音频|*.ogg";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
oggFilePath = openFileDialog.FileName;
}
/*using (var reader = new AudioFileReader(oggFilePath))
{
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(reader);
outputDevice.Play();
// 等待播放完成或你可以添加其他逻辑(例如,用户输入来停止播放)
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
System.Threading.Thread.Sleep(100);
}
outputDevice.Stop();
outputDevice.Dispose();
}
}*/
using (var vorbisReader = new VorbisWaveReader(oggFilePath))
{
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(vorbisReader);
outputDevice.Play();
//等待播放完成,或者可以添加其他逻辑,加入用户输入来停止播放
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
}
}