开发者社区> 灰小猿> 正文

听音乐不过瘾?自制一个音乐播放器!【附带函数源码】

简介: 听音乐不过瘾?自制一个音乐播放器!【附带函数源码】
+关注继续查看
C#的音乐播放器是基于C#窗体程序而设计开发,是学习C#winform开发的一个较好的实战项目。本文讲解了音乐播放器的基本控件的函数编写及开发思路

@TOC

在这里插入图片描述
最近在学习C#的GUI编程时想着自制一个播放器,说干就干。

其实C#除了在游戏开发上具有显著优势以外,在winform交互页面设计和web网站开发上也是独树一帜的。

那么对于使用C#自己开发一个音乐播放器,首先应该了解的当然就是播放器的基本构成了,毕竟知己知彼方能百战不殆嘛,和我们平常使用的音乐播放器一样。

我们制作的播放器当然也应该具有对音乐的添加、删除、多选、静音、暂停、停止、切换、

同时为了更加符合常用播放器的使用习惯,我们当然还需要添加自动切换下一曲、实时时间显示、播放器屏幕等基本操作啦,

在这里插入图片描述
.

现在当我们知道我们的播放器需要实现哪些功能以后,就是我们搭建整个播放器的界面和函数方法的阶段了,在VS软件的设计界面,我们可以很轻松的对播放器的界面进行整体布局,

同时我们所添加的每一个控件都有它独特的属性,我们可以对控件的属性进行个性化的设置,增加我们更好的体验感。

下面这个是大灰狼搭建的播放器界面,小伙伴们可以参考,其中播放器所需的基本界面和所需的功能都有实现。

在这里插入图片描述

在界面设计完成以后,就是后端函数的书写操作了,

打开音乐文件控件函数

该函数的目的是为了我们从系统文件中添加音乐文件。

基本思路是:先定义一个存放每一首音乐路径的列表,然后在选择音乐文件之后,依次将所选音乐文件的路径添加到路径列表之中。其中需要注意的是:我们需要设置音乐的起始默认打开位置和所选择的音乐格式,一般来说音乐的格式有mp3、WAV、flac等,在属性中设置音乐格式时应注意,每一个格式应该使用分号进行分割开。

函数实现代码如下:

//定义一个列表存放文件路径
        List<string> listpath = new List<string>();

   //设置打开音乐文件属性
        private void openmusic_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();

            //设置音乐的起始默认打开位置
            ofd.InitialDirectory = @"‪C:/Users/郭运刚/Music";

            //设置可以匹配的音乐格式
            ofd.Filter = "MP3文件|*.mp3;*.wav";
            //ofd.Filter = null;

            //设置上方的标题框名称
            ofd.Title = "请选择音乐文件!";

            //设置允许多选
            ofd.Multiselect = true;
            ofd.ShowDialog();

            //获取所选文件的全路径
            string[] path = ofd.FileNames;

            for (int i = 0; i < path.Length; i++)
            {
                //将音乐文件的全路径加入到列表中
                listpath.Add(path[i]);

                //将音乐文件名添加到列表
                listBox1.Items.Add(Path.GetFileName(path[i]));
            }
        }

.

双击音乐触发播放属性函数

在添加好音乐之后,我们当然需要对音乐进行播放,在这里我们需要设置当双击音乐文件后,可以在musicplayer播放器中进行播放。

该函数需要注意的地方是: 我们需要对存放音乐文件的列表进行判断,如果音乐列表为零,也就是说当前并没有可以播放的音乐的时候,我们需要对用户进行提示。同时在我们双击播放音乐之后,我们先前设置的播放音乐的控件,此刻应该显示的是暂停选项。

实现代码如下:

//双击音乐触发播放属性
        private void listBox1_DoubleClick(object sender, EventArgs e)
        {
            if (listBox1.Items.Count == 0)
            {
                MessageBox.Show("请先选择播放音乐!");
                return;
            }
            try
            {
                musicPlayer.URL = listpath[listBox1.SelectedIndex];
                musicPlayer.Ctlcontrols.play();
                playorpause.Text = "暂停";
                //timer1_Tick_1(sender, e);
                //music_plan.Text = musicPlayer.currentMedia.duration.ToString();
                
                //调用函数去处理这个路径下的这首歌的歌词
                IsExistlrc(listpath[listBox1.SelectedIndex]);
            }
            catch
            { }
            
        }

播放或暂停控件属性函数

该控件函数的作用,顾名思义,当然就是控制音乐的播放和暂停,同时需要注意的地方是,当我们点击音乐播放的时候,应该让音乐继续之前的播放,而不是重新开始。同时在我们点击播放或者暂停按钮之后,该控件应该有对应的显示。

实现代码如下:

