Android 实现歌词同步

歌词同步的原理其实很简单:
  歌词显示是一个线程, 音乐播放时一个线程,通过播放时间将歌词显示进度与播放进度同步起来。
  网络标准的歌词格式是LRC. 我们看下一个LRC文档,其格式就一目了然了.
  [ti:爱]
  [ar:小虎队]
  [al:华纳国语情浓13首]
  [by:爱上你了音乐网]
  [02:08.00][00:38.00]把你的心、我的心串一串
  [02:11.00][00:41.00]串一株幸运草、串一?同心圆
  [02:16.00][00:46.00]让所有期待未?的呼唤
  [02:19.00][00:49.00]趁青春做?伴
  [03:16.00][02:24.00][00:53.00]?让年轻越长大越孤单
  [03:19.00][02:27.00][00:56.00]把我的幸运草种在你的梦田
  [03:23.00][02:31.00][01:01.00]让地球随我?的同心圆
  ….
  LRC 格式为 [歌词显示起始时间][歌词显示结束时间]歌词内容。
  了解歌词同步原理,我们可以想到要做如下工作:
  1. LRC 解析
  2. LRC 歌词显示
  3. 歌词与播放音乐同步
  4. 歌词的获取
  一 LRC解析
  这边我推荐YOYOPlayer 音乐播放开源项目. 源代码已经非常好的支持了LRC解析. 我拿过来就用了.
  过程大概如此: 把LRC文件读到内存里面,用 sentence数据结构存放. Sentence里面有 Fromtime, Totime, content三个成员变量。显示的时候需要这些数据。
  二. LRC歌词显示
  歌词的绘制通过重写 OnDraw方法.
  绘制的代码贴出来:
  long t = tempTime;
  int index = getNowSentenceIndex(t);
  if (index == -1) {
  return;
  }
  Sentence now = list.get(index);
  float f = (t - now.getFromTime()) * 1.0f
  / (now.getToTime() - now.getFromTime());
  if (f > 0.98f) {
  f = 0.98f;
  }
  Shader shader = new LinearGradient(0, 0,
  now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,
  Color.BLUE }, new float[] { f, f + 0.01f },
  TileMode.CLAMP);
  mTxtPaint.setShader(shader);
  canvas.drawText(now.getContent(), 0, 20, mTxtPaint);
上面的代码很简单,关键一个函数是getNowSentenceIndex(t). 通过播放时间来获得歌词的索引. 我们看下getNowSentenceIndex()如何实现.
  /**
  * 得到当前正在播放的那一句的下标 不可能找不到,因为最开头要加一句 自己的句子 ,所以加了以后就不可能找不到了
  *
  * @return 下标
  */
  private int getNowSentenceIndex(long t) {
  for (int i = 0; i < list.size(); i++) {
  if (list.get(i).isInTime(t)) {
  return i;
  }
  }
  // throw new RuntimeException("竟然出现了找不到的情况!");
  return -1;
  }
  还有一个歌词渐变的效果,其关键代码在与对画笔的设置,如下.
  Shader shader = new LinearGradient(0, 0,
  now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,
  Color.BLUE }, new float[] { f, f + 0.01f },
  TileMode.CLAMP);
  mTxtPaint.setShader(shader);
  三. 歌词与播放音乐同步
  音乐播放的时候,同时启动歌词显示线程. 将音乐播放的时间设置到歌词View的成员变量中, 以达到同步的目的。
  private class MyHandler extends Handler {
  @Override
  public void handleMessage(Message msg) {
  // Log.v("#################hahah", "" + mp.getCurrentPosition());
  // 重画
  lrcView.mLyric.setTime(mp.getCurrentPosition());
  lrcView.invalidate();
  }
  }
  四. 歌词的获取
  歌词的获取是通过百度搜索出来的. 具体代码如下,很好看懂,关键代码如下:
  GetMethod get = new GetMethod("http://www.baidu.com/s?wd=" + URLEncoder.encode("filetype:lrc " + key, "GBK"));
  get.addRequestHeader("Host", "www.baidu.com");
  get.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11");
  get.addRequestHeader("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
  get.addRequestHeader("Accept-Language", "zh-cn,zh;q=0.5");
  get.addRequestHeader("Keep-Alive", "300");
  get.addRequestHeader("Referer", "http://www.baidu.com/");
  get.addRequestHeader("Connection", "keep-alive");
  int i = http.executeMethod(get);
  返回的结果是歌词的xml格式转化字符串就可以了,这个太简单了,懒得说了.

更多相关文章

  1. Android(安卓)MVP 模式:简单易懂的介绍方式
  2. android TextView显示文字和图片
  3. Android使用Google Breakpad进行崩溃日志管理
  4. 阿里路由框架ARouter简介
  5. Android中ScrollView布局初始化显示的时候使页面置顶
  6. android的ITC
  7. 【Android开发】构建第一个APP
  8. Handler、HandlerThread理解
  9. Android(安卓)中ListView setOnItemClickListener点击无效原因分

随机推荐

  1. 拦截短信,不让系统发通知
  2. android linux 基础知识总结
  3. 《H5 App开发》判断当前环境是Android还
  4. Android中的Menu
  5. Android(安卓)- Intent - 传递数据
  6. Android(安卓)获取设备信息
  7. Android(安卓)2.1 源码结构分析
  8. 虚拟键盘弹出时挡住EditText的解决方案
  9. Android剪切图片
  10. Android之使用ContentResolver对通信录中