C#作业-作业三:实现在线音乐播放器

目录

前言

一、设计思路

1.1 功能需求分析

1.2 主要技术与工具

1.3 项目结构

二、代码实现

2.1 窗体设计

2.2 具体控件的作用与代码实现

(1)Button控件

(2)ListBox 控件 

(3)TrackBar 控件

 (4)Label 控件

2.3 整体代码

 三、运行结果

总结

归纳与总结

改进建议


前言

 WindowsMusicPlayer 是一个音乐播放器,能够播放 .mp3.wav 和 .ogg 格式的音乐文件。项目使用 C# 和 Windows Forms 构建,结合 Windows Media Player 控件与 NAudio 库处理不同格式的音频文件。并且加入在线音频播放和音乐下载功能,本文将详细介绍如何用C#为一个现有的音乐播放器添加这两个功能,并对实现过程中的关键代码进行分析。


提示:以下是本篇文章正文内容,下面案例可供参考

一、设计思路

1.1 功能需求分析

  • 支持 .mp3 和 .wav 本地文件的播放,使用 Windows Media Player 控件。
  • 支持 .ogg 本地文件的播放,使用 NAudio.Vorbis 控件。
  • 提供播放列表功能,能够选择多个文件进行播放。
  • 提供音量控制和播放控制(停止、下一曲等)。
  • 提供用户友好的界面,显示当前播放曲目。
  • 具备异常处理,能够处理文件不存在、读取错误等问题 。
  • 支持在线音频播放和音乐下载功能。

1.2 主要技术与工具

  • Windows Forms:用于构建用户界面。
  • Windows Media Player 控件:用于播放 .mp3、.flac 和 .wav 文件。
  • NAudio.Vorbis 控件:用于播放 .ogg 文件。
  • Visual Studio2022:用于开发与调试。

1.3 项目结构

  • Form1.cs:主窗体逻辑代码文件。
  • Form1.Designer.cs:主窗体设计文件。
  • Form1.resx:主窗体资源文件。

二、代码实现

2.1 窗体设计

窗体布局方面,Form1 包含以下主要控件:Button(用于播放ogg文件、选择本地歌曲、停止播放、播放下一曲和播放在线歌曲)、ListBox(用于显示音乐播放列表)、TrackBar(音量滑动条)、Label(用于显示当前播放的曲目)以及 Windows Media Player 控件(用于播放 .mp3和 .wav 文件)。整体布局如图所示:

2.2 具体控件的作用与代码实现

(1)Button控件

选择本地歌曲按钮(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;
        string[] array = files;
        foreach (string x in array) 
        {
            listBox1.Items.Add(x);
            localmusiclist.Add(x);
        }


    }
}

停止播放按钮(button2): 用于停止当前播放的音乐文件。其功能是停止 Windows Media Player 控件和 OGG 文件的播放。

 private void button2_Click(object sender, EventArgs e)
 {
     axWindowsMediaPlayer1.Ctlcontrols.stop();
 }

播放下一曲按钮(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;

       
    }


}

 播放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);
            }
        }
    }

}

  播放在线歌曲按钮(button5): 用于播放在线音频文件链接中的歌曲,当用户点击按钮时,会调用DownloadAudioAsync方法异步下载在线音频文件。

 private async void button5_Click(object sender, EventArgs e)
 {
     await PlayOnlineAudio(onlineAudioUrl);
 }

 private const string onlineAudioUrl = "http://tool.liumingye.cn/music/?page=homePage";

(2)ListBox 控件 

音乐播放列表(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]);
     }

 }

(3)TrackBar 控件

  音量滑动条(trackBar1): 用于音量控制,通过滑动条调整音量百分比,设置音乐播放器的音量。

private void trackBar1_Scroll(object sender, EventArgs e)
{
    axWindowsMediaPlayer1.settings.volume=trackBar1.Value;
}

 (4)Label 控件

当前曲目标签(label1): 用于显示当前播放的音乐曲目名称。

