zoukankan      html  css  js  c++  java
  • (原创)C#LRC复读机2

    有了单个的英文字符串,咱们就可以得到整个的英文字符串数组,如下:

    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文件后才能开始控制,所以要先关闭.

    image

    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事件来进行处理

    image
    private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        //一开始加载listBox1的内容时时间对列表可能是空
        //这里假定获取到的时间对列表和短语列表其顺序是一致的
        //如果LRC不规范有可能造成不一致的现象发生
        //因为他们是分开获取的
        if (时间对列表 != null)
        {
            开始时间 = 时间对列表[listBox短语列表.SelectedIndex].开始时间;
            结束时间 = 时间对列表[listBox短语列表.SelectedIndex].结束时间;
        }
    }
    比如,当你点击第二行时,程序会取得listBox短语列表.SelectedIndex的值,为1,而因为我的时间对列表是一个List<时间对>,理论上他们是一一对应的,所以可以使用下标来访问,这样就可以取得相对应的开始和结束时间,

    当点击播放的时候就会按照你选择的句子所在的时间来播放.

    OK,核心的功能已经完成,下面咱们来处理一些控制上的细节.

    待续...

  • 相关阅读:
    sync.WaitGroup golang并发调度器
    Golang New 关键字的小bug 未找到原因(暂时)
    zabbix监控websphere的几个监控项
    zabbix监控AIX DB2数据库
    NOIP2008P 排座椅
    解题报告—— 2018级2016第二学期第五周作业 删数问题
    解题报告——2018级2016第二学期第五周作业排座椅
    解题报告——2018级2016第二学期第四周作业 (2的幂次方)
    解题报告——-2018级2016第二学期第三周作业
    解题报告——2018级2016第二学期第二周作业
  • 原文地址:https://www.cnblogs.com/angestudy/p/2029140.html
Copyright © 2011-2022 走看看