酷狗KRC歌词文件解析和与LRC的转换

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Text;

using System.Text.RegularExpressions;

using zlib;//using前要先引用

namespace KrcLib

{

publicclass KrcReader : IDisposable

{

private Stream _sourceStream = new MemoryStream();

public Stream SourceStream

{

get { return _sourceStream; }

privateset { _sourceStream = value; }

}

///

///用包含krc数据的流创建

///

///包含krc数据的流

public KrcReader(Stream sourceStream)

{

sourceStream.CopyTo(this.SourceStream);

this.SourceStream.Position = 0;

}

///

///打开krc文件

///

///文件全路径

public KrcReader(string fileName)

{

this.SourceStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

}

///

///将包含krc数据的流解析为包含明码的流

///

///明码流

public Stream GetKrcStream()

{

//krc数据需要先解密再解压缩

//在这之前先去掉头部4字节的krc歌词版本号:krc1 其HEX为:6b 72 63 31

//解密:遍历字节时循环地使每个字节与数组h中对应元素异或运算

//解压缩:zlib使用LZ77的变种算法,DEFLATE的算法

char[] h = { '@', 'G', 'a', 'w', '^', '2', 't', 'G', 'Q', '6', '1', '-', 'Î', 'Ò', 'n', 'i' }; MemoryStream outStream = new MemoryStream();

ZOutputStream outZStream = new ZOutputStream(outStream);

SourceStream.Position = 4;//去掉头部4字节

int len = 0;

byte[] databuffer = newbyte[1024];

while ((len = SourceStream.Read(databuffer, 0, 1024)) > 0)

{

int m;

for (int k = 0; k < len; k++)

{

m = k % 16;

databuffer[k] = (byte)(databuffer[k] ^ h[m]);//异或解密

}

outZStream.Write(databuffer, 0, len);//zlib解压缩

}

outZStream.finish();

MemoryStream tmp = new MemoryStream();

outStream.Position = 0;

outStream.CopyTo(tmp);//复制新的流以便outZStream.Close()时不会关闭要返回的流

tmp.Position = 0;//tmp被CopyTo时到了尾部,返回前需要重置位置

outStream = tmp;//指向刚复制的流用于返回

outZStream.Close();

return outStream;

}

///

///将包含krc数据的流解析为字符串

///

///解析后的字符串

publicstring GetKrcString()

{

using (Stream decodedStream = GetKrcStream())

{

byte[] buffer = newbyte[decodedStream.Length];

int i = decodedStream.Read(buffer, 0, buffer.Length);

return Encoding.UTF8.GetString(buffer, 0, i);

}

}

///

///将包含krc数据的流解析为按行存储的列表

///

///解析后的行列表

public List GetKrcList()

{

List rowList = new List();

using (StreamReader sr = new StreamReader(GetKrcStream(), Encoding.UTF8))

{

while (!sr.EndOfStream)

rowList.Add(sr.ReadLine());

}

return rowList;

}

///

///将包含krc数据的流转换为按行存储的lrc格式列表

///

///lrc格式列表

public IEnumerable ToLrcList()

{

List krcList = GetKrcList();

//List lrcList = new List();

Regex rowReg = new Regex(@"^\[\d+,\d+\](<\d+,\d+,\d+>.+)*");//匹配一行krc格式的歌词

Regex timeLableReg1 = new Regex(@"^\[\d+,\d+\]");//匹配krc格式行的时间

Regex timeLableReg2 = new Regex(@"<\d+,\d+,\d+>");//匹配krc格式字的时间

char[] splitChars = { '[', ',', ']' };//用于取得每行的开始时刻

Regex idLabelReg = new Regex(@"^\[(ar|ta|al|by|offset|encoding|la|fm|wl|wm|co|ad):.*\]$", RegexOptions.IgnoreCase);

IEnumerable lrcIdLabelList = from row in krcList

where idLabelReg.IsMatch(row) == true

select row;

IEnumerable lrcTextList = from row in krcList

where rowReg.IsMatch(row) == true

let newRow2 = timeLableReg2.Replace(row, "")//去除对每个字的时间标签,如<0,751,0>

let timeKrcLabel = timeLableReg1.Match(newRow2).Value//获取对行的时间标签,如[2781,3355]

let timeKrc = Convert.ToInt32(timeKrcLabel.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)[0]) * 10000//获取每行的开始时刻,以100纳秒为单位

let timeLrc = new DateTime(timeKrc).ToString("[mm:ss.ff]")//生成lrc格式的时间标签,如[00:02.78]

//let timeLrc = string.Format("[{0:mm}:{0:ss}.{0:ff}]", new DateTime(timeKrc))

//let timeKrc = Convert.ToSingle(timeKrcLabel.Split(splitChars,StringSplitOptions.RemoveEmptyEntries)[0]) / 1000

//let timeLrc = string.Format("[{0:00}:{1:00.00}]", timeKrc / 60, timeKrc % 60)

相关文档
最新文档