//设置播放或者暂停按钮属性
    private void playorpause_Click(object sender, EventArgs e)
    {
        if (playorpause.Text == "播放")
        {

            //来个异常,防止列表没有音乐
            try
            {
                //如果继续单击播放,那就让他接着放
                if (b)
                {
                    musicPlayer.URL = listpath[listBox1.SelectedIndex];

                }
            }
            catch
            { }
            musicPlayer.Ctlcontrols.play();
            playorpause.Text = "暂停";
        }
        else if (playorpause.Text == "暂停")
        {
            musicPlayer.Ctlcontrols.pause();
            playorpause.Text = "播放";
            b = false;
        }
   
        
    }

停止控件属性函数

该函数的作用是:当用户点击停止之后,当前正在播放的音乐停止并且回到最初位置。

实现代码如下:

 //设置停止控件属性
        private void button3_Click(object sender, EventArgs e)
        {
            musicPlayer.Ctlcontrols.stop();
            playorpause.Text = "播放";
        }

.

点击下一曲控件函数

该函数的作用是:当我们点击下一曲的时候,可以根据当前播放的音乐列表,播放列表中的下一首歌曲。

实现代码如下:

//点击下一曲
        private void music_down_Click(object sender, EventArgs e)
        {
            //获取当前歌曲索引位置
            int index = listBox1.SelectedIndex;

            //清空歌曲选择索引
            listBox1.SelectedIndices.Clear();

            index++;
            if (index == listBox1.Items.Count)
            {
                index = 0;
            }
            listBox1.SelectedIndex = index;
            musicPlayer.URL = listpath[index];
            musicPlayer.Ctlcontrols.play();
        }

点击下一曲控件函数

该函数的作用是:当我们点击上一曲的时候,可以根据当前播放的音乐列表,播放列表中的上一首歌曲。

实现代码如下:

 //点击上一曲
        private void music_up_Click(object sender, EventArgs e)
        {
            int index = listBox1.SelectedIndex;
            

            listBox1.SelectedIndices.Clear();
            index--;

            //如果此时是第一首歌曲,则索引减一为-1
            if (index == -1)
            {
                //listBox1.Items.Count记录的是歌曲数目,
                //如果跳转到最后一首,索引是数目减一
                index = listBox1.Items.Count - 1;
            }

            listBox1.SelectedIndex = index;

            musicPlayer.URL = listpath[index];
            musicPlayer.Ctlcontrols.play();
        }

音乐删除函数

该函数是将我们已经存放到音乐列表中的音乐进行删除,当我们单击选择某一首音乐后,可以将其从列表中删除。并且不会在自动播放时播放该音乐。

实现代码如下:

 //点击删除
        private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //获取已经选中歌曲的数量
            int count = listBox1.SelectedItems.Count;

            //删除列表中的选中项
            for (int i = 0; i < count; i++)
            {
                //首先删除集合中的歌曲
                listpath.RemoveAt(listBox1.SelectedIndex);
                //再删除存放在列表里的歌曲
                listBox1.Items.RemoveAt(listBox1.SelectedIndex);
            }
            
        }

点击静音函数

点击静音函数的作用是在我们点击之后,音乐静音,但此时的音乐仍然可以继续播放,该徐行与播放器的settings.mute函数有关。

该函数的实现思路是:我们需要对当前音乐是否静音进行一个设定,由于Text静音控件的文本永远都是不变的,所以我们需要借助该控件下的Tag属性进行赋值判断,

具体实现代码如下:

 //点击静音函数
        private void label1_Click(object sender, EventArgs e)
        {
            if (label1.Tag.ToString() == "1")
            {
                musicPlayer.settings.mute = true;
                
                //label1.Image = Image.FromFile(@"‪C:/Users/郭运刚/Pictures/320578.png");
                label1.Tag = "2";
            }
            else if (label1.Tag.ToString() == "2")
            {
                musicPlayer.settings.mute = false;
                //label1.Image = Image.FromFile(@"C:/Users/郭运刚/Pictures/Saved Pictures/322557.png");
                label1.Tag = "1";
            }
        }

时间监控控件函数

该函数需要我们在添加时间控件之后,与时间监控控件绑定使用,该函数的作用是实时的对播放的音乐进行监控,并且返回当前的播放时间,

具体实现代码如下:

//时间监控控件1
        private void timer1_Tick_1(object sender, EventArgs e)
        {
            //music_plan.Text = "测试";
            //如果播放器的状态是正在播放中
            if (musicPlayer.playState == WMPLib.WMPPlayState.wmppsPlaying)
            {
                //music_plan.Text = "播放";
                music_plan.Text = musicPlayer.currentMedia.duration.ToString() + "\r\n" + musicPlayer.currentMedia.durationString + "\r\n" + musicPlayer.Ctlcontrols.currentPosition.ToString() + "\r\n" + musicPlayer.Ctlcontrols.currentPositionString;

                double t1 = double.Parse(musicPlayer.currentMedia.duration.ToString());
                double t2 = double.Parse(musicPlayer.Ctlcontrols.currentPosition.ToString()) + 1;
                if ( t1 <= t2)
                {
                    //获取当前歌曲索引位置
                    int index = listBox1.SelectedIndex;

                    //清空歌曲选择索引
                    listBox1.SelectedIndices.Clear();

                    index++;
                    if (index == listBox1.Items.Count)
                    {
                        index = 0;
                    }
                    listBox1.SelectedIndex = index;
                    musicPlayer.URL = listpath[index];
                    musicPlayer.Ctlcontrols.play();
                }

            }

        }

