目录
前言
- 音乐软件在播放歌曲时,能同步显示歌词,一般都是引用了对应的歌词文件,而歌词文件主要要存储的就是歌词内容,以及每一句歌词、每一个歌词文字的播放时间。由此引申出的歌词格式就很多了,有LRC、SRT、SSA等,其中LRC是最为流行和广泛使用的格式。
- LRC是一般认为是逐行歌词。
LRC格式
- 尽管LRC歌词有标准规定,但它在网络上流传的非标准格式也非常多,所以,如果你希望做一个兼容性足够高的LRC解析器,很有必要考虑兼容常见的非标准格式做好一些容错。
- 下面我们先来介绍一下它的格式:
标识标签(ID-tags)
- 格式为 [标识名称:值]。大小写等价。
- 标准预定义了一些标签:
- [ar:艺术家];示例:[ar:coolight]
- [ti:歌曲名称];示例:[ti:hello world]
- [al:专辑名称];示例:[al:hello]
- [by:制作LRC歌词的作者];示例:[by:coolight]
- [offset:[+/-]时间补偿值] 其单位是毫秒(1秒=1000毫秒),正值表示整体提前,负值相反。这是用于总体调整显示快慢。示例:[offset:0], [offset:100], [offset:+100], [offset:-200]
- 当然你也可以自定义标签,一般自定义标签的名称不应当由数字开头
- 标签之后的内容需要忽略,比如:
- [ti:hello world] aaabbbccc
- 标签是[ti:hello world]
- 之后的内容是aaabbbccc,这部分应对忽略掉
- 一般是一个标签占一行,但也需要考虑兼容一行多标签
- 注意兼容允许内部的空格,比如:[ offset : +200 ] 内容
时间标签(Time-tag)
- 这个比较复杂,非标准格式也是多种多样
- 注意1秒=1000毫秒
- 下面我们用m代表分钟,s代表秒,f代表毫秒,常见格式有:
- [mm:ss.ff],即[分钟:秒.(毫秒/10)],分钟和秒之间用冒号:隔开,而秒和毫秒之间用点.隔开,毫秒部分是真实毫秒值 / 10得到的,因此它是一个二位数。
- [mm:ss:ff],同上,差别在于秒和毫秒之间用冒号:隔开而不是点.
- [mm:ss.fff],同上,差别在于毫秒部分不需要除以10,是真实的毫秒值,因此有3位
- [mm:ss:fff],同上,差别在于秒和毫秒之间用冒号:隔开而不是点.
- [mm:ss],这个格式没有了毫秒部分
- 一般来讲,分钟、秒、毫秒都会是正整数,但应当考虑兼容匹配负数,如果出现负数,则可以考虑将负数置零或者忽略这一行歌词不予显示
- 时间标签是可以出现一行多时间的,比如:
- [01:10][01:20][01:50]hello
- 这应对解析为当播放到 [01:10]、[01:20]、[01:50]这三个时间点时,显示hello这行歌词
- 注意时间标签的内容可能为空格行或者没有内容,即:
- [01:10] {标签后面是一些空白符号}
- [01:10] {标签后面没有内容}
- 注意最后自己排一下序,歌词文件内的不一定是排好序的,应对自己按照时间重新排序。
翻译歌词
- LRC中表示翻译歌词,常见的有两种格式:
- 原文歌词有时间标签,翻译歌词没有时间标签:
- 原文歌词:[01:10]hello world
- 翻译歌词:你好 世界
- 原文歌词和翻译歌词的时间完全相同:
- 原文歌词:[01:10]hello world
- 翻译歌词:[01:10]你好 世界
- 显示时,当出现以上两种情况应对视为翻译歌词,播放到时,两句歌词同时亮起
- 重排序时主要考虑无时间戳的翻译歌词仍应跟随原文歌词,对于时间相同的歌词,应对保持他们原来的顺序,即使用稳定排序,如二路归并。
解码实现
- 首先将LRC歌词文本按行分割成一个字符串数组,注意分割符号应当使用 \n 和 \r,这是因为不同操作系统的换行符不同,有些是 \n,有些是 \r\n。
- 遍历字符串数组,将字符串行的左右空白符移除,如果移除完后,这个字符串是空字符串,则丢弃这一行。
- 开始逐行解码,可使用正则表达式匹配标识标签和时间标签:
- 标识标签:
- RegExp(r"^[\s\S][\s([^\d])\s\:([\s\S])][\s\S]$")
- 最基本的部分是 [([^\d])\:(\s\S)],用于匹配 [{key}:{value}]
- 然后添加一些空白符匹配,增加容错率即可
- 时间标签:
- 这需要分两次匹配,因为一行可能包含多个时间
- RegExp(r"^[\s\S]?(([[+-]?\d+\:[+-]?\d+([.:][+-]?\d+)?]\s)+)([\s\S]*)$"),先检查这一行内是否有时间标签,如果有则进行下一步。
- RegExp(r"([([+-]?\d+)\:([+-]?\d+)(.:)?]){1}?")可以将每一个时间提取出来。
- 上面这两个正则表达式支持的时间格式:
- ① [mm:ss.ff]
- ② [mm:ss]
- ③ [+-mm:+-ss.+-ff]
- 如果时间有出现负值,需要将整个时间置零。
- 计算毫秒部分ff的真实值:
- ① 如果ff部分是两位数,则 ff=毫秒/10,即真实毫秒值为 ff * 10,转成秒为 ff * 10 / 1000 = ff / 100
- ② 如果ff部分是三位数,则 ff=毫秒,转成秒为 ff / 1000
- 对于没有标签的行,应当作为无时间的翻译歌词处理,单行解析时作为-1时间的歌词返回即可,最终排序时作为翻译歌词判断依据。
- 解析完每一行歌词后,将歌词行使用稳定排序算法,如二路归并进行重排序,但在排序之前,需要将歌词时间重新赋值,这是因为部分翻译歌词没有时间,直接排序会导致错乱,因此需要给这些歌词赋值为上一行歌词的时间,让翻译歌词和原文歌词时间一致。然后进行重排序。
编码实现
- 编码要简单一些,主要是歌词时间需要规范化,时间不能出现负数,并遵循[mm:ss.ff]格式,其中ff是 真实毫秒值/10 得到的,因此它只有两位数。
- 注意ff要补足前导零,比如ff值只有7,需要补为 07,否则可能会被认为ff是 真实毫秒值/100。
- 分钟和秒数的前导零没那么重要,但最好也是不足2位则补足前导零。
注意事项
- LRC本质仍然是文本,自然就会有编码问题,一般是UTF-8,当然也有ANSI。
- 一般的歌曲文件,如flac、mp3等都是可以内嵌歌词的,也可以外置一个和歌曲文件同目录、同名、仅文件后缀为lrc的歌词文件。
You made some really good points there. I looked on the internet for more information about the issue and found most people will go along with your views on this site.
how to buy cheap clomid tablets: buy clomid – buying cheap clomid no prescription
how can i get prednisone: prednisoneraypharm – prednisone 20mg
prednisone 500 mg tablet: generic Prednisone – buy prednisone online without a script
I love reading through a post that will make men and women think. Also, thank you for allowing me to comment.
how can i get clomid for sale: clomid online – how to get cheap clomid price
Priligy tablets: dapoxetine price – buy dapoxetine online
can i order generic clomid now: clomid – clomid pill
order amoxicillin online no prescription: com pharm – generic for amoxicillin
prednisone pill 20 mg: prednisone – prednisone 40 mg tablet
generic for amoxicillin: cheap amoxil – amoxicillin canada price