听音乐不过瘾?自制一个音乐播放器!| 原力计划

2020 年 6 月 11 日 CSDN

作者 |  灰小猿
责编 | 夕颜
出品 | CSDN博客

最近在学习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 删除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格式,将空格删除再进行歌词显示处理。


版权声明:本文为CSDN博主「灰小猿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。


原文链接:https://blog.csdn.net/weixin_44985880/article/details/106120326


【END】

更多精彩推荐

☞程序员之痛:六次创业五回失败了

研发的未来在哪里?Serverless 云开发来了!

张一鸣是如何练就字节跳动的

性能超越最新序列推荐模型,华为诺亚方舟提出记忆增强的图神经网络

DevOps 在移动应用程序开发中扮演什么角色?

稳定币经济:十大稳定币简史

你点的每个“在看”,我都认真当成了喜欢
登录查看更多
0

相关内容

音乐,广义而言,指精心组织声音,并将其排布在时间和空间上的艺术类型。
Linux导论,Introduction to Linux,96页ppt
专知会员服务
78+阅读 · 2020年7月26日
【2020新书】现代C++初学者指南,301页pdf
专知会员服务
159+阅读 · 2020年7月24日
【Google】多模态Transformer视频检索,Multi-modal Transformer
专知会员服务
102+阅读 · 2020年7月22日
【2020新书】实战R语言4,323页pdf
专知会员服务
100+阅读 · 2020年7月1日
Transformer文本分类代码
专知会员服务
116+阅读 · 2020年2月3日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
Stabilizing Transformers for Reinforcement Learning
专知会员服务
59+阅读 · 2019年10月17日
手把手教你用Python实现“坦克大战”,附详细代码!
机器学习算法与Python学习
11+阅读 · 2019年6月8日
听完了1000+首古风歌曲,我发现自己也能火
PingWest品玩
4+阅读 · 2019年6月2日
渗透某德棋牌游戏
黑白之道
12+阅读 · 2019年5月17日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
百闻不如一码!手把手教你用Python搭一个Transformer
大数据文摘
18+阅读 · 2019年4月22日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
Python | 爬爬爬:爬百度云,爬百度贴吧,爬爱奇艺
计算机与网络安全
3+阅读 · 2018年3月30日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
Deformable Style Transfer
Arxiv
14+阅读 · 2020年3月24日
Deflecting Adversarial Attacks
Arxiv
8+阅读 · 2020年2月18日
Arxiv
12+阅读 · 2019年2月28日
Arxiv
7+阅读 · 2018年9月27日
Rapid Customization for Event Extraction
Arxiv
7+阅读 · 2018年9月20日
VIP会员
相关VIP内容
Linux导论,Introduction to Linux,96页ppt
专知会员服务
78+阅读 · 2020年7月26日
【2020新书】现代C++初学者指南,301页pdf
专知会员服务
159+阅读 · 2020年7月24日
【Google】多模态Transformer视频检索,Multi-modal Transformer
专知会员服务
102+阅读 · 2020年7月22日
【2020新书】实战R语言4,323页pdf
专知会员服务
100+阅读 · 2020年7月1日
Transformer文本分类代码
专知会员服务
116+阅读 · 2020年2月3日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
Stabilizing Transformers for Reinforcement Learning
专知会员服务
59+阅读 · 2019年10月17日
相关资讯
手把手教你用Python实现“坦克大战”,附详细代码!
机器学习算法与Python学习
11+阅读 · 2019年6月8日
听完了1000+首古风歌曲,我发现自己也能火
PingWest品玩
4+阅读 · 2019年6月2日
渗透某德棋牌游戏
黑白之道
12+阅读 · 2019年5月17日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
百闻不如一码!手把手教你用Python搭一个Transformer
大数据文摘
18+阅读 · 2019年4月22日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
Python | 爬爬爬:爬百度云,爬百度贴吧,爬爱奇艺
计算机与网络安全
3+阅读 · 2018年3月30日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
相关论文
Deformable Style Transfer
Arxiv
14+阅读 · 2020年3月24日
Deflecting Adversarial Attacks
Arxiv
8+阅读 · 2020年2月18日
Arxiv
12+阅读 · 2019年2月28日
Arxiv
7+阅读 · 2018年9月27日
Rapid Customization for Event Extraction
Arxiv
7+阅读 · 2018年9月20日
Top
微信扫码咨询专知VIP会员