Lrc文件与音乐的同步显示
来源:互联网 发布:linux怎么加入环境变量 编辑:程序博客网 时间:2024/05/24 04:13
(第一个文档 有问题处请大家多多包含)
在Musicplayer中,如何使歌词与歌曲同步显示?
这其实很简单。
我们可以下载一个lrc歌词文件,打开该文件我们可以发现其实lrc文件中格式是很规范的
lrc文件如下:
如何使歌词与歌曲同步显示,关键点就在于lrc文件显示的格式。上图我们发现lrc歌词文件是分两部分组成 左边是歌词播放的时间,右边是歌词内容。
我们可以创建一个集合来存放该信息,该集合的存放数据类型为lrc内容的实体类且该类中属性分为歌词时间与歌词内容。同时在使用MediaPlayer类来播放音频文件时,有一个getCurrentPosition()方法获取当前播放时间。
因为通过该方法获取的时间是毫秒单位,所以我们在截取lrc文件中时间的时候先转换为毫秒,在与当前时间对比就可以知道当前时间所对应的歌词内容了。话不多说,
代码如下:
首先我们需要一个Music工具类用来存放歌词信息的实体类 与 读取歌词方法类.代码如下:
MusicUtils.java:
package com.example.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class MusicUtils {
public static class MusicInfos {
private String LrcContent;
private int LrcTime;
public String getLrcContent() {
return LrcContent;
}
public void setLrcContent(String lrcContent) {
LrcContent = lrcContent;
}
public int getLrcTime() {
return LrcTime;
}
public void setLrcTime(int lrcTime) {
LrcTime = lrcTime;
}
}
public static class ReadLrc {
MusicInfos musicInfos = null;
ArrayList<MusicInfos> LrcList = null;
public ReadLrc() {
musicInfos = new MusicInfos();
LrcList = new ArrayList<MusicUtils.MusicInfos>();
}
public void Read(String file) throws IOException {
File f = new File(file);
FileInputStream fis = new FileInputStream(f);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String s = null;
StringBuffer sb = null;
while ((s = br.readLine()) != null) {
s = s.replace("[", "");
s = s.replace("]", "@");
String lrc_data[] = s.split("@");
if (lrc_data.length > 1) {
String lrcContent = lrc_data[1];
String lrcTime = lrc_data[0];
musicInfos.setLrcContent(lrcContent);
int time = LrcTime(lrcTime);
musicInfos.setLrcTime(time);
LrcList.add(musicInfos);
musicInfos = new MusicInfos();
}
}
br.close();
isr.close();
}
public int LrcTime(String lrcTime) {
lrcTime = lrcTime.replace(":", ".");
lrcTime = lrcTime.replace(".", "@");
String[] lrc_time = lrcTime.split("@");
String min = lrc_time[0];
String seconds = lrc_time[1];
String perseconds = lrc_time[2];
int currentTime = ((Integer.parseInt(min) * 60 + Integer
.parseInt(seconds)) * 1000 + Integer.parseInt(perseconds) * 10);
return currentTime;
}
public ArrayList<MusicInfos> getLrcList() {
return LrcList;
}
}
}
//在MusicUtils.class中我们创建两个静态内部类。在ReadLrc.class中使用Read方法来读取lrc文件。并且通过replace把lrc文件中"[" 换为空字符 把“]”换为“@”。
目的是为了通过@截取时间与歌词内容两部分 (你也可以不用替换"]"根据个人喜欢) 再把截取的内容放入 集合中。这里我们通过LrcTime()方法来把时间单位转换
为毫秒。
同时我们需要自定义视图空间来动态显示歌词内容,代码如下:
LrcView:
package com.example.test;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
import com.example.test.MusicUtils.MusicInfos;
public class LrcView extends TextView {
private Paint CurrentPaint;
private ArrayList<MusicInfos> LrcContentList = new ArrayList<MusicUtils.MusicInfos>();
private Paint NotCurrentPaint;
private int index;
private float width;
private float heigth;
private float textSize = 20;
private float textHeight = 30;
private String tag = "tag";
public LrcView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public LrcView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LrcView(Context context) {
super(context);
init();
}
private void init() {
setFocusable(true);
CurrentPaint = new Paint();
CurrentPaint.setAntiAlias(true); // 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
CurrentPaint.setTextAlign(Paint.Align.CENTER); // 设置绘制文字的对齐方向
NotCurrentPaint = new Paint();
NotCurrentPaint.setAntiAlias(true);
NotCurrentPaint.setTextAlign(Paint.Align.CENTER);
}
public void setLrcContent(ArrayList<MusicInfos> LrcContentList) {
this.LrcContentList = LrcContentList;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas == null) {
return;
}
CurrentPaint.setColor(Color.YELLOW);
CurrentPaint.setTextSize(textSize);
CurrentPaint.setTypeface(Typeface.SERIF); // 设置字体(衬线)
NotCurrentPaint.setColor(Color.BLUE);
NotCurrentPaint.setTextSize(textSize);
NotCurrentPaint.setTypeface(Typeface.SERIF);
try {
canvas.drawText(LrcContentList.get(index).getLrcContent(),
width / 2, heigth / 2, CurrentPaint);
float mheight = heigth / 2;
for (int i = index - 1; i >= 0; i--) {
mheight = mheight - textHeight;
canvas.drawText(LrcContentList.get(i).getLrcContent(),
width / 2, mheight, NotCurrentPaint);
}
mheight = heigth / 2;
for (int i = index + 1; i < LrcContentList.size(); i++) {
mheight = mheight + textHeight;
canvas.drawText(LrcContentList.get(i).getLrcContent(),
width / 2, mheight, NotCurrentPaint);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.heigth = h;
this.width = w;
}
public void setIndex(int Index) {
this.index = Index;
}
}
//通过setIndex()方法来从外部获取索引位置。使在onDraw()方法中通过index来画图(歌词)
最后我们需要一个MainActivity来实现这些方法。
MainActivity.class:
package com.example.test;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.example.test.MusicUtils.MusicInfos;
import com.example.test.MusicUtils.ReadLrc;
public class MainActivity extends Activity {
MediaPlayer mediaPlayer = null;
ReadLrc readLrc = null;
Button btnPlay = null;
LrcView tvLrc = null;
ArrayList<MusicInfos> Lrcinfos = new ArrayList<MusicUtils.MusicInfos>();
private int index = 0;
private int currentTime = 0;
private int countTime = 0;
private String tag = "tag";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
try {
readLrc.Read("sdcard/yaoyuandeta.lrc");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Lrcinfos = readLrc.getLrcList();
tvLrc.setLrcContent(Lrcinfos);
mHandler.post(runnable);
btnPlay.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
play();
}
});
}
public void play() {
try {
Log.i(tag, "play1");
mediaPlayer.reset();
Log.i(tag, "play2");
mediaPlayer.setDataSource("sdcard/yaoyuandeta.mp3");
Log.i(tag, "play3");
mediaPlayer.prepare();
Log.i(tag, "play4");
mediaPlayer.start();
mediaPlayer.setLooping(true);
} catch (IllegalStateException e) {
Log.i(tag, "error1");
e.printStackTrace();
} catch (IllegalArgumentException e) {
Log.i(tag, "error2");
e.printStackTrace();
} catch (SecurityException e) {
Log.i(tag, "error3");
e.printStackTrace();
} catch (IOException e) {
Log.i(tag, "error4");
e.printStackTrace();
}
}
Handler mHandler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
tvLrc.setIndex(Index());
tvLrc.invalidate();
tvLrc.postDelayed(runnable, 100);
}
};
public int Index() {
if (mediaPlayer.isPlaying()) {
currentTime = mediaPlayer.getCurrentPosition();
countTime = mediaPlayer.getDuration();
}
if (currentTime < countTime) {
for (int i = 0; i < Lrcinfos.size(); i++) {
if (i < Lrcinfos.size() - 1) {
if (currentTime > Lrcinfos.get(i).getLrcTime() && i == 0) {
index = i;
}
if (currentTime > Lrcinfos.get(i).getLrcTime()
&& currentTime <= Lrcinfos.get(i + 1).getLrcTime()) {
index = i;
}
}
if (currentTime == Lrcinfos.size() - 1
&& currentTime < Lrcinfos.get(i).getLrcTime()) {
index = i;
}
}
}
return index;
}
private void init() {
mediaPlayer = new MediaPlayer();
readLrc = new ReadLrc();
btnPlay = (Button) findViewById(R.id.btnStart);
tvLrc = (LrcView) findViewById(R.id.tv);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i(tag, "destroy");
mediaPlayer.stop();
}
}
//这里我们不进行遍历sdcard或者通过MediaStore来获取音频文件信息,直接通过路径来获取一个示例。我们通过线程动态的向setIndex()方法中传入index值,来实时同步歌词与音乐。
xml文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btnStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="播放音乐" />
<com.example.test.LrcView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.example.test.LrcView>
</LinearLayout>
- Lrc文件与音乐的同步显示
- android 音乐播放器-------歌词同步 lrc
- android 在线获取音乐歌词lrc文件
- android 在线获取音乐歌词lrc文件
- 歌词同步的实现(lrc)
- 音乐播放器功能的实现,歌词lrc显示,播放过程中来电
- 网页中LRC歌词同步显示
- MP3 lrc文件的解析
- Android开发----lrc歌词的同步展示
- android MusicPlayer 音乐播放器 Lrc歌词控件的实现
- lrc歌词解析(正则表达式)与歌词卡拉ok显示的思路
- 关于音乐播放器中歌词同步显示的实现
- 《菊花台》的歌词LRC文件
- c# 操作Lrc歌词文件 的类
- 牛刀小试--删除多余的lrc文件
- LRC 歌词同步
- Android音乐播放器读取歌词.lrc文件乱码问题解决方法
- 本地MediaPlayer音乐播放器与歌词同步的实现
- vb.net Excel文件转二进制文件,及反转
- package manager service是怎样选择armeabi/armeabi-v7a中的库文件的?
- Android 调试助手ATools [WIFI BT NFC GPS USB BLE 蓝牙串口 iBeacon ......]
- 有关NSUserdefaults使用时的问题记录
- 获得项目绝对路径
- Lrc文件与音乐的同步显示
- POJ 1651 Multiplication Puzzle
- 数据库中的文本如果有标签应该在往网页上显示前先把标签和样式都过滤掉
- 【win10应用】安装windows SDK10 安装失败:Windows 10 SDK 10.0.10069 : 安装程序失败。哈希数值不正确。错误代码: -2146889721
- block 用法详解
- 开源项目分析之UIL(续)
- C/C++编译错误(原因&解决)
- android listview ScrollView
- Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机