Code Bye

c#中怎么高效匹配KRC歌词时间


这个是歌词,大家假如要让这个歌词和当前歌词的进度相匹配,应该怎么匹配时间呢?
本人匹配的慢了2秒的样子,估计是循环嵌套的比较深。
大家有什么高效的做法吗?
解决方案

35

给你看看本人的测试代码
    public class SubTitle
    {
        public Bitmap bmp1 = new Bitmap(1, 1);
        public Bitmap bmp2 = new Bitmap(1, 1);
        public bool Eof = true;
        Style style = Style.DoubleRow;
        Font font = new Font("黑体", 24);
        
        public enum Style
        {
            SingleRow, //单行
            DoubleRow, //双行
            DoubleRowAlternation, //双行交替
        }
        class Krc
        {
            public int StartTime;
            public int EndTime;
            public string Word;
            public int[] Durations;
            public GraphicsPath path;
            public int last = 0;
            public int point = 0;
            public bool IsTimeOut(int msec)
            {
                if (last == 0) point = 0;
                if (msec >= StartTime + last)
                {
                    last += Durations[point++];
                    return true;
                }
                return false;
            }
        }
        List<Krc> dat = new List<Krc>();
        int sp = 0;
        public void Prepare(Font f = null, SubTitle.Style s = SubTitle.Style.DoubleRow)
        {
            if (f is Font) font = f;
            style = s;
            var rect = RectangleF.Empty;
            foreach (var x in dat)
            {
                x.path = new GraphicsPath();
                x.path.AddString(x.Word, font.FontFamily, 1, font.Size, Point.Empty, new StringFormat());
                rect = RectangleF.Union(rect, x.path.GetBounds());
                x.last = 0;
            }
            bmp1 = new Bitmap((int)Math.Ceiling(rect.X + rect.Width) + 2, (int)Math.Ceiling(rect.Y + rect.Height) + 2);
            bmp2 = new Bitmap((int)Math.Ceiling(rect.X + rect.Width) + 2, (int)Math.Ceiling(rect.Y + rect.Height) + 2);
            sp = 0;
            Eof = false;
        }
        public bool Open(string fname)
        {
            foreach (var buf in File.ReadAllLines(fname, Encoding.GetEncoding("gbk")))
            {
                var m = Regex.Matches(buf, @""([\d\w:.,]+)"").Cast<Match>().ToArray();
                if (m.Length == 4)
                {
                    var krc = new Krc();
                    krc.StartTime = (int)(TimeSpan.Parse("00:" + m[0].Groups[1].Value).TotalMilliseconds);
                    krc.EndTime = (int)(TimeSpan.Parse("00:" + m[1].Groups[1].Value).TotalMilliseconds);
                    krc.Word = m[2].Groups[1].Value;
                    krc.Durations = m[3].Groups[1].Value.Split(",").Select(x => int.Parse(x)).ToArray();
                    dat.Add(krc);
                }                
            }
            if (dat.Count == 0) return false;
            return Eof = true;
        }
        public bool IsTimeOut(int msec)
        {
            if (sp >= dat.Count)
            {
                Eof = true;
                return false;
            }
            if (msec >= dat[sp].StartTime) return draw(msec); 
            return false;
        }
        bool draw(int msec)
        {
            if (msec >= dat[sp].EndTime) sp++;
            if (sp >= dat.Count)
            {
                Eof = true;
                return false;
            }
            if (!dat[sp].IsTimeOut(msec)) return false;
            
            switch (style)
            {
                case Style.DoubleRow:
                    return doubleRow();
                case Style.DoubleRowAlternation:
                    return doubleRowAlternation();
            }
            return false;
        }
        bool doubleRow()
        {
            var g1 = Graphics.FromImage(bmp1);
            var g2 = Graphics.FromImage(bmp2);
            if (sp % 2 == 0)
            {
                g1.Clear(Color.FromArgb(0, 0, 0, 0));
                g1.FillPath(Brushes.Black, dat[sp].path);
                if (sp + 1 < dat.Count)
                {
                    g2.Clear(Color.FromArgb(0, 0, 0, 0));
                    g2.FillPath(Brushes.Black, dat[sp + 1].path);
                }
            }
            var g = sp % 2 == 0 ? g1 : g2;
            var pr = dat[sp].path.GetBounds();
            int w = (int)Math.Ceiling(pr.X + pr.Width * dat[sp].point / dat[sp].Durations.Length);
            int h = (int)Math.Ceiling(pr.Y + pr.Height);
            g.Clip = new Region(new Rectangle(0, 0, w, h));
            g.DrawPath(Pens.Green, dat[sp].path);
            return true;
        }
        bool doubleRowAlternation()
        {
            var g1 = Graphics.FromImage(bmp1);
            var g2 = Graphics.FromImage(bmp2);
            if (sp == 0)
            {
                g1.Clear(Color.FromArgb(0, 0, 0, 0));
                g1.FillPath(Brushes.Black, dat[sp].path);
                if (sp + 1 < dat.Count)
                {
                    g2.Clear(Color.FromArgb(0, 0, 0, 0));
                    g2.FillPath(Brushes.Black, dat[sp + 1].path);
                }
            }
            else
            {
                if (sp % 2 == 0 && sp + 1 < dat.Count)
                {
                    g2.Clear(Color.FromArgb(0, 0, 0, 0));
                    g2.FillPath(Brushes.Black, dat[sp + 1].path);
                }
                if (sp % 2 == 1 && sp + 1 < dat.Count)
                {
                    g1.Clear(Color.FromArgb(0, 0, 0, 0));
                    g1.FillPath(Brushes.Black, dat[sp + 1].path);
                }
            }
            var g = sp % 2 == 0 ? g1 : g2;
            var pr = dat[sp].path.GetBounds();
            int w = (int)Math.Ceiling(pr.X + pr.Width * dat[sp].point / dat[sp].Durations.Length);
            int h = (int)Math.Ceiling(pr.Y + pr.Height);
            g.Clip = new Region(new Rectangle(0, 0, w, h));
            g.DrawPath(Pens.Red, dat[sp].path);
            return true;
        }
    }

歌词

karaoke := CreateKaraokeObject;
karaoke.rows := 2;
karaoke.clear;
// 歌曲附加信息(便于检索)
karaoke.tag("歌名", "偶然");
karaoke.internalnumber := 1461;  // 歌曲编号
karaoke.tag("缩写", "or");
karaoke.tag("歌手", "蔡琴");
karaoke.tag("字数", "2");
karaoke.tag("语种", "国语");	// 国语/粤语/台语/外语
karaoke.tag("歌类", "女");	// 男/女/乐队/合唱/戏曲/舞曲
karaoke.tag("风格", "流行");
karaoke.videofilename := "pt85440";
karaoke.audiofilename := "*.wav";
karaoke.add("01:05.001", "01:07.284", "你本人相逢", "300,431,474,1078");
karaoke.add("01:07.971", "01:11.374", "在黑夜的海上", "431,431,473,387,474,1207");
karaoke.add("01:12.709", "01:14.819", "你有你的", "387,431,516,776");
karaoke.add("01:15.508", "01:18.823", "本人有本人的方向", "345,433,471,474,472,1120");
karaoke.add("01:21.061", "01:22.956", "你记得也好", "603,172,258,344,518");
karaoke.add("01:24.980", "01:28.037", "最好你忘掉", "259,559,603,861,775");
karaoke.add("01:28.774", "01:31.140", "在那交会时", "429,431,517,474,515");
karaoke.add("01:31.529", "01:36.955", "互放的光亮", "430,603,1636,1336,1421");
karaoke.add("01:42.727", "01:48.326", "本人是天空的一片云", "259,301,344,1292,216,216,1895,1076");
karaoke.add("01:49.662", "01:54.183", "偶尔投影在你的波心", "345,344,429,431,388,431,559,862,732");
karaoke.add("01:57.103", "02:02.055", "你不心讶异无须欢欣", "259,344,345,344,430,345,474,1722,689");
karaoke.add("02:03.132", "02:08.689", "在转瞬间消灭了踪影", "259,302,430,1465,344,430,474,861,992");
karaoke.add("02:12.478", "02:17.863", "本人是天空的一片云", "390,343,387,1034,172,260,1764,1035");
karaoke.add("02:19.025", "02:23.374", "偶尔投影在你的波心", "302,344,431,387,430,475,473,775,732");
karaoke.add("02:26.002", "02:31.557", "你不心讶异无须欢欣", "345,301,517,431,473,388,473,1938,689");
karaoke.add("02:32.247", "02:39.137", "在转瞬间消灭了踪影", "431,474,516,1378,432,473,644,1594,948");
karaoke.add("02:42.583", "02:45.555", "你本人相逢", "602,603,562,1205");
karaoke.add("02:46.201", "02:49.517", "在黑夜的海上", "387,430,431,474,475,1119");
karaoke.add("02:50.851", "02:52.918", "你有你的", "390,557,431,689");
karaoke.add("02:53.564", "02:57.269", "本人有本人的方向", "518,430,473,432,603,1249");
karaoke.add("02:58.432", "03:01.144", "你记得也好", "516,431,516,560,689");
karaoke.add("03:03.428", "03:06.915", "最好你忘掉", "429,560,603,863,1032");
karaoke.add("03:09.205", "03:11.877", "在那交会时", "604,516,517,691,344");
karaoke.add("03:12.608", "03:19.672", "互放的光亮", "430,776,2239,2240,1379");

测试代码

            var krc = new SubTitle();
            krc.Open("偶然(蔡琴).ksc");
            krc.Prepare(null, SubTitle.Style.DoubleRowAlternation);
            label1.Text = "运行";
            //用一个循环来模拟播放器,i 对应播放器的已播放时长(毫秒)
            int i = 0;
            while(! krc.Eof)
            {
                if (krc.IsTimeOut(i))
                {
                    pictureBox1.Image = krc.bmp1;
                    pictureBox2.Image = krc.bmp2;
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(500); //太快看不清,挂起0.5秒。实用时是不需要的
                }
                i++;
            }
            label1.Text = "结束";
        }

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明c#中怎么高效匹配KRC歌词时间