有了单个的英文字符串,咱们就可以得到整个的英文字符串数组,如下:
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 媒体控件)主要用到WMP中的几个最常用的片段播放控制
{
//直接返回当前时间也是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;
}
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,核心的功能已经完成,下面咱们来处理一些控制上的细节.
待续...