有了单个的英文字符串,咱们就可以得到整个的英文字符串数组,如下:
public List<string> 得到短语列表() { List<string> phraseContent = new List<string>(); //获取短语列表和时间有点不同,因为循环会多一次 for (int i = 0; i < LRC文件内容.Length; i++) { if (获取匹配英文短语(LRC文件内容[i]) == null)//没有找到匹配项,继续 { continue; } else { phraseContent.Add(获取匹配英文短语(LRC文件内容[i])); } } return phraseContent; }
这儿的循环和获取时间对不同,相信看官能够领悟到为什么.
如何到获取文件内容呢?LrC是个文本文件,用C#自带的File.ReadAllLines就可以得到所有的行:
private string[] 读取LRC文件(string 媒体文件名) { //将文件名后缀改为lrc以便得到一个新的文件名 //如果用IndexOf有可能因为文件中有两个.而造成故障 //所以需要使用最后一个匹配 int 点处的位置 = 媒体文件名.LastIndexOf('.'); string lrc文件名 = 媒体文件名.Replace(媒体文件名.Substring(点处的位置+1,3), "lrc"); if (File.Exists(媒体文件名) && File.Exists(lrc文件名)) { try { return File.ReadAllLines(lrc文件名); } catch (Exception) { string output = string.Format("{0}文件读取错误", lrc文件名); throw new Exception(output); } } else { string output = string.Format("{0}或{1}不存在!", 媒体文件名,lrc文件名); throw new Exception(output); } }
public LRC(string 媒体文件名) { this.LRC文件内容 = 读取LRC文件(媒体文件名); }
这段程序对需要播放的媒体文件有个要求,就是需要你的媒体文件名和lrc要同时存在,并且其文件名要相同
构造函数中有一个this.LRC文件内容,这是一个字符串数组,所有的时间对和英文短语都以它为基础.
OK,到现在为止,一个读取LRC,并且能够从中产生时间对和字符串的类就完成了,下面咱们就可以配合WMP来使用它了.
先来看看如何播放和停止声音中的某些片段:
private void button播放_Click(object sender, EventArgs e) { //axWindowsMediaPlayer1.Ctlcontrols.currentPosition = 11.01;表示11.01秒 //对currentPosition赋值就表示你想从什么时间开始 //和下面的时钟配合就可以做到精确的片段播放 axWindowsMediaPlayer1.Ctlcontrols.currentPosition = 开始时间; axWindowsMediaPlayer1.Ctlcontrols.play(); } private void timer1_Tick(object sender, EventArgs e) { var 毫秒时间 = 取得毫秒(axWindowsMediaPlayer1); //这里需要用>=判断,用==有时候会失灵,推断可能是浮点数的不确定造成的 if (毫秒时间 >= 结束时间) { axWindowsMediaPlayer1.Ctlcontrols.pause(); } //不停的显示当前播放时间 label1.Text = 毫秒时间.ToString(); }
private static double 取得毫秒(AxWindowsMediaPlayer 媒体控件) { //直接返回当前时间也是OK的 //return 媒体控件.Ctlcontrols.currentPosition; //不过为了显示的好看,还是只取小数点后两位 //比如3.45986*100=345.986 //Math.Floor(345.986)取最小整数变成345 //再除以100,变成3.45,就实现了只取2位小数,并且不四舍五入 return Math.Floor(媒体控件.Ctlcontrols.currentPosition * 100) / 100; //如果想取三位,可以这样: //return Math.Floor(媒体控件.Ctlcontrols.currentPosition * 1000) / 1000; }
主要用到WMP中的几个最常用的片段播放控制
Ctlcontrols.currentPosition ,从你指定的时间开始,后面跟上Ctlcontrols.play(); 就会一直播放,如果你没有设置结束时间,那么会一直播放到媒体文件结束.
对结束的控制,用了一个Timer控件,这个timer会不停的循环,每隔10毫秒(Interval)就会执行一次,注意其起始状态是关闭的(Enabled=False),因为程序运行的时候只有在读取完lrc文件后才能开始控制,所以要先关闭.
Ctlcontrols.pause是暂停,一开始我用的是Ctlcontrols.Stop,结果开始时间变为0,这个是需要注意的地方.
现在可以控制片段播放了,那么如何得到我所需要的时间对呢?这个需要用到listBox以及获取到的短语列表.
先选择一个媒体文件:
private void button选择文件_Click(object sender, EventArgs e) { //所有的初始化都在读取LRC文件后开始! openFileDialog1.Filter = "音乐文件(*.mp3)(*.wma)|*.mp3;*.wma|所有文件(*.*)|*.*"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { axWindowsMediaPlayer1.URL = openFileDialog1.FileName; LRC myLRC = new LRC(openFileDialog1.FileName); 时间对列表 = myLRC.得到时间对列表(); //将所有的英文短语读取到一个listBox中 短语列表=myLRC.得到短语列表(); listBox短语列表.DataSource = 短语列表; //手动调用以便一开始就朗读! button全部播放.PerformClick(); button上一句.Visible = true; button下一句.Visible = true; button播放.Visible = true; //一开始时钟是停止的 timer1.Start(); } }
在窗体中我先定义了几个变量
private double 开始时间; private double 结束时间; private List<时间对> 时间对列表; private List<string> 短语列表;
现在listBox中有了文本显示,当你点击listBox中的某一项时,程序就会得到那一句的时间对,使用listBox的一个SelectedIndexChanged事件来进行处理
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { //一开始加载listBox1的内容时时间对列表可能是空 //这里假定获取到的时间对列表和短语列表其顺序是一致的 //如果LRC不规范有可能造成不一致的现象发生 //因为他们是分开获取的 if (时间对列表 != null) { 开始时间 = 时间对列表[listBox短语列表.SelectedIndex].开始时间; 结束时间 = 时间对列表[listBox短语列表.SelectedIndex].结束时间; } } 比如,当你点击第二行时,程序会取得listBox短语列表.SelectedIndex的值,为1,而因为我的时间对列表是一个List<时间对>,理论上他们是一一对应的,所以可以使用下标来访问,这样就可以取得相对应的开始和结束时间,
当点击播放的时候就会按照你选择的句子所在的时间来播放.
OK,核心的功能已经完成,下面咱们来处理一些控制上的细节.
待续...