Your SlideShare is downloading. ×
0
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
音乐歌词同步
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

音乐歌词同步

684

Published on

method for sync lyric and sound

method for sync lyric and sound

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
684
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
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!

×