判断歌词是否存在函数

了解音乐文件的小伙伴可能都知道,每一首音乐的歌词和音乐文件是相互独立的,通常情况下是音乐文件的文件名后加.lrc为其所对应的歌词文件,所以当我们播放一首歌曲的时候,就需要我们对该歌曲的歌词文件进行判断,判断当前播放的音乐是否具有歌词文件。

如果有,则进行歌词标准化和歌词播放函数,如果没有,当然需要对用户进行相应的提示“未找到歌词”

实现代码如下:

//判断歌词是否存在
        void IsExistlrc(string songPath)
        {
            //每次制作歌词前先清空存放时间和歌词的列表
            listlrcTime.Clear();
            listlrcText.Clear();

            songPath += ".lrc";
            //MessageBox.Show(songPath);
            bool fileIn = File.Exists(songPath);
            if (fileIn)
            {
                //label_lyric.Text = "即将播放歌词";
                //定义一个存放歌词的列表,获取到歌词文件中的内容
                string[] lrcText = File.ReadAllLines(songPath, Encoding.Default);

                //如果歌词存在,则调用函数formatlrc格式化歌词
                formatlrc(lrcText);
            }
            else
            {
                label_lyric.Text = "未找到歌词......";
            }
        }

歌词格式化函数

很多小伙伴可能不知道,起始看到的歌词都是进行过特殊处理的,真正的歌词文件并不是只有歌词的,它还包括每一句歌词应该播放的时间。

如下所示:

在这里插入图片描述

所以我们在显示歌词的时候,就需要对歌词文件进行特殊化处理,让真正显示出来的只有歌词,这里就需要我们对每一句歌词文件进行分割,将获取到的播放时间和歌词,分别存放到对应的列表汇总去。

具体的实现代码如下:

       //定义存储歌词时间的列表
        List<double> listlrcTime = new List<double>();
        //定义存放歌词的列表
        List<string> listlrcText = new List<string>();


 //定义存储歌词时间的列表
        List<double> listlrcTime = new List<double>();
        //定义存放歌词的列表
        List<string> listlrcText = new List<string>();


        //对歌词进行标准格式化函数
        void formatlrc(string [] lrcText)
        {
            for (int i = 0; i < lrcText.Length; i++)
            {
                //去掉歌词每一行前后的[、]
                string[] lrcTemp = lrcText[i].Split(new char[] { '[', ']'}, StringSplitOptions.RemoveEmptyEntries);
                //返回的数组中lrcTemp[0]是时间,  格式为00:00.00
                //lrcTemp[1]是歌词

                //去掉时间字符中的冒号“:”
                string [] lrcNewTemp= lrcTemp[0].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);

                //定义变量time表示时间
                double time = double.Parse(lrcNewTemp[0]) * 60 + double.Parse(lrcNewTemp[1]);

                //把每一次截取到的歌词时间放到lrctime列表中
                listlrcTime.Add(time);

                //MessageBox.Show("测试点1");
                //把对应的每一次的歌词存放到泛型列表listlrcText中
                listlrcText.Add(lrcTemp[1]);
            
            }
            //MessageBox.Show("测试点1");
        }

播放歌词函数

当我们检测到将要播放的歌曲存在歌词文件时,就会对其歌词文件进行格式化处理,并且将歌词实时的播放出来,这时就需要定义另外的一个时间监控控件,来对歌词的播放时间进行监控,并且可以根据时间实时的显示出需要播放的歌词。

具体实现代码如下:

//播放歌词
        private void timer2_Tick(object sender, EventArgs e)
        {
            //label_lyric.Text = "即将播放歌词...";
            for (int i = 0; i < listlrcTime.Count; i++)
            {
                if (musicPlayer.Ctlcontrols.currentPosition >= listlrcTime[i] && musicPlayer.Ctlcontrols.currentPosition < listlrcTime[i + 1])
                {
                    //MessageBox.Show("我要播放歌词了");
                    //将该时间段的歌词在显示歌词的文本框显示
                    label_lyric.Text = listlrcText[i];
                }
            }
        }

各个控件的函数方法完成以后,音乐播放器的基本功能就完成了,

其中值得注意的一点是,在进行歌词显示的时候,部分音乐的歌词文件中会隔行出现空格,导致歌词格式化处理函数无法辨别,建议先将歌词文件后缀修改为txt格式,将空格删除再进行歌词显示处理。

==觉得不错记得点赞关注!==

==大灰狼期待与你一同进步!==

在这里插入图片描述

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23543 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22275 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
22224 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
19158 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
11988 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36376 0
+关注
灰小猿
一个用代码编织世界的工程师
70
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载