用c#实现简单音乐播放器

一、功能需求

  1. 播放MP3文件:可播放MP3文件
  2. 播放OGG文件:可播放OGG文件
  3. 用户界面:一个简单的窗口,包含播放和暂停按钮及文件选择功能
  4. 异常处理:程序能处理可能处理可能出现的异常,如文件不存在、文件读取错误等
  5. 兼容性:确保代码能在多个c#版本上运行

二、设计思路分析

  • 架构选择

    考虑到需求中的界面友好和跨版本兼容性,我们可以选择选择Windows Forms作为开发平台,Windows Forms提供了一个简单而强大的方法来创建桌面应用程序,并且与C#高度兼容,在开发过程,我们选择.NETFramework 4.8.0进行程序设计。

  • 设计思路

    1. 界面设计: 使用Windows Forms工具箱中的控件如按钮、标签和文件对话框构建用户界面。
    2. 功能编码: 使用OpenFileDialog允许用户选择音频文件。 根据文件扩展名调用相应的播放器对象进行播放。 播放控制,包括开始、暂停和停止。
    3. 异常处理: 捕获并响应各种可能的运行时错误,如文件读取失败、文件格式不支持等,为用户提供清晰的错误信息。
  • 难点分析

    1. 文件格式支持: 处理多种音频格式(MP3,OGG等)要求使用不同的库,这可能导致代码复杂度增加。
    2. 异常处理: 音频文件的播放中可能遇到多种异常情况,如文件损坏、编解码器不支持等。

三、窗体设计

按照需求设计窗体,并进行一定的美化

  • Label:展示当前播放的歌曲
  • Listbox:展示歌曲列表
  • AxWindowsMediaPlayer:播放常规音乐
  • Button:选择歌曲文件、停止播放、下一曲
  • TraceBarl:用于音量控制

四、代码实现

  1. 头文件引入

    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;
  2. 类成员变量定义

    c# 复制代码
    List<string> localmusiclist = new List<string> { };
    private WaveOutEvent waveOut = new WaveOutEvent();
    private VorbisWaveReader currentVorbisReader;

    在类中,localmusiclist在音乐播放时用来追踪和管理用户加载的音乐文件集合,waveOut用于播放ogg文件,currentVorbisReader为当前播放ogg文件的状态

  3. 按钮控件

    • 歌曲文件选择

      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来显示当前播放音乐的信息。

  4. 音乐选择控件

    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的值

  5. 音乐播放函数

    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捕获播放错误来防止读取文件产生的错误导致程序卡死。

  6. 音量控制组件

    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文件。 此外,程序还缺少一些高级音频功能的设置,比如音频效果处理(如均衡器、声音增强等),以及支持音频流的直接下载和播放。

相关推荐
却尘1 天前
Server Actions 深度剖析(2):缓存管理与重新验证,如何用一行代码干掉整个客户端状态层
前端·客户端·next.js
程序员老刘3 天前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Lei活在当下4 天前
【业务场景架构实战】1. 多模块 Hilt 使用原则和环境搭建
性能优化·架构·客户端
万少9 天前
可可图片编辑 HarmonyOS(3)应用间分享图片
前端·harmonyos·客户端
程序员老刘13 天前
Dart MCP翻车了!3.9.0版本无法运行,这个坑你踩过吗?
flutter·ai编程·客户端
程序员老刘14 天前
Cursor vs Claude Code vs AS+AI助手:谁才是客户端的编程神器?
flutter·ai编程·客户端
麦客奥德彪20 天前
React native 项目函数式编程的背后-另类的架构InversifyJS 依赖注入(DI)
react native·架构·客户端
fouryears_2341725 天前
Flutter InheritedWidget 详解:从生命周期到数据流动的完整解析
开发语言·flutter·客户端·dart
程序员老刘25 天前
Flutter 3.35 更新要点解析
flutter·ai编程·客户端
红橙Darren25 天前
手写操作系统 - 编译链接与运行
android·ios·客户端