目录
一、作业内容
请编写一个C#程序,实现音乐文件的播放功能。
要求1:
1. 程序应能够读取MP3文件,并播放其中的音频。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
要求2:
1. 程序应能够播放ogg文件。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
二、设计思路
1.设计思路
1.1 界面设计
为实现简单的音乐播放器,需要使用Windows Forms
工具箱中的各种控件(如:button、label等)构建出音乐播放器的界面。
1.2 功能设计
(1)打开音乐文件:使用openFileDialog让用户选择需要播放的音乐文件。
(2)显示正在播放的音乐:使用label显示正在播放的音乐。
(3)显示音乐列表:使用listBox显示音乐列表。
(4)操作控制:使用多个button进行控制,包括选择音乐、停止播放等功能。
1.3 异常处理
捕获并响应各种可能的运行时错误,如文件读取失败、文件格式不支持等。
2.难点分析
1.1 文件格式
该音乐播放器需要对多种不同格式的音乐文件(如:MP3文件、ogg文件等)进行处理,不同的文件需要调用不同的库进行处理,这使得代码更加复杂。
1.2 异常处理
该音乐播放器运行过程中可能遇到多种异常,如文件读取失败、文件格式不支持等异常。
三、窗体设计
根据需求设计窗体如下:
说明:窗体的具体属性可以更具个人喜好设计
其中包含的控件及其作用如下:
Label :显示正在播放的歌曲。
ListBox :显示选择的所有歌曲。
WindowsMediaPlayer :播放常规格式音乐(ogg无法播放)。
TrackBar :用于音量控制。
Button :用于控制音乐播放,包括选择歌曲、停止播放、下一曲。
OpenFileDialog :用于获取音乐文件。
四、代码实现
1.准备工作
由于需要对ogg文件进行处理,故需要使用Nuget程序包中的Naudi.Vorbis控件
2.定义变量
//定义变量
string[] files;
List<string> localmusiclist = new List<string> { };
private WaveOutEvent waveOutEvent = new WaveOutEvent();
private VorbisWaveReader vorbisReader;
各个变量的意义:
files 用于存放选择的音乐文件。
localmusiclist
在音乐播放应用中用来追踪和管理用户加载的音乐文件集合。
waveOutEvent
用于播放ogg
文件。
vorbisReader用于记录ogg文件的状态。
3.选择歌曲功能
3.1选择所有音乐文件
使用
openFileDialog
控件来实现文件的选择,Filter
用于筛选文件类型。
利用localmusiclist
变量存储文件名,并且作为类成员变量进行传输,方便后续对音乐的操作。
//选择所有音乐文件
private void button1_Click(object sender, EventArgs e)
{
//支持同时打开多个文件
openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav;*.ogg";
openFileDialog1.Multiselect = true;
//判断openFileDialog是否接收到文件
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//清空歌单
localmusiclist.Clear();
listBox1.Items.Clear();
//清空files
if (files != null)
{
Array.Clear(files, 0, files.Length);
}
//向歌单中添加选中的歌曲
files = openFileDialog1.FileNames;
string[] array = files;
foreach (string file in array)
{
listBox1.Items.Add(file);
localmusiclist.Add(file);
}
}
}
注意:添加歌曲前要清空原有的歌单,并且操作前要确保 openFileDialog接收到文件
3.2选择需要播放的音乐
在ListBox
控件中,利用SelectedIndexChanged 选择歌曲的编码SelectedIndex ,并通过SelectedIndex与localmusiclist 进行选择歌曲的播放。
//选择需要播放的音乐
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//判断歌单中是否有歌曲
if (localmusiclist.Count > 0)
{
//选择歌单中要播放的歌曲进行播放
axWindowsMediaPlayer1.URL = localmusiclist[listBox1.SelectedIndex];
musicplay(axWindowsMediaPlayer1.URL);
//更新正在播放的歌曲
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
}
}
4.歌曲播放及异常处理功能
4.1歌曲播放
由于ogg文件与MP3文件的播放路径不同,故在播放音乐之前需要先判断文件的类型。
使用extension记录文件名的后缀信息,用于判断文件类型。
若是ogg
文件,调用NAudio
第三方库实现播放音乐;
若是其他类型的文件,使用WindowsMediaPlayer
控件实现播放。
4.2异常处理
使用try catch 语句对播放的文件进行异常处理,包括文件不存在异常、文件读取错误异常以及其他异常。
private void musicplay(string filename)
{
//获取当前文件名的后缀信息
string extension = Path.GetExtension(filename);
try
{
//判断当前文件类型
if (extension == ".ogg")
{
if (vorbisReader != null)
{
//确保先停止当前播放再释放资源
if (waveOutEvent.PlaybackState != PlaybackState.Stopped)
{
waveOutEvent.Stop();
}
vorbisReader.Dispose();
}
//播放ogg文件
vorbisReader = new VorbisWaveReader(filename);
waveOutEvent.Init(vorbisReader);
waveOutEvent.Play();
}
else
{
//播放其他类型文件
axWindowsMediaPlayer1.URL = filename;
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
//文件不存在异常
catch (FileNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
//文件读取错误异常
catch (IOException ex)
{
Console.WriteLine("读取文件时发生错误: " + ex.Message);
}
//其他异常
catch (Exception ex)
{
Console.WriteLine("发生未知错误: " + ex.Message);
}
}
注意: 播放音乐前,先检测当前是否有正在进行播放或者是暂停播放的
ogg
音乐,防止同时初始化两次WaveOut
产生播放异常。
5.停止播放功能
停止播放功能也需要对文件类型进行区分:
ogg文件需要使用waveOutEvent.Stop()停止播放;
MP3文件使用axWindowsMediaPlayer1.Ctlcontrols.stop()停止播放。
//停止播放
private void button2_Click(object sender, EventArgs e)
{
if (waveOutEvent.PlaybackState == PlaybackState.Playing)
{
//停止ogg文件播放
waveOutEvent.Stop();
}
else
//停止其他类型文件播放
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
6.下一曲功能
想要播放下一首歌曲需要将ListBox 中正在播放的歌曲的编码更新为下一首歌的编码,若正在播放的为歌单的最后一首歌,需要将正在播放的歌曲的编码更新为第一首歌的编码,同时更新Label中的内容。
//下一曲
private void button3_Click(object sender, EventArgs e)
{
//判断歌单中是否有歌曲
if (localmusiclist.Count > 0)
{
//找到下一曲的编码
int index = listBox1.SelectedIndex + 1;
//若正在播放的为歌单的最后一首歌
//下一曲的编码为歌单第一首歌的编码
if (index >= localmusiclist.Count())
{
index = 0;
}
//播放下一首歌曲
axWindowsMediaPlayer1.URL = localmusiclist[index];
musicplay(axWindowsMediaPlayer1.URL);
//更新正在播放的歌曲
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
listBox1.SelectedIndex = index;
}
}
7.音量控制功能
将 WindowsMediaPlayer
的属性和TrackBar
设置的值进行关联,从而达到音量控制的效果。
//音量控制
private void trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
}
五、运行结果
六、完整代码
using NAudio.Vorbis;
using NAudio.Wave;
using System.Windows.Forms;
namespace musicplayer
{
public partial class Form1 : Form
{
//定义变量
string[] files;
List<string> localmusiclist = new List<string> { };
private WaveOutEvent waveOutEvent = new WaveOutEvent();
private VorbisWaveReader vorbisReader;
public Form1()
{
InitializeComponent();
}
private void musicplay(string filename)
{
//获取当前文件名的后缀信息
string extension = Path.GetExtension(filename);
try
{
//判断当前文件类型
if (extension == ".ogg")
{
if (vorbisReader != null)
{
//确保先停止当前播放再释放资源
if (waveOutEvent.PlaybackState != PlaybackState.Stopped)
{
waveOutEvent.Stop();
}
vorbisReader.Dispose();
}
//播放ogg文件
vorbisReader = new VorbisWaveReader(filename);
waveOutEvent.Init(vorbisReader);
waveOutEvent.Play();
}
else
{
//播放其他类型文件
axWindowsMediaPlayer1.URL = filename;
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
//文件不存在异常
catch (FileNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
//文件读取错误异常
catch (IOException ex)
{
Console.WriteLine("读取文件时发生错误: " + ex.Message);
}
//其他异常
catch (Exception ex)
{
Console.WriteLine("发生未知错误: " + ex.Message);
}
}
//选择所有音乐文件
private void button1_Click(object sender, EventArgs e)
{
//支持同时打开多个文件
openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav;*.ogg";
openFileDialog1.Multiselect = true;
//判断openFileDialog是否接收到文件
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//清空歌单
localmusiclist.Clear();
listBox1.Items.Clear();
//清空files
if (files != null)
{
Array.Clear(files, 0, files.Length);
}
//向歌单中添加选中的歌曲
files = openFileDialog1.FileNames;
string[] array = files;
foreach (string file in array)
{
listBox1.Items.Add(file);
localmusiclist.Add(file);
}
}
}
//选择需要播放的音乐
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//判断歌单中是否有歌曲
if (localmusiclist.Count > 0)
{
//选择歌单中要播放的歌曲进行播放
axWindowsMediaPlayer1.URL = localmusiclist[listBox1.SelectedIndex];
musicplay(axWindowsMediaPlayer1.URL);
//更新正在播放的歌曲
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
}
}
//停止播放
private void button2_Click(object sender, EventArgs e)
{
if (waveOutEvent.PlaybackState == PlaybackState.Playing)
{
//停止ogg文件播放
waveOutEvent.Stop();
}
else
//停止其他类型文件播放
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
//下一曲
private void button3_Click(object sender, EventArgs e)
{
//判断歌单中是否有歌曲
if (localmusiclist.Count > 0)
{
//找到下一曲的编码
int index = listBox1.SelectedIndex + 1;
//若正在播放的为歌单的最后一首歌
//下一曲的编码为歌单第一首歌的编码
if (index >= localmusiclist.Count())
{
index = 0;
}
//播放下一首歌曲
axWindowsMediaPlayer1.URL = localmusiclist[index];
musicplay(axWindowsMediaPlayer1.URL);
//更新正在播放的歌曲
label1.Text = Path.GetFileNameWithoutExtension(localmusiclist[listBox1.SelectedIndex]);
listBox1.SelectedIndex = index;
}
}
//音量控制
private void trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
}
}
}
七、总结
通过本次作业,我懂得运用第三方库来辅助程序设计,从而降低代码难度,学会了复杂的控件使用以及控件之间的协作。
当前程序能实现较多的音乐文件格式播放,但是不能够实现所有的音乐文件解析,如ape和aac文件无法被当前程序处理。并且无法实现真正的控制音量的输出大小以及停止播放后继续播放该文件。