音乐歌词同步

  • 666 views
Uploaded on

method for sync lyric and sound

method for sync lyric and sound

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
666
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 音乐歌词同步 邵彬 2010.08.07
  • 2. 已有的产品天天动听 摸手音乐
  • 3. LRC• LRC是英文lyric(歌词)的缩写,被用做歌 词文件的扩展名。以lrc为扩展名的歌词文 件可以在各类数码播放器中同步显示。LRC 歌词是一种包含着“*:*”形式的“标签(tag)”的、 基于纯文本的歌词专用格式。最早由郭祥 祥先生(Djohan)提出并在其程序中得到应用。
  • 4. 歌词文件例子[ti:青花瓷] [ar:周杰伦][al:我很忙][by:张琪][00:00.00]发送短信18到291199下载该歌曲到手机[00:01.11]青花瓷[03:36.49][00:21.39]素眉勾勒秋千话北风龙转丹 [00:26.08]屏层鸟绘的牡丹一如你梳妆[00:30.46]黯然腾香透过窗心事我了然[00:34.93]宣纸上皱边直尺各一半[00:39.49]油色渲染侍女图因为被失藏 [00:43.83]而你嫣然的一笑如含苞待放[00:48.30]你的美一缕飘散[00:50.77]去到我去不了的地方[02:23.97][00:55.77][03:01.92][02:25.63][00:56.90]天正在等烟雨[03:03.57][02:27.91][00:58.99]而我在等你[03:05.92][02:30.44][01:00.93]炊烟袅袅升起[03:07.76][02:32.25][01:03.49]隔江千万里[03:10.36][02:34.85][01:05.84]在平地书刻你房间上的飘影[03:14.67][02:38.73][01:09.87]就当我为遇见你伏笔
  • 5. 时间标签• 形式为“*mm:ss+”或“*mm:ss.ff+”(分钟:秒.百 分之一秒)后面跟着歌词。• 数字须为非负整数,比如"[12:34.5]"是有效 的,而"[0x0C:-34.5]"无效。它可以位于某行 歌词中的任意位置。一行歌词可以包含多 个时间标签(比如歌词中的迭句部分)。• 标签无须排序。
  • 6. 标识标签其格式为"[标识名:值]"。大小写等价。以下是定 义的标签.[ar:艺人名][ti:曲名][al:专辑名][by:编者(指编辑LRC歌词的人)][offset:时间补偿值]其单位是毫秒,正值表示整 体提前,负值相反。这是用于总体调整显示快 慢的。
  • 7. 解析歌词• 歌名• 艺术家• 专辑• 歌词制作人• 时间偏移量• 时间歌词列表 – {开始时间1,结束时间2,句子1} – {开始时间1,结束时间2,句子2} – … – {开始时间n,结束时间n,句子n}
  • 8. 歌词对象
  • 9. 开发标准• 无论是否在行首,行内凡具有[*:*]形式的都应认为是标签。• 凡是标签都不应显示。• 凡是标签,且被冒号分隔的两部分都为非负数,则应认为是时 间标签。• 因此,对于非标准形式(非[mm:ss]或[mm:ss.ff])的时间标签也 应能识别(如“*m:s+”)。• 应能正确识别连续的时间标签.如[00:01.555][01:03.234]歌词内 容。• 凡是标签,且非时间标签的,应认为是标识标签。• 标识名中大小写等价。• 为了向后兼容,应对未定义的新标签作忽略处理。另应对注释 标签([:])后的同一行内容作忽略处理。• 应允许一行中存在多个标签,并能正确处理。• 应能正确处理未排序的标签。
  • 10. 解析标识标签Regex: [(ti|ar|al|by|offset):([^]]*)]
  • 11. private void parseIdTags(String lyricStr) { Pattern pattern = Pattern.compile("[(ti|ar|al|by|offset):([^]]*)]", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(lyricStr); while (matcher.find()) { String tag = matcher.group(1); String value = matcher.group(2); if ("ti".equalsIgnoreCase(tag)) ti = value; else if ("ar".equalsIgnoreCase(tag)) ar = value; else if ("al".equalsIgnoreCase(tag)) al = value; else if ("by".equalsIgnoreCase(tag)) by = value; else if ("offset".equalsIgnoreCase(tag)) offset = Long.parseLong(value); }}
  • 12. 解析时间标签[03:01.92][02:25.63][00:56.90]天正在等烟雨[00:50.77]去到 我去不了的地方…Regex: ((?:[d{1,2}:d{1,2}(?:.d{1,3}){0,1}])+)([^[]*)一句时间歌词格式.也即包括时间戳标签以及该时间所对应 的歌词.表达式中的"+"号表示允许同时有多个连续的时 间戳标签存在(注意:多个时间标签之间不能有空格.否则 空格将也会被认为是歌词),这也正是符合上面提到的开 发标准中的第5条.那么,如何描述歌词呢? 一句歌词就是 从时间标签结束以后一直到下一个"["出现之前,就为一 句歌词的内容了.所以用一个非左括号表达式来匹配歌词 内容.
  • 13. • Regex: [((d{1,2}):(d{1,2})((?:.d{1,3}){0,1}))]
  • 14. private void parseTimeTags(String lyricStr) { Pattern timePattern = Pattern.compile("[((d{1,2}):(d{1,2})((?:.d{1,3}){0,1}))]"); Pattern timeTagPattern = Pattern.compile("((?:[d{1,2}:d{1,2}(?:.d{1,3}){0,1}])+)([^[]*)"); Matcher timeTagMatcher = timeTagPattern.matcher(lyricStr); while (timeTagMatcher.find()) { String time = timeTagMatcher.group(1); // 时间部分 String text = timeTagMatcher.group(2).trim(); // 歌词部分 Matcher timeMatcher = timePattern.matcher(time); while (timeMatcher.find()) { long minute = Integer.parseInt(timeMatcher.group(2)); long second = Integer.parseInt(timeMatcher.group(3)); long from = (minute * 60 + second) * 1000L; // 转换成毫秒数 if (timeMatcher.groupCount() == 4) // 如果还有百分之一秒部分,则加上 from += Integer.parseInt(timeMatcher.group(2)) * 10; if (offset != 0) // 处理偏移量 from += offset; Sentence sentence = new Sentence(timeMatcher.group(1), from, text); sentences.add(sentence); } } Collections.sort(sentences); // 按时间排序}
  • 15. 根据时间查找歌词Sentence getSentence(long time) { //binarySearch()}
  • 16. LyricViewpublic class LyricView extends View { private Lyric mLyric; private Sentence mSentence; public void update(long time) { mSentence = mLyric.getSentence(time); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.d(TAG, "in onDraw"); if (mLyricLoaded) { drawFocusedLine(canvas); drawOtherLines(canvas); } else { drawErrorMessage(canvas); } } private void drawFocusedLine(Canvas canvas) {...} private void drawOtherLines(Canvas canvas) {...}}
  • 17. TODO• 歌词文件的字符编码• 字幕平滑滚动,颜色渐变• 歌词长度超出了屏幕宽度
  • 18. Q&AThanks!