2.3 整体代码

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.Net.Http;

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);
                    }
                }
            }

            /*
            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);
                    }
                }
            }*/
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void axWindowsMediaPlayer1_Enter(object sender, EventArgs e)
        {

        }


        private async void DownloadAndPlayButton_Click(object sender, EventArgs e)
        {
            string url = textBox1.Text; 
            if (string.IsNullOrEmpty(url))
            {
                MessageBox.Show("请输入有效的URL!");
                return;
            }

            try
            {
                using (var httpClient = new HttpClient())
                {
                    var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
                    if (response.IsSuccessStatusCode)
                    {
                          
                        var audioFileStream = await response.Content.ReadAsStreamAsync();
  
                        PlayAudioFromStream(audioFileStream);
                    }
                    else
                    {
                        MessageBox.Show("无法下载音频文件:" + response.StatusCode);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发生错误:" + ex.Message);
            }
        }
        private void PlayAudioFromStream(Stream audioStream)
        {
            // 尝试检测音频格式。在这个例子中,我们假设它是WAV或PCM。   
            IWaveProvider waveProvider = null;

            // 如果流是WAV格式,我们可以直接使用WaveFileReader  
            if (Path.GetExtension(GetContentTypeFromStream(audioStream)).Equals(".wav", StringComparison.OrdinalIgnoreCase))
            {
                waveProvider = new WaveFileReader(audioStream);
            }
            // 如果知道PCM参数(如采样率、通道数、位深度),可以直接使用BufferedWaveProvider  
            
            else
            {
                throw new NotSupportedException("不支持的音频格式。");
            }

            using (var outputDevice = new WaveOutEvent())
            {
                outputDevice.Init(waveProvider);
                outputDevice.Play();

                outputDevice.PlaybackStopped += (sender, e) => { /* 处理播放停止事件 */ };

            }

            // PS:由于outputDevice在using块中,如果尚未释放的话,当播放完成时它会自动被释放  
            // 因此,不需要在这里调用Dispose或其他清理逻辑  
        }


        private string GetContentTypeFromStream(Stream stream)
        { 
            throw new NotSupportedException("不能直接从流中获取内容类型。");
        }

        private async void button5_Click(object sender, EventArgs e)
        {
            await PlayOnlineAudio(onlineAudioUrl);
        }

        private const string onlineAudioUrl = "http://tool.liumingye.cn/music/?page=homePage";

        private async Task PlayOnlineAudio(string audioUrl)
        {
            try
            {
                // 使用AudioFileReader从URL读取音频
                using (var reader = new NAudio.Wave.AudioFileReader(audioUrl))
                {
                    // 创建音频输出设备
                    using (var outputDevice = new NAudio.Wave.WaveOutEvent())
                    {
                        // 初始化输出设备
                        outputDevice.Init(reader);

                        // 播放音频
                        outputDevice.Play();

                        // 等待播放完成,这里使用异步等待,以免阻塞UI线程
                        while (outputDevice.PlaybackState == NAudio.Wave.PlaybackState.Playing)
                        {
                            // 这里使用Invoke确保UI线程更新
                            if (this.InvokeRequired)
                            {
                                this.Invoke(new Action(() =>
                                {
                                    // 这里可以添加更新UI的代码,例如缓冲进度条
                                }));
                            }

                            // 短暂等待后再次检查播放状态
                            await Task.Delay(100);
                        }

                        // 播放完成后,可以在这里添加清理逻辑
                    }
                }
            }
            catch (Exception ex)
            {
                // 处理异常,例如网络问题或格式不支持等
                MessageBox.Show("播放失败: " + ex.Message);
            }

        }

        private async Task DownloadAudioAsync(string url)
            {
                using (var httpClient = new HttpClient())
                {
                    try
                    {
                        // 发起 GET 请求并获取响应
                        using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
                        {
                            response.EnsureSuccessStatusCode(); // 确保响应成功
                            using (var stream = await response.Content.ReadAsStreamAsync())
                            {
                                // 获取文件名,如果服务器没有提供文件名,可以自行指定
                                var fileName = GetFileName(response);

                                // 指定保存文件的路径,这里保存在当前用户的下载目录下
                                var filePath = Path.Combine(@"D:\Desktop", fileName);

                                // 使用 FileStream 写入文件
                                using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                                {
                                    await stream.CopyToAsync(fileStream);
                                }

                                MessageBox.Show("下载完成:" + filePath, "下载成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"下载失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }

            private string GetFileName(HttpResponseMessage response)
            {
                // 从响应头或 URL 中获取文件名
                string fileName = null;
                if (!string.IsNullOrEmpty(response.Content.Headers.ContentDisposition?.FileName))
                {
                    fileName = response.Content.Headers.ContentDisposition.FileName;
                }
                else
                {
                    Uri.TryCreate(response.RequestMessage.RequestUri.ToString(), UriKind.Absolute, out Uri uri);
                    fileName = Path.GetFileName(uri.LocalPath);
                }
                return fileName;
            }

        private void textBox1_TextChanged_1(object sender, EventArgs e)
        {

        }
    }
}

 三、运行结果

 


总结

归纳与总结

  在现有的程序基础上,我通过导入第三方库学习了更多控件的使用和互相联系,加深了对C#控件使用的理解。目前程序已经实现了多种常见音乐格式如MP3、OGG以及在线音乐的播放,但仍有一些不足之处:

  1. 不支持APE、AAC、NCM等部分新型或特有的音乐格式。
  2. 播放控制功能有限: 当前的播放器缺少一些常见的播放控制功能。
  3. 音频信息显示不完善: 播放器目前对于音频文件的信息显示比较简单。

改进建议

1.支持更多音频格式:

  • 研究并集成第三方解码库,如ffmpeg、libmpg123等,以支持APE、AAC、NCM等格式。
  • 如有必要,可尝试自行编写解码器模块,深入学习音频编解码原理。

2.加入高级音频处理功能:

  • 利用NAudio等库提供的音频效果处理功能,开发均衡器、混响、压限等音效调节功能。
  • 学习数字信号处理(DSP)相关知识,尝试自行实现某些音频效果算法。 

3.完善播放控制功能:

  • 添加播放速度调节功能,允许用户在0.5x到2x之间改变播放速度。
  • 实现AB段循环播放,方便用户反复聆听某个片段。
  • 支持显示歌词,并与播放进度同步滚动。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羊布鹅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值