HTML5 Audio 标签歌词同步的实现
HTML5草案里面其实有原生的字幕标签( Tag)的,但使用的是vtt格式的文件,非常规的字幕(.sub, .srt)或歌词文件(.lrc)。
用法如下(代码来自W3School):
但遗憾的是,使用起来还有不便之处。一是浏览器支持情况不太理想,连强大的FireFox(目前28.0)都还没支持,这你敢信!?。二是格式不兼容现有字幕或歌词文件,至少得需要个转换工具吧。所以在它流行起来之前,考虑另外的实现还是有必要的。
后台获取文件的io流,并且已文本问世返回
//通过io流读取文件,放的是绝对路径
//这个文件流里面放的是绝对路径
InputStream is = new FileInputStream("D:/YC_66Work1/mu/src/main/webapp/Lyric/韩红 _ 林俊杰 - 飞云之下.lrc");
byte[] b = new byte[is.available()];//把所有的数据读取到这个字节当中
//完整的读取一个文件
is.read(b);
//read:返回的是读取的文件大小
//最大不超过b.length,返回实际读取的字节个数
System.out.println(Arrays.toString(b));//读取的是字节数组
//把字节数组转成字符串
System.out.println(new String(b));
//关闭流
```java
歌词文件的格式
实现之前,当然得了解一下歌词文件的格式了。常规歌词文件的格式基本是一句一行,每行由两部分组成,前面是中括号括起来的时间轴,后面紧跟歌词,像下面这样:
[ti:飞云之下]
[ar:韩红/林俊杰]
[al:飞云之下]
[by:]
[offset:0]
[00:02.22]飞云之下 - 韩红/林俊杰 (JJ Lin)
[00:04.63]词:易家扬
[00:05.62]曲:林俊杰
[00:06.42]编曲:Terence Teo
[00:07.17]制作人:林俊杰
[00:07.86]人声录音:林俊杰/瞿然/Leonard Fong/李岳松/黄冠龙
[00:08.52]混音:周天澈/Richard Furch
[00:09.94]封面设计:方亮
[00:10.18]录音棚:HONG MUSIC STUDIO
[00:11.88]
这样挺有规律的,用正则可以很方便地将时间与歌词提取分离。
但凡事得多个心眼啊。事后发生的事情证明这句话有多正确。我在整理歌词时还发现了另外一种形式,像下面这样:
[ti:飞云之下]
[ar:韩红/林俊杰]
[al:飞云之下]
[by:]
[offset:0]
[00:02.22]飞云之下 - 韩红/林俊杰 (JJ Lin)
[00:04.63]词:易家扬
[00:05.62]曲:林俊杰
[00:06.42]编曲:Terence Teo
[00:07.17]制作人:林俊杰
[00:07.86]人声录音:林俊杰/瞿然/Leonard Fong/李岳松/黄冠龙
[00:08.52]混音:周天澈/Richard Furch
[00:09.94]封面设计:方亮
[00:10.18]录音棚:HONG MUSIC STUDIO
[00:11.88]
这种形式的歌词把歌词内容相同但时间不同的部分合并,节省了篇幅。
所以,现在知道的歌词其实有两种写法了,不过都还算规律,用正则可以搞定,只是对于第二种,处理时得将时间再次分割。
具体思路
首先将LRC文件读取为文本
用String.prototype.split('\n');将整个文本以换行符为单位分隔成一行一行的文本,保存到一个数组中
然后将开头部分不属于歌词的文本去掉,得到只有时间与歌词的干净文件
对于每一行,匹配出时间与文字,分别存入数组[time,text],然后将每行得到的这样的数组存入一个大的数组[[time,text],[time,text]…]
利用Audio标签的ontimeupdate事件,不断比较当然播放时间audio.currentTime与数组中每个元素中时间,如果当前时间大于某个歌词中的时间,则显示该歌词
文件读取
在具体处理歌词前,需要解决一个问题就是如何把歌词文件读取到代码中。对于文件读取,JavaScript中可以用FileReader,但它需要手动选择文件,也就是你得在页面放一个file类型的input或者实现文件拖拽操作,显示不可能让用户听歌的时候自己去找歌词然后上传,多麻烦。但JavaScript是没有办法操作本地文件的能力的,那就只能通过XMLHttpRequest(Ajax)发起一个到服务器的请求来获得文件了,这样一来,我们的程序就必需得运程在服务器上面。所以当你从GitHub下载了本文的源码后是无法直接运行的,请挂到本地服务器上观看效果。
下面展示了如何发起一个Ajax请求来获得歌词文件。
```javascript
在这里插入代码片
function getLyric(url) {
//建立一个XMLHttpRequest请求
var request = new XMLHttpRequest();
//配置, url为歌词地址,比如:'./content/songs/foo.lrc'
request.open('GET', url, true);
//因为我们需要的歌词是纯文本形式的,所以设置返回类型为文本