这个是歌词,大家假如要让这个歌词和当前歌词的进度相匹配,应该怎么匹配时间呢?
本人匹配的慢了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 = "结束";
}