一、功能需求
- 播放
MP3
文件:可播放MP3文件 - 播放
OGG
文件:可播放OGG文件 - 用户界面:一个简单的窗口,包含播放和暂停按钮及文件选择功能
- 异常处理:程序能处理可能处理可能出现的异常,如文件不存在、文件读取错误等
- 兼容性:确保代码能在多个c#版本上运行
二、设计思路分析
-
架构选择
考虑到需求中的界面友好和跨版本兼容性,我们可以选择选择
Windows Forms
作为开发平台,Windows Forms
提供了一个简单而强大的方法来创建桌面应用程序,并且与C#高度兼容,在开发过程,我们选择.NETFramework 4.8.0进行程序设计。 -
设计思路
- 界面设计: 使用
Windows Forms
工具箱中的控件如按钮、标签和文件对话框构建用户界面。 - 功能编码: 使用
OpenFileDialog
允许用户选择音频文件。 根据文件扩展名调用相应的播放器对象进行播放。 播放控制,包括开始、暂停和停止。 - 异常处理: 捕获并响应各种可能的运行时错误,如文件读取失败、文件格式不支持等,为用户提供清晰的错误信息。
- 界面设计: 使用
-
难点分析
- 文件格式支持: 处理多种音频格式(
MP3
,OGG
等)要求使用不同的库,这可能导致代码复杂度增加。 - 异常处理: 音频文件的播放中可能遇到多种异常情况,如文件损坏、编解码器不支持等。
- 文件格式支持: 处理多种音频格式(
三、窗体设计
按照需求设计窗体,并进行一定的美化
- Label:展示当前播放的歌曲
- Listbox:展示歌曲列表
- AxWindowsMediaPlayer:播放常规音乐
- Button:选择歌曲文件、停止播放、下一曲
- TraceBarl:用于音量控制
四、代码实现
-
头文件引入
c#using AxWMPLib; using NAudio.Vorbis; using NAudio.Wave; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection.Emit; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement;
-
类成员变量定义
c#List<string> localmusiclist = new List<string> { }; private WaveOutEvent waveOut = new WaveOutEvent(); private VorbisWaveReader currentVorbisReader;
在类中,
localmusiclist
在音乐播放时用来追踪和管理用户加载的音乐文件集合,waveOut
用于播放ogg
文件,currentVorbisReader
为当前播放ogg
文件的状态 -
按钮控件
-
歌曲文件选择
c#private void button1_Click(object sender, EventArgs e) { string[] files = { }; openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav;*.ogg"; //同时打开多个文件 openFileDialog1.Multiselect = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { //清空原有列表 listBox1.Items.Clear(); localmusiclist.Clear(); if (files != null) { Array.Clear(files, 0, files.Length); } files = openFileDialog1.FileNames; string[] array = files; foreach (string file in array) { string extension = Path.GetExtension(file).ToLower(); if (extension == ".mp3" || extension == ".flac" || extension == ".wav" || extension == ".ogg") { listBox1.Items.Add(file); localmusiclist.Add(file); } else { MessageBox.Show($"不支持的文件格式:{file}", "文件错误", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } }
这里我们通过
Filter
方法来限制用户选择的音乐文件,防止后续播放功能报错,并在选择文件之后将选择的音乐列表放置到ListBox
中,同时逻辑判断删除已有的列表,并将歌曲播放列表放入localmusiclist
中,再通过openFileDialog来判断文件是否读取成功。 -
暂停播放按钮
c#private void button2_Click(object sender, EventArgs e) { if (waveOut.PlaybackState == PlaybackState.Playing) { waveOut.Pause(); // 暂停播放OGG } axWindowsMediaPlayer1.Ctlcontrols.stop(); // 停止其他格式的播放 }
用
if
条件判断,如果在播放ogg就停止播放ogg,如果播放的是普通文件就停止普通播放器就行 -
播放下一首按钮
c#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[index]); listBox1.SelectedIndex = index; } }
判断
Count
是否大于0,以此来判断是否能执行下一首播放的逻辑,如果index
大于localmusiclist
的长度,就将index
置0,以此来循环播放列表,在播放时调用musicplay
函数来播放音乐,同时用Label
来显示当前播放音乐的信息。
-
-
音乐选择控件
c#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]); } }
当listBox1中的音乐选择发生改变时,会触发该事件函数,若localmusiclist.Count > 0,就用musicplay播放选择中的音乐,并更新label1的值
-
音乐播放函数
c#private void musicplay(string filename) { string extension = Path.GetExtension(filename).ToLower(); try { if (extension == ".ogg") { if (currentVorbisReader != null) { // 确保先停止当前播放再释放资源 if (waveOut.PlaybackState != PlaybackState.Stopped) { waveOut.Stop(); } currentVorbisReader.Dispose(); } currentVorbisReader = new VorbisWaveReader(filename); waveOut.Init(currentVorbisReader); waveOut.Play(); } else { if (currentVorbisReader != null) { // 确保先停止当前播放再释放资源 if (waveOut.PlaybackState != PlaybackState.Stopped) { waveOut.Stop(); } currentVorbisReader.Dispose(); } axWindowsMediaPlayer1.URL = filename; axWindowsMediaPlayer1.Ctlcontrols.play(); } } catch (Exception ex) { MessageBox.Show($"无法播放文件:{filename}\n\n错误信息:{ex.Message}", "播放错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
首先获取文件后缀名,然后判断后缀名是否为ogg,若为普通文件,则用c#自带的内置播放器即可完成播放,否则则需要下载安装NAudio的第三方库中的Vorbis和Wave类来实现播放音乐,在播放时要检查是否正在播放ogg音乐,若是则停止播放当前音乐再播放其他音乐,同时这里使用try捕获播放错误来防止读取文件产生的错误导致程序卡死。
-
音量控制组件
c#private void trackBar1_Scroll(object sender, EventArgs e) { axWindowsMediaPlayer1.settings.volume = trackBar1.Value; }
这里将axWindowsMediaPlayer1的按钮联动到traceBar1上,实现用traceBar1来控制音量。
五、完整代码
ini
```c#
using AxWMPLib;
using NAudio.Vorbis;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace _4._23上课code
{
public partial class Form1 : Form
{
List<string> localmusiclist = new List<string> { };
private WaveOutEvent waveOut = new WaveOutEvent();
private VorbisWaveReader currentVorbisReader;
public Form1()
{
InitializeComponent();
}
private void musicplay(string filename)
{
string extension = Path.GetExtension(filename).ToLower();
try
{
if (extension == ".ogg")
{
if (currentVorbisReader != null)
{
// 确保先停止当前播放再释放资源
if (waveOut.PlaybackState != PlaybackState.Stopped)
{
waveOut.Stop();
}
currentVorbisReader.Dispose();
}
currentVorbisReader = new VorbisWaveReader(filename);
waveOut.Init(currentVorbisReader);
waveOut.Play();
}
else
{
if (currentVorbisReader != null)
{
// 确保先停止当前播放再释放资源
if (waveOut.PlaybackState != PlaybackState.Stopped)
{
waveOut.Stop();
}
currentVorbisReader.Dispose();
}
axWindowsMediaPlayer1.URL = filename;
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
catch (Exception ex)
{
MessageBox.Show($"无法播放文件:{filename}\n\n错误信息:{ex.Message}", "播放错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void axWindowsMediaPlayer1_Enter(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
string[] files = { };
openFileDialog1.Filter = "选择音频|*.mp3;*.flac;*.wav;*.ogg";
//同时打开多个文件
openFileDialog1.Multiselect = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//清空原有列表
listBox1.Items.Clear();
localmusiclist.Clear();
if (files != null)
{
Array.Clear(files, 0, files.Length);
}
files = openFileDialog1.FileNames;
string[] array = files;
foreach (string file in array)
{
string extension = Path.GetExtension(file).ToLower();
if (extension == ".mp3" || extension == ".flac" || extension == ".wav" || extension == ".ogg")
{
listBox1.Items.Add(file);
localmusiclist.Add(file);
}
else
{
MessageBox.Show($"不支持的文件格式:{file}", "文件错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}
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 trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
}
private void button2_Click(object sender, EventArgs e)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
waveOut.Pause(); // 暂停播放OGG
}
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[index]);
listBox1.SelectedIndex = index;
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
```
六、总结&改进思路
通过本次作业,我得以运用第三方库来辅助我的程序设计,并学习了更复杂的控件使用以及控件之间的协作。这让我对C#的控件使用有了更深入的理解。 尽管当前程序能够播放多种音乐文件格式,但它无法解析最新的音乐文件格式,比如ape和aac文件。 此外,程序还缺少一些高级音频功能的设置,比如音频效果处理(如均衡器、声音增强等),以及支持音频流的直接下载和播放。