前言
在日常生活中,音乐是我们不可或缺的一部分。作为程序员,我们可以利用自己的编程技能来开发一个简单的音乐播放器。这不仅可以满足我们日常的娱乐需求,同时也可以提高我们的编程水平。在这篇博客中,我将带大家一起探索如何使用 C# 来开发一个基本的音乐播放器。
一、摘要
音乐播放器是一个很常见的应用程序,本文将详细介绍如何使用 C# 和 Windows Forms 开发一个音乐播放器应用程序,支持本地音乐文件的播放、音量调节、播放控制、在线音乐播放及下载等功能。该项目中我使用 了NAudio 库来处理音频文件,HttpClient 来获取在线音乐。
二、项目概述
这个音乐播放器包含以下主要功能:
1.支持播放本地音乐文件(包括 MP3、FLAC、WAV 等格式)。
2.支持在线音乐播放,可以通过网易云音乐 API 获取音乐链接并播放。
3.支持音乐下载功能,可以下载网易云音乐的音乐文件到本地。
4.提供基本的音量控制功能。
5.支持切换音乐和停止播放。
接下来让我们一步步来实现这个音乐播放器。
三、项目结构
我将项目分为以下几个部分:
1、用户界面设计
在该项目中,我定义了一个 Form1 类,这个类作为应用程序的主窗体。在这个类的构造函数 public Form1() 中,我调用了 InitializeComponent() 方法,这个方法会自动生成窗体的各种控件,如按钮、列表框等。
在窗体上我添加了如下控件:
openFileDialog1: 用于选择本地音乐文件
listBox1: 用于显示选择的本地音乐文件列表
axWindowsMediaPlayer1: 用于播放音乐
trackBar1: 用于控制音量
button1: 用于选择本地音乐文件
button2: 用于停止播放
button3: 用于播放下一首音乐
button4: 用于播放 OGG 格式的音乐
textBoxDownloadURL: 用于输入要下载的歌曲 ID
buttonDownload: 用于下载网络音乐
textBoxOnlineURL: 用于输入要播放的网络音乐 ID
buttonPlayOnline: 用于播放网络音乐
这些控件的具体作用和实现将在后面的章节中介绍。
2、本地音乐播放功能
在 button1_Click 方法中,我实现了本地音乐文件的选择和加载。当用户点击 button1 时,会弹出一个 openFileDialog1 对话框,用户可以选择多个音乐文件。选择完文件后,会将选择的文件路径添加到 localmusiclist 列表中,并将文件名显示在 listBox1 中。当用户在 listBox1 中选择一个文件时,会触发 listBox1_SelectedIndexChanged 方法。在这个方法中,我获取了选中文件的路径,并调用 musicplay 方法来播放音乐。musicplay 方法首先设置 axWindowsMediaPlayer1 的 URL 属性为选中文件的路径,然后检查文件的扩展名是否为 .ogg。如果是 OGG 格式,我们会在控制台输出提示信息,否则直接调用 axWindowsMediaPlayer1.Ctlcontrols.play() 方法播放音乐。
此外,我还实现了音量控制功能。当用户拖动 trackBar1 时,会触发 trackBar1_Scroll 方法,在这个方法中我将 axWindowsMediaPlayer1 的音量设置为 trackBar1 的值。我还实现了停止播放的功能。当用户点击 button2 时,会触发 button2_Click 方法,在这个方法中我调用 axWindowsMediaPlayer1.Ctlcontrols.stop() 方法来停止播放。
最后,当用户点击 button3 时,会触发 button3_Click 方法,在这个方法中我实现了播放下一首音乐的功能。获取 localmusiclist 列表中下一个文件的路径,设置 axWindowsMediaPlayer1 的 URL 属性,并调用 musicplay 方法来播放音乐。同时,还更新了 listBox1 中选中的项目。
3、在线音乐播放功能
在 buttonPlayOnline_Click 事件处理器中,我实现了从网易云音乐播放在线音乐的功能。
首先,我定义了一个名为 GetMusicUrlFromNetease 的异步方法,该方法使用 HttpClient 向网易云音乐的 API 发送请求,并获取指定歌曲的 URL。然后,我在 PlayOnlineMusic 方法中使用这个 URL 来播放音乐。使用 MediaFoundationReader 类读取音乐数据,并通过 WaveOutEvent 类播放音乐。为了避免内存泄漏,我在播放完成后删除了临时文件。
4、在线音乐下载功能
在 buttonDownload_Click 事件处理器中,我实现了从网易云音乐下载音乐的功能。
首先,我使用 GetValidFileName 方法生成一个合法的文件名。然后,需要确保下载目录 (C:\Music) 存在,并使用 DownloadMusicFile 异步方法下载音乐文件。在 DownloadMusicFile 方法中,我再次使用 GetMusicUrlFromNetease 方法获取音乐的 URL,并使用 HttpClient 下载音乐文件。最后将文件保存到指定的路径。
通过这个应用程序,用户可以轻松地播放本地音乐文件,也可以从网易云音乐下载和播放在线音乐。该应用程序使用了多种 .NET 库和 API,展示了如何利用 C# 和 .NET Framework 开发一个功能丰富的音乐播放器应用程序。
三、环境配置
1.安装Visual Studio
(确保版本支持Windows Forms应用程序)。
2.创建一个新的Windows Forms应用程序项目。
3.通过NuGet包管理器安装NAudio库
(用于OGG文件播放)。
四、具体的功能设计和实现
1、引入必要的命名空间
首先,我们需要引入一些必要的命名空间:
using System.Net.Http;
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 Un4seen.Bass;
using System.Xml.Linq;
using Newtonsoft.Json.Linq;
2、初始化组件
在 Form1
类的构造函数中初始化组件:
namespace WindowsMusic2
{
public partial class Form1 : Form
{
string[] files;
List<string> localmusiclist = new List<string> { };
public Form1()
{
InitializeComponent();
}
}
}
3、播放音乐文件
我们创建一个 musicplay
方法,用于播放指定的音乐文件:
private void musicplay(string filename)
{
axWindowsMediaPlayer1.URL = filename;
string extension = Path.GetExtension(filename);
if (extension == ".ogg")
{
Console.WriteLine("这是ogg文件。");
}
else
{
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
4、选择并加载本地音乐文件
通过按钮 button1
的点击事件,用户可以选择并加载多个本地音乐文件:
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;
foreach (string x in files)
{
listBox1.Items.Add(x);
localmusiclist.Add(x);
}
}
}
5、选择播放列表中的音乐
通过列表框 listBox1
的选择事件,用户可以选择播放列表中的音乐进行播放:
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]);
}
}
6、音量调节
通过滑动条 trackBar1
的滚动事件,用户可以调节音量:
private void trackBar1_Scroll(object sender, EventArgs e)
{
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
}
7、停止播放
通过按钮 button2
的点击事件,用户可以停止播放当前音乐:
private void button2_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
8、播放下一首音乐
通过按钮 button3
的点击事件,用户可以播放下一首音乐:
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;
}
}
9、播放 OGG 文件
通过按钮 button4
的点击事件,用户可以选择并播放 OGG 文件:
private void button4_Click(object sender, EventArgs e)
{
string oggFilePath = "";
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "播放音频|*.ogg";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
oggFilePath = openFileDialog.FileName;
}
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);
}
}
}
}
10、获取网易云音乐的 URL
通过 HttpClient
获取网易云音乐的 URL:
private async Task<string> GetMusicUrlFromNetease(string songId)
{
string apiEndpoint = $"https://music.163.com/api/song/enhance/player/url?ids=[{songId}]&br=320000";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Referer", "https://music.163.com");
var response = await httpClient.GetAsync(apiEndpoint);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var json = JObject.Parse(content);
return json["data"][0]["url"].ToString();
}
}
11、播放在线音乐
通过按钮的点击事件,用户可以播放在线音乐:
private async void PlayOnlineMusic(string songId)
{
try
{
string url = await GetMusicUrlFromNetease(songId);
if (!string.IsNullOrEmpty(url))
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
var tempFilePath = Path.GetTempFileName();
using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
{
await stream.CopyToAsync(fileStream);
}
using (var mediaFoundationReader = new MediaFoundationReader(tempFilePath))
{
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(mediaFoundationReader);
outputDevice.Play();
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
await Task.Delay(1000);
}
}
}
File.Delete(tempFilePath);
}
}
}
else
{
MessageBox.Show("无法获取音乐 URL。");
}
}
catch (Exception ex)
{
MessageBox.Show("播放在线音乐时出错:" + ex.Message);
}
}
12、下载在线音乐文件
通过按钮的点击事件,用户可以下载在线音乐文件:
private async void buttonDownload_Click(object sender, EventArgs e)
{
string songId = textBoxDownloadURL.Text;
string saveFileName = GetValidFileName(songId) + ".mp3";
string savePath = Path.Combine(@"C:\Music\", saveFileName);
await DownloadMusicFile(songId, savePath);
}
辅助方法:获取合法文件名
private string GetValidFileName(string fileName)
{
foreach (char c in Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
return fileName;
}
private async Task DownloadMusicFile(string songId, string savePath)
{
try
{
string url = await GetMusicUrlFromNetease(songId);
if (!string.IsNullOrEmpty(url))
{
string directory = Path.GetDirectoryName(savePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
using (var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
await response.Content.CopyToAsync(fs);
}
MessageBox.Show("下载完成!");
}
}
else
{
MessageBox.Show("无法获取音乐 URL。");
}
}
catch (Exception ex)
{
MessageBox.Show("下载音乐文件时出错:" + ex.Message);
}
}
13、界面设计
通过设计器添加以下控件:
- 一个
OpenFileDialog
控件,用于选择本地音乐文件。 - 一个
ListBox
控件,用于显示播放列表。 - 一个
TrackBar
控件,用于调节音量。 - 若干按钮(Button)控件,用于播放、暂停、停止、下一曲等操作。
- 一个
AxWindowsMediaPlayer
控件,用于播放音乐。 - 两个文本框(TextBox)控件,用于输入在线音乐的歌曲 ID 和下载路径。
- 若干标签(Label)控件,用于显示歌曲信息。
五、源代码和运行结果
using System.Net.Http;
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 Un4seen.Bass;
using System.Xml.Linq;
using Newtonsoft.Json.Linq;
namespace WindowsMusic2
{
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];
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)
{
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 button4_Click(object sender, EventArgs e)
{
string oggFilePath="";
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "播放音频|*.ogg";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
oggFilePath = openFileDialog.FileName;
}
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);
}
}
}
}
private async Task<string> GetMusicUrlFromNetease(string songId)
{
string apiEndpoint = $"https://music.163.com/api/song/enhance/player/url?ids=[{songId}]&br=320000";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Referer", "https://music.163.com");
var response = await httpClient.GetAsync(apiEndpoint);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var json = JObject.Parse(content);
return json["data"][0]["url"].ToString();
}
}
private async void PlayOnlineMusic(string songId)
{
try
{
string url = await GetMusicUrlFromNetease(songId);
if (!string.IsNullOrEmpty(url))
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
var tempFilePath = Path.GetTempFileName();
using (var fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
{
await stream.CopyToAsync(fileStream);
}
using (var mediaFoundationReader = new MediaFoundationReader(tempFilePath))
{
using (var outputDevice = new WaveOutEvent())
{
outputDevice.Init(mediaFoundationReader);
outputDevice.Play();
// 等待播放完成
while (outputDevice.PlaybackState == PlaybackState.Playing)
{
await Task.Delay(1000);
}
}
}
File.Delete(tempFilePath); // 删除临时文件
}
}
}
else
{
MessageBox.Show("无法获取音乐 URL。");
}
}
catch (Exception ex)
{
MessageBox.Show("播放在线音乐时出错:" + ex.Message);
}
}
private string GetValidFileName(string fileName)
{
foreach (char c in Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
return fileName;
}
private async Task DownloadMusicFile(string songId, string savePath)
{
try
{
string url = await GetMusicUrlFromNetease(songId);
if (!string.IsNullOrEmpty(url))
{
// 确保目录存在
string directory = Path.GetDirectoryName(savePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
using (var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
await response.Content.CopyToAsync(fs);
}
MessageBox.Show("下载完成!");
}
}
else
{
MessageBox.Show("无法获取音乐 URL。");
}
}
catch (Exception ex)
{
MessageBox.Show("下载音乐文件时出错:" + ex.Message);
}
}
private async void buttonDownload_Click(object sender, EventArgs e)
{
string songId = textBoxDownloadURL.Text; // 使用文本框来输入歌曲ID
string saveFileName = GetValidFileName(songId) + ".mp3"; // 获取合法的文件名
string savePath = Path.Combine(@"C:\Music\", saveFileName); // 下载保存路径
await DownloadMusicFile(songId, savePath);
}
private void buttonPlayOnline_Click(object sender, EventArgs e)
{
string songId = textBoxOnlineURL.Text; // 使用文本框来输入歌曲ID
PlayOnlineMusic(songId);
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private void buttonDownload_Click_1(object sender, EventArgs e)
{
}
private void buttonPlayOnline_Click_1(object sender, EventArgs e)
{
}
private void textBoxDownloadURL_TextChanged(object sender, EventArgs e)
{
}
private void label6_Click(object sender, EventArgs e)
{
}
}
}
播放本地音乐:
在线播放音乐:
下载音乐到本地:
六、结论
本项目实现了本地音乐播放功能,用户可以选择多个音频文件并进行播放,控制音量大小。支持 OGG 文件的播放,扩展了系统的音频格式兼容性。实现了从网易云音乐 API 获取在线音乐的播放和下载功能。整体上满足了用户的基本音乐管理和播放需求,并通过使用 NAudio 库和网易云音乐 API 提高了系统的可扩展性。未来可以继续优化界面交互、增加更多音频格式支持等功能,提升用户体验。
本文所涉及的代码可以在gitee上找到。
总结
通过上述步骤,我们实现了一个简单的音乐播放器,支持本地音乐文件的播放、音量调节、播放控制、在线音乐播放及下载等功能。该程序可以作为音乐播放器开发的基础,通过进一步扩展,可以实现更多的功能。希望这篇文章对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。