一、要求
(一)要求1:
1. 程序应能够读取MP3文件,并播放其中的音频。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
可以使用WindowsMediaPlayer控件
(二)要求2:
1. 程序应能够播放ogg文件。
2. 程序应能够处理可能出现的异常,如文件不存在、文件读取错误等。
3. 程序应具有良好的用户界面,方便用户进行操作。
4. 程序应具有良好的兼容性,能在不同版本的C#中正常运行。
提示:此功能可以使用Nuget程序包中的Naudi.Vorbis控件
二、实现途径
(一)实现MP3 文件的播放
第一步,创建项目,选择C#语言,在Windows窗体应用的两个版本中选择(.NET Framework),两个不同的项目文件会产生不同的问题,这个在后面会说到。
第二步,从左侧工具箱中点击右键,选择“选择项”
在COM组件中找到Windows Media Player ,选择并点击确定。
正常情况下,会直接在工具箱中成功添加该组件,拖动其到设计窗口即可。
第三步 ,在左侧工具箱的公共控件中找到Button,拖取到设计窗口。在右下角的属性一栏中可修改该Button的文本内容,字体,颜色字号等基本条件。如下图所示:
第四步,添加代码,实现播放MP3后缀文件的音乐播放。
双击Button,进入代码页面,在button1(播放音乐),button2(停止播放)对应加入以下代码。点击运行。我们通过 OpenFileDialog 打开文件对话框来让用户选择要播放的 MP3 文件。选定文件后,我们尝试加载并播放该文件。如果加载或播放过程中出现异常,我们会弹出一个消息框显示错误信息(对应代码中的try 测试用例)。另外,点击 “停止播放音乐” 按钮时,我们调用了 Windows Media Player 控件的 stop 方法来停止播放音乐。
private void button1_Click(object sender, EventArgs e) //选择文件播放音乐
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "MP3 files (*.mp3)|*.mp3|All files (*.*)|*.*";
openFileDialog.Title = "选择要播放的MP3文件";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
axWindowsMediaPlayer2.URL = openFileDialog.FileName;
axWindowsMediaPlayer2.Ctlcontrols.play();
}
catch (Exception ex)
{
MessageBox.Show("发生错误: " + ex.Message, "错误", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
private void button2_Click(object sender, EventArgs e) //停止播放音乐
{
axWindowsMediaPlayer2.Ctlcontrols.stop();
}
以上,你的应用程序就能够加载和播放 MP3 音频文件了,并具备了异常处理的功能。
(二)增加用户界面
(1)增加音乐音量大小控制
以下介绍两种途径:第一,在Windows Media Player 中能够直接实现对音乐音量的大小控制。第二,通过trackBar滑动条工具实现。通过滑动滑动条来调整音量大小。在 trackBar1
的 Scroll
事件处理程序中,我们获取滑动条的值,并将其映射到音量范围(0-100),然后设置 Windows Media Player 控件的音量属性为相应的值。示例代码如下:
private void trackBar2_Scroll(object sender, EventArgs e)
{
int volume = trackBar2.Value;// 获取滑动条的值,并将其映射到音量范围(0-100)
axWindowsMediaPlayer2.settings.volume = volume;// 设置音量
}
(2)实现音乐列表播放
在实现途径(一)中的实现方法是选择MP3音乐文件进行播放,这里会将代码进行修改,以实现音乐列表播放(前提是提前下载好多首MP3音乐文件)
当您添加媒体项到播放列表或尝试播放媒体时,可能会遇到各种问题,比如文件不存在、文件格式不支持、播放器组件出错等。为了处理这些情况,可以使用 try-catch
语句块来捕获并处理异常。
private void button4_Click(object sender, EventArgs e)
{
try
{
WMPLib.IWMPPlaylist playlist = axWindowsMediaPlayer2.playlistCollection.newPlaylist("myPlaylist"); // 创建一个新的播放列表
// 创建媒体项并添加到播放列表
WMPLib.IWMPMedia mediaItem1 = axWindowsMediaPlayer2.newMedia(@"C:\Users\国平\Desktop\编程\3809516739.mp3");
WMPLib.IWMPMedia mediaItem2 = axWindowsMediaPlayer2.newMedia(@"C:\Users\国平\Desktop\编程\3350937945.mp3");
WMPLib.IWMPMedia mediaItem3 = axWindowsMediaPlayer2.newMedia(@"C:\Users\国平\Desktop\编程\3189583354.mp3");
// 添加更多音乐项...
playlist.appendItem(mediaItem1);
playlist.appendItem(mediaItem2);
playlist.appendItem(mediaItem3);
// 添加更多项到播放列表...
axWindowsMediaPlayer2.currentPlaylist = playlist; // 设置播放器的当前播放列表为刚创建的播放列表
// 如果需要立即开始播放,则调用play方法
axWindowsMediaPlayer2.Ctlcontrols.play();
}
catch (Exception ex)
{
// 弹出一个消息框来显示错误信息
MessageBox.Show("播放列表创建或播放过程中发生异常: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
(3)实现上下曲播放
需要先添加两个按钮作为上下曲的载体。我这里仍然使用的是button。
在 Windows Media Player 控件中,通常没有直接的方式来从当前媒体对象获取它在播放列表中的索引。需要使用不同的方法来确定当前媒体的位置。我使用的方法是遍历播放列表,并与当前播放的媒体进行比较,从而找到当前媒体的索引。
GetCurrentMediaIndex
方法通过遍历播放列表,并比较每个项的 sourceURL
属性(通常是音乐文件的路径或URL)与当前播放媒体的 sourceURL
是否相同来确定当前媒体的索引。这样可以确保正确地获取到当前播放歌曲的索引。
private int GetCurrentMediaIndex()
{
IWMPPlaylist playlist = axWindowsMediaPlayer2.currentPlaylist;
IWMPMedia currentMedia = axWindowsMediaPlayer2.currentMedia;
if (playlist != null && currentMedia != null)
{
for (int i = 0; i < playlist.count; i++)
{
if (playlist.get_Item(i).sourceURL == currentMedia.sourceURL)
{
return i; // 返回当前媒体的索引
}
}
}
return -1; // 如果没有找到或者播放列表为空,则返回-1
}
private void button8_Click(object sender, EventArgs e)
{
int currentIndex = GetCurrentMediaIndex();
if (currentIndex == -1)
{
MessageBox.Show("无法确定当前播放歌曲的索引!", "错误");
return;
}
int playlistCount = axWindowsMediaPlayer2.currentPlaylist.count;
if (currentIndex >= playlistCount - 1)
{
MessageBox.Show("已经是最后一首歌曲!", "提示");
}
else
{
axWindowsMediaPlayer2.Ctlcontrols.next();
}
}
private void button7_Click(object sender, EventArgs e)
{
int currentIndex = GetCurrentMediaIndex();
if (currentIndex == -1)
{
MessageBox.Show("无法确定当前播放歌曲的索引!", "错误");
return;
}
if (currentIndex <= 0)
{
MessageBox.Show("已经是第一首歌曲!", "提示");
}
else
{
axWindowsMediaPlayer2.Ctlcontrols.previous();
}
}
(4)实现音乐的播放进度控制
实现此功能,需要两个主要的步骤:获取当前的播放进度,然后通过将这个进度值绑定给一个滑块滑动条来显示这个进度。
首先,可以在播放器对象上调用axWindowsMediaPlayer2.Ctlcontrols.currentPosition
这将返回一个double类型的值,代表当前媒体的播放进度,以秒为单位。然后,你可以将此值绑定给一个控件(例如,一个滑块或进度条)来表示音乐的当前播放位置。
已添加一个滑块来表示播放位置,您可以设置滑块的最大值为媒体的总长度(可以通过 axWindowsMediaPlayer2.currentMedia.duration
获取),最小值为 0。然后,您可以将滑块的值 设置为当前的播放位置。
private void timer1_Tick(object sender, EventArgs e)
{
if (axWindowsMediaPlayer2.currentMedia != null)
{
trackBar3.Maximum = (int)axWindowsMediaPlayer2.currentMedia.duration;//获取当前滑块的长度
trackBar3.Value = (int)axWindowsMediaPlayer2.Ctlcontrols.currentPosition;
}
}
private void trackBar3_Scroll(object sender, EventArgs e)
{
if (axWindowsMediaPlayer2.currentMedia != null)
{
axWindowsMediaPlayer2.Ctlcontrols.currentPosition = trackBar3.Value;
}
}
要点注意:
(1)当有多个相同类型的控件(例如多个按钮)时,确保你在代码中准确引用它们的名称以避免混淆或错误。
①使用按钮的名称来引用它们:确保你在代码中使用正确的按钮名称来添加事件处理程序或执行相应的操作。如果有多个按钮,建议保持命名一致性并在代码中准确引用它们的名称。
② 注意命名规则:在为按钮或其他控件命名时,尽量遵循一致的命名规则和约定,以确保易于识别和管理。
③ 连接正确的事件处理程序:当为按钮或其他控件添加事件处理程序时,确保将正确的事件与正确的处理程序连接。这将有助于确保代码在触发事件时执行预期的操作。
④放置代码的位置:根据功能或逻辑将代码放置在正确位置。例如,控制播放进度的代码应该与播放器控件的相关代码放在一起。
(2)滑块的滑动范围不够大,调节的范围太小的问题。
对于音量,你的音量滑块的值应该是在 0 到 100 之间。在 Windows Media Player 中,音量由 0(静音)到 100(最大音量)的数值表示。设置音量时,你可以将滑块的值直接给到 `Player.settings.volume`:
private void trackBar_volume_ValueChanged(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar_volume.Value;
}
关于进度,你可以尝试设置一个更大的数值作为你的滑块的 Maximum 属性,例如:
trackBar_progress.Maximum = (int)(axWindowsMediaPlayer1.currentMedia.duration * 10);
然后获取和设置当前位置时,需要按同样的转换比例:
// 获取播放进度
double position = axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
trackBar_progress.Value = (int)(position * 10);
// 设置播放进度
axWindowsMediaPlayer1.Ctlcontrols.currentPosition = trackBar_progress.Value / 10.0;
注意,此处* 10和 / 10.0 只是为了扩大滑块的调整范围。
三、要求拔高
(一)使用的Naudi.Vorbis控件
NAudio.Vorbis 控件实现功能:
NAudio.Vorbis 是 NAudio 库中的一个组件,用于处理 Ogg Vorbis 音频文件。它提供了一种在 C# 中读取、播放和处理这种特定类型音频文件的方式。
1. 读取并播放 Ogg Vorbis 音频文件:通过 NAudio.Vorbis 控件,你可以读取和加载并播放已加载的 Ogg Vorbis 音频文件 Ogg Vorbis 格式的音频文件,
2. 处理音频数据:NAudio.Vorbis 控件还提供了处理音频数据的方法,例如获取音频文件的元数据,控制音频的播放速度和音量等操作。
3 支持音频格式转换:可以将 Ogg Vorbis 格式的音频文件转换为其他格式,或者将其他格式的音频文件转换为 Ogg Vorbis 格式。
4. 自定义音频处理:你可以利用 NAudio.Vorbis 控件提供的功能,对音频文件进行自定义处理,例如添加特效、混音、剪辑等操作。
具体安装
第一步,下载Nuget程序包中的Naudi.Vorbis控件。在右侧解决资源方案管理器中右键选择你的项目,找到”管理NuGet程序包“,点击进去
之后在浏览页面搜索找到Naudi.Vorbis控件,安装即可。
(二)实现播放ogg文件
完整代码如下。这段代码主要是用来将一个.ogg格式的音频文件(MyFile.ogg)转换成.wav格式文件(MyFile.wav), Windows Media Player可以直接播放这个.wav文件。
using NAudio.Wave;
using NAudio.Vorbis;
using System;
string oggFileName = "MyFile.ogg";
using (VorbisWaveReader vorbisStream = new VorbisWaveReader(oggFileName))
{
// Create a WaveFormatConversionStream to convert to PCM format.
using (WaveFormatConversionStream conversionStream = new WaveFormatConversionStream(
new WaveFormat(vorbisStream.WaveFormat.SampleRate, 16, vorbisStream.WaveFormat.Channels), vorbisStream))
{
// Use WaveFileWriter to write the stream to a .wav file.
WaveFileWriter.WriteWavFileToStream(File.Create("MyFile.wav"), conversionStream);
}
}
对以上代码进行分析:
1. `string oggFileName = "MyFile.ogg";` :这行代码是定义了一个字符串变量oggFileName存放你想要转换的.ogg文件的路径。
2. `using (VorbisWaveReader vorbisStream = new VorbisWaveReader(oggFileName))` :这行代码是创建一个VorbisWaveReader对象vorbisStream用来读取你想要转换的.ogg文件。‘using’关键字保证了该对象在结束使用后会被正确地释放资源。
3. `using (、、、、、)` :这行代码是创建一个WaveFormatConversionStream对象conversionStream,它的作用是将vorbisStream中的Vorbis音频数据转换成标准的PCM格式音频数据,因为Windows Media Player可能不能直接播放Vorbis格式的音频数据。这个转换过程中需要设定一个目标音频格式WaveFormat,这个WaveFormat的设定参数从vorbisStream中获取,其中音频采样率(SampleRate)保持不变,音频的位深度设置为16位,音频通道数(Channels)也不变。
4. `WaveFileWriter.WriteWavFileToStream(File.Create("MyFile.wav"), conversionStream);` :这行代码是将转换后的音频数据通过WaveFileWriter类的静态方法WriteWavFileToStream写入到一个.wav文件中去。这里使用了File类的Create方法创建了一个名叫"MyFile.wav"的文件用来存放转换后的音频数据。
(三)播放ogg文件的异常处理
该异常处理是在ogg文件播放的代码基础上进行的增加。每个可能抛出异常的代码段添加了try-catch块。
string oggFileName = "MyFile.ogg";
try
{
using (VorbisWaveReader vorbisStream = new VorbisWaveReader(oggFileName))
{
try
{
using (WaveFormatConversionStream conversionStream = new WaveFormatConversionStream(
new WaveFormat(vorbisStream.WaveFormat.SampleRate, 16, vorbisStream.WaveFormat.Channels), vorbisStream))
{
try
{
WaveFileWriter.WriteWavFileToStream(File.Create("MyFile.wav"), conversionStream);
}
catch (Exception ex)
{
Console.WriteLine("Error writing WAV file: " + ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error converting stream: " + ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error reading OGG file: " + ex.Message);
}
如果在读取OGG文件、转换流或写入WAV文件过程中出现任何异常,将会捕获该异常并输出一个错误消息。在catch块中,我使用了Exception类的Message属性来获取有关异常的详细信息。
四、后续
后续我将持续更新页面设计的优化以及文章开头提到的两种窗体应用的差异。