android lrc歌词
MP3文件本身只有音频信息,诸如标题、歌手、专辑等等信息统统是没有的。然而在windows资源管理器中查看mp3文件,或者用播放器时能看到这些信息,就是MP3标签的功劳了。MP3标签有多种格式,但是没有一项国际标准,也即是说没有统一的标准。不同类型的标签,其结构、大小、存储的信息都不同。
这是比较早期的一种标签,大部分软硬件,包括window都可以识别。它存储在mp3文件的最后,长度固定为128字节,以“TAG”标记开头。用UltraEdit等软件可以很容易看到这一点。这128自己又被分为固定大小的几段,分别存储歌手,专辑,评论,歌曲类型等最基本的信息。由于128字节的限制,ID3v1标签中没有歌词信息;更为致命的一个缺点是,ID3v1标签位于mp3文件的结尾处,大概当时的设计者没有预料到互联网技术的爆发,使得这种标签在流媒体大行其道的今天变得有些尴尬:你得等整个文件都缓冲完毕才能得到曲目信息。但是,简单和兼容仍是它最大的优点:)
这是ID3v1之后若干年提出的一项新的标签格式,有多个子版本,常见的是v2.3.0.曾经看到有人说ID3v2放在mp3文件的开头是因为ID3v1放在结尾而别无选择,这是不对的,下面我还要再说这个问题。很大程度上是因为上面提到的ID3v1放在结尾的缺点,放在开头的话可以在流媒体中发挥优势。(事实上,这个标签的设计者为了获得更大程度的方便,允许在文件结尾也放置ID3v2标签,但在ID3v1之前,以提高从结尾开始查找的速度)
ID3v2标签的改进不止如此。它极大地扩展了标签的容量,是变长的,最大可达大约256MB(它用28bit来存储标签大小,2^28)。这个数字大的惊人,可以预计,这个标签格式未来100年也不会过时 _所以存储歌词当然是小case了。不仅如此,ID3v2甚至同时支持同步歌词和不同步歌词,也就是前面提到的ID3v2 Synchronized Lyrics和 ID3v2 Unsynchronized Lyrics.关于这两种歌词我会在后面详细说明。
这是一种类似ID3v1的标签,其内容也很简单,但大小不完全固定,一般稍大于ID3v1,内容也丰富一些,比如有增益信息。但是仍然不包含歌词。其位置在mp3本身数据的后面,ID3v1标签和其他存放在末尾的标签之前。标签以"APETAGEX"开头。对于这个标签的认识完全来自千千静听,呵呵,不知道还有什么其他的播放器支持它。
mp3的歌词分为两种:外置的歌词文件和内嵌的歌词。外置的歌词主要指.lrc格式的文本文件。
这是大多数播放器支持的外挂歌词。对于电脑上的播放软件来说,他可以在歌曲和歌词文件之间建立一个映射(关联),这当然是很方便的。可是对于mp3播放机来说就没那么容易了,两者的文件名必须相同。(扩展名当然不同了:)好在千千给我们提供了自动命名的功能,甚至在你通过千千把mp3文件发送到可移动磁盘的时候,它还很贴心地问你要不要把关联的歌词文件也烤过去,多好的软件!
lrc格式其实就是纯文本,用notepad打开可以看到。示例
[02:09.30][04:02.22]On a dark desert highway, cool wind in my hair
它的结构以行为单位,行首是用中括号[]括起来的时间,后面是歌词内容。也许你要问了,为什么有两个时间标记呢?哈哈,lrc格式是很聪明的,对于某些重复的歌词,它就只写时间标签把内容省略了。同一行中不管有多少时间标签,其歌词内容都是那一个。还有一点要说明,虽然是一行一行出现的,但是这些行没有顺序的,也就是说那些时间标签不一定要按时间排序的。这样的目的也是为了编辑歌词的方便,比如你要插入一句歌词,不用再找它应该在什么位置。
这个歌词包含在ID3v2标签中,代号是SYLT。它也是由好多小段组成(按时间顺序排列),每个小段包含了时间标签和歌词内容,但具体结构和lrc那种不同了。按其标准严格地说,每个小段应该对以一个音节,这样把歌词分的很细很细,实际上也不用这么夸张。我的程序里面就是还按一句一句的来。
这个歌词也包含在ID3v2标签中,代号是USLT。从字面可以看出,非同步歌词,抑或叫异步歌词,其不包含时间信息,就是一下子把歌词全显示出来。这就显得不那么吸引人了,所以我的程序中放弃了它,仅仅写入了ID3v2 Synchronized Lyrics。顺便说一下,千千静听对这两种ID3歌词都不支持,而微软的Media Player支持。以前我也从没有见过WMP可以显示歌词的,其实它可以,而且能够编辑歌词。
这就是千千静听的那个内嵌歌词格式。和上面的两者不同,它是以歌词信息的形式单独出现的,并不依附于某个mp3标签。他的位置在APEv2标签(如果有的话)之后,ID3v1之前。开头标记是"LYRICSBEGIN",结束标记为"LYRICS200"。他的结构相对简单,基本上是照抄.lrc歌词的格式。
先从最基本的读取歌词文件开始:
Public class LrcHandle{
private List mWords= new ArrayList();
private List mTimeList= new ArrayList();
//处理歌词文件
public void readLRC(String path){
File file= new File(path);
try{
FileInputStream fileInputStream= new FileInputStream(file);
InputStreamReader inputStreamReader= new InputStreamReader(
fileInputStream,"utf-8");
BufferedReader bufferedReader= new BufferedReader(
inputStreamReader);
String s="";
while((s= bufferedReader.readLine())!= null){
addTimeToList(s);
if((s.indexOf("[ar:")!=-1)||(s.indexOf("[ti:")!=-1)
||(s.indexOf("[by:")!=-1)){
s= s.substring(s.indexOf(":")+ 1, s.indexOf("]"));
} else{
String ss= s.substring(s.indexOf("["), s.indexOf("]")+ 1);
s= s.replace(ss,"");
}
mWords.add(s);
}
bufferedReader.close();
inputStreamReader.close();
fileInputStream.close();
} catch(FileNotFoundException e){
e.printStackTrace();
mWords.add("没有歌词文件,赶紧去下载");
} catch(IOException e){
e.printStackTrace();
mWords.add("没有读取到歌词");
}
}
public List getWords(){
return mWords;
}
public List getTime(){
return mTimeList;
}
//分离出时间
private int timeHandler(String string){
string= string.replace(".",":");
String timeData[]= string.split(":");
//分离出分、秒并转换为整型
int minute= Integer.parseInt(timeData[0]);
int second= Integer.parseInt(timeData[1]);
int millisecond= Integer.parseInt(timeData[2]);
//计算上一行与下一行的时间转换为毫秒数
int currentTime=(minute* 60+ second)* 1000+ millisecond* 10;
return currentTime;
}
private void addTimeToList(String string){
Matcher matcher= Pattern.compile(
"[d{1,2}:d{1,2}([.:]d{1,2})?]").matcher(string);
if(matcher.find()){
String str= matcher.group();
mTimeList.add(new LrcHandle().timeHandler(str.substring(1,
str.length()- 1)));
}
}
}
一般歌词文件的格式大概如下:
[ar:艺人名]
[ti:曲名]
[al:专辑名]
[by:编者(指编辑LRC歌词的人)]
[offset:时间补偿值]其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
但也不一定,有时候并没有前面那些ar:等标识符,所以我们这里也提供了另一种解析方式。
歌词文件中的时间格式则比较统一:[00:00.50]等等,00:表示分钟,00.表示秒数,.50表示毫秒数,当然,我们最后是要将它们转化为毫秒数处理才比较方便。