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,核心的功能已经完成,下面咱们来处理一些控制上的细节.

    待续...

  • 相关阅读:
    扫面线模板
    (动态规划、栈)leetcode 84. Largest Rectangle in Histogram, 85. Maximal Rectangle
    tmux 常见命令汇总
    leetcode 221
    leetcode 319 29
    (贪心)leetcode 392. Is Subsequence, 771. Jewels and Stones, 463. Island Perimeter
    leetcode 982 668
    Python import 同文件夹下的py文件的函数,pycharm报错
    Windows里Anaconda-Navigator无法打开的解决方案
    Windows下 gpu版 Tensorflow 安装
  • 原文地址:https://www.cnblogs.com/angestudy/p/2029140.html
Copyright © 2011-2022 走看看