html5 audio歌词同步教程源码下载附Demo
日期:2018-03-10
来源:程序思维浏览:2888次
在网上看到音频和歌词可以同步,想必好多程序员都想知道是如何开发的,现在我就奉献出代码让大家使用。
歌词文件的格式
实现之前,当然得了解一下歌词文件的格式了。常规歌词文件的格式基本是一句一行,每行由两部分组成,前面是中括号括起来的时间轴,后面紧跟歌词,像下面这样:
[ar:文筱芮]
[by:airplay]
[00:00.00]那个
[00:03.00]作词:文筱芮 作曲:文筱芮
[00:06.00]编曲:于韵非
[00:09.00]制作人:胡海泉 秦天
[00:12.00]演唱:文筱芮
这样挺有规律的,用正则可以很方便地将时间与歌词提取分离。
具体思路
1、首先将LRC文件读取为文本
2、用String.prototype.split('\n');将整个文本以换行符为单位分隔成一行一行的文本,保存到一个数组中
3、然后将开头部分不属于歌词的文本去掉,得到只有时间与歌词的干净文件
4、对于每一行,匹配出时间与文字,分别存入数组[time,text],然后将每行得到的这样的数组存入一个大的数组[[time,text],[time,text]…]
5、利用Audio标签的ontimeupdate事件,不断比较当然播放时间audio.currentTime与数组中每个元素中时间,如果当前时间大于某个歌词中的时间,则显示该歌词。
一般歌词都是从服务器利用ajax读取出来,我这里就不放ajax的代码了,只做静态代码,自己添加ajax这样比较清晰。
//歌词对象
var lyricsobj = {
song: {
name: '',
lrcTimeArray: [],
lrcArray_line: []
}
};
//歌词
var lyricsText="[00:00.00]薛之谦 - 演员\n" +
"[00:04.00]词:薛之谦\n" +
"[00:07.00]曲:薛之谦\n" +
"[00:10.00]歌词编辑:果果\n" +
"[00:13.00]QQ:765708831\n" +
"[00:16.00]爱歌词网:www.22lrc.com\n" +
"[00:20.00]\n" +
"[00:21.44]简单点说话的方式简单点\n" +
"[00:30.59]递进的情绪请省略\n" +
"[00:33.78]你又不是个演员\n" +
"[00:36.39]别设计那些情节\n" +
"[00:39.57]\n" +
"[00:42.43]没意见我只想看看你怎么圆\n" +
"[00:51.80]你难过的太表面 像没天赋的演员\n" +
"[00:57.34]观众一眼能看见\n" +
"[01:00.68]\n" +
"[01:02.69]该配合你演出的我演视而不见\n" +
"[01:07.73]在逼一个最爱你的人即兴表演\n" +
"[01:13.00]什么时候我们开始收起了底线\n" +
"[01:18.11]顺应时代的改变看那些拙劣的表演\n" +
"[01:23.50]可你曾经那么爱我干嘛演出细节\n" +
"[01:28.76]我该变成什么样子才能延缓厌倦\n" +
"[01:33.94]原来当爱放下防备后的这些那些\n" +
"[01:39.66]才是考验\n" +
"[01:42.23]\n" +
"[01:45.25]没意见你想怎样我都随便\n" +
"[01:55.09]你演技也有限\n" +
"[01:57.57]又不用说感言\n" +
"[02:00.20]分开就平淡些\n" +
"[02:03.30]\n" +
"[02:05.61]该配合你演出的我演视而不见\n" +
"[02:10.64]别逼一个最爱你的人即兴表演\n" +
"[02:15.91]什么时候我们开始没有了底线\n" +
"[02:21.21]顺着别人的谎言被动就不显得可怜\n" +
"[02:26.46]可你曾经那么爱我干嘛演出细节\n" +
"[02:31.62]我该变成什么样子才能配合出演\n" +
"[02:36.77]原来当爱放下防备后的这些那些\n" +
"[02:42.06]都有个期限\n" +
"[02:44.99]\n" +
"[02:48.19]其实台下的观众就我一个\n" +
"[02:53.23]其实我也看出你有点不舍\n" +
"[02:58.52]场景也习惯我们来回拉扯\n" +
"[03:02.95]还计较着什么\n" +
"[03:07.87]\n" +
"[03:09.16]其实说分不开的也不见得\n" +
"[03:14.17]其实感情最怕的就是拖着\n" +
"[03:19.46]越演到重场戏越哭不出了\n" +
"[03:24.34]是否还值得\n" +
"[03:28.47]\n" +
"[03:29.35]该配合你演出的我尽力在表演\n" +
"[03:34.46]像情感节目里的嘉宾任人挑选\n" +
"[03:39.74]如果还能看出我有爱你的那面\n" +
"[03:44.99]请剪掉那些情节让我看上去体面\n" +
"[03:50.29]可你曾经那么爱我干嘛演出细节\n" +
"[03:55.46]不在意的样子是我最后的表演\n" +
"[04:01.32]是因为爱你我才选择表演 这种成全\n" +
"[04:09.39]\n";
window.onload = function(){
document.getElementById("currentSong").innerHTML = "薛之谦--演员";
getLyrics(); //默认先播放第一首歌
var audio = document.getElementById("audio");
audio.addEventListener('timeupdate', scroll_lyrics, true);
};
//从服务器获得歌词
function getLyrics(){
parseLyrics(""+lyricsText+"");
create_lyrics();
}
//对歌词进行解析
function parseLyrics(lyrics){
var lyrics_self = lyrics;
//获取歌词内容
var lrcArray = lyrics_self.split("\n");
lyricsobj.song.lrcArray_line.length = 0;
lyricsobj.song.lrcTimeArray.length = 0;
for (var i = 0; i < lrcArray.length; i++){
var lrcVal = lrcArray[i].replace(/[dd:dd.dd]/g,":");
var str = lrcVal.substr(1, 8).split(':');
var seconds = 0;
seconds = parseInt(str[0])*60 + parseInt(str[1]);
var lyrics_line = lrcVal.substring(10);
if (i == 0) {
lyricsobj.song.name = lyrics_line;
}
lyricsobj.song.lrcArray_line.push(lyrics_line);
lyricsobj.song.lrcTimeArray.push(seconds);
}
}
//让歌词显示在页面
function create_lyrics(){
var lyricsp = document.getElementById("lyricslist");
var text = "";
var timelist = lyricsobj.song.lrcTimeArray;
var lyricslist = lyricsobj.song.lrcArray_line;
for (var i = 0; i < timelist.length; i++){
text += '<p name="' + timelist[i] +'">'+lyricslist[i] + '</p>';
}
lyricsp.innerHTML = '';
lyricsp.innerHTML = text;
var audio = document.getElementById("audio");
audio.autoplay = true;
}
//没有歌词时显示
function create_noLyrics(){
var lyricsp = document.getElementById("lyricslist");
lyricsp.innerHTML = '';
lyricsp.innerHTML = '<h1>此歌曲暂无歌词!</h1>';
}
//让歌词滚动
function scroll_lyrics(){
var audio = document.getElementById("audio");
var timelist = lyricsobj.song.lrcTimeArray;
var lyricslist = lyricsobj.song.lrcArray_line;
var p = document.getElementsByTagName('p');
for (var i = 0; i < timelist.length; i++){
if (timelist[i] <= audio.currentTime + 0.5) {
if (i > 0) {
p[i - 1].style.color = 'white';
}
p[i].style.color = 'yellow';
var ptop =p[i].offsetTop; //获得当前歌词距离浏览器顶部的距离
var parent = p[i].parentNode.offsetTop; //获得滚动窗口距离浏览器的距离
var parentScroll = p[i].parentNode.scrollTop; //获得滚动窗口的滚动距离
if (ptop - parent - parentScroll > 220){ //比较当前歌词距离滚动窗口顶部的距离,大于220,就让窗口滚动20,根据自己的布局设置
p[i].parentNode.scrollTop = p[i].parentNode.scrollTop + 20;
}
else{
//控制让当前歌词显示在中间,根据自己的布局设置
p[i].parentNode.scrollTop = ptop - parent - 220;
}
}
}
}
好了就写到这里,css样式什么的没怎么弄,主要是让大家看懂代码就ok了。
歌词文件的格式
实现之前,当然得了解一下歌词文件的格式了。常规歌词文件的格式基本是一句一行,每行由两部分组成,前面是中括号括起来的时间轴,后面紧跟歌词,像下面这样:
[ar:文筱芮]
[by:airplay]
[00:00.00]那个
[00:03.00]作词:文筱芮 作曲:文筱芮
[00:06.00]编曲:于韵非
[00:09.00]制作人:胡海泉 秦天
[00:12.00]演唱:文筱芮
这样挺有规律的,用正则可以很方便地将时间与歌词提取分离。
具体思路
1、首先将LRC文件读取为文本
2、用String.prototype.split('\n');将整个文本以换行符为单位分隔成一行一行的文本,保存到一个数组中
3、然后将开头部分不属于歌词的文本去掉,得到只有时间与歌词的干净文件
4、对于每一行,匹配出时间与文字,分别存入数组[time,text],然后将每行得到的这样的数组存入一个大的数组[[time,text],[time,text]…]
5、利用Audio标签的ontimeupdate事件,不断比较当然播放时间audio.currentTime与数组中每个元素中时间,如果当前时间大于某个歌词中的时间,则显示该歌词。
一般歌词都是从服务器利用ajax读取出来,我这里就不放ajax的代码了,只做静态代码,自己添加ajax这样比较清晰。
//歌词对象
var lyricsobj = {
song: {
name: '',
lrcTimeArray: [],
lrcArray_line: []
}
};
//歌词
var lyricsText="[00:00.00]薛之谦 - 演员\n" +
"[00:04.00]词:薛之谦\n" +
"[00:07.00]曲:薛之谦\n" +
"[00:10.00]歌词编辑:果果\n" +
"[00:13.00]QQ:765708831\n" +
"[00:16.00]爱歌词网:www.22lrc.com\n" +
"[00:20.00]\n" +
"[00:21.44]简单点说话的方式简单点\n" +
"[00:30.59]递进的情绪请省略\n" +
"[00:33.78]你又不是个演员\n" +
"[00:36.39]别设计那些情节\n" +
"[00:39.57]\n" +
"[00:42.43]没意见我只想看看你怎么圆\n" +
"[00:51.80]你难过的太表面 像没天赋的演员\n" +
"[00:57.34]观众一眼能看见\n" +
"[01:00.68]\n" +
"[01:02.69]该配合你演出的我演视而不见\n" +
"[01:07.73]在逼一个最爱你的人即兴表演\n" +
"[01:13.00]什么时候我们开始收起了底线\n" +
"[01:18.11]顺应时代的改变看那些拙劣的表演\n" +
"[01:23.50]可你曾经那么爱我干嘛演出细节\n" +
"[01:28.76]我该变成什么样子才能延缓厌倦\n" +
"[01:33.94]原来当爱放下防备后的这些那些\n" +
"[01:39.66]才是考验\n" +
"[01:42.23]\n" +
"[01:45.25]没意见你想怎样我都随便\n" +
"[01:55.09]你演技也有限\n" +
"[01:57.57]又不用说感言\n" +
"[02:00.20]分开就平淡些\n" +
"[02:03.30]\n" +
"[02:05.61]该配合你演出的我演视而不见\n" +
"[02:10.64]别逼一个最爱你的人即兴表演\n" +
"[02:15.91]什么时候我们开始没有了底线\n" +
"[02:21.21]顺着别人的谎言被动就不显得可怜\n" +
"[02:26.46]可你曾经那么爱我干嘛演出细节\n" +
"[02:31.62]我该变成什么样子才能配合出演\n" +
"[02:36.77]原来当爱放下防备后的这些那些\n" +
"[02:42.06]都有个期限\n" +
"[02:44.99]\n" +
"[02:48.19]其实台下的观众就我一个\n" +
"[02:53.23]其实我也看出你有点不舍\n" +
"[02:58.52]场景也习惯我们来回拉扯\n" +
"[03:02.95]还计较着什么\n" +
"[03:07.87]\n" +
"[03:09.16]其实说分不开的也不见得\n" +
"[03:14.17]其实感情最怕的就是拖着\n" +
"[03:19.46]越演到重场戏越哭不出了\n" +
"[03:24.34]是否还值得\n" +
"[03:28.47]\n" +
"[03:29.35]该配合你演出的我尽力在表演\n" +
"[03:34.46]像情感节目里的嘉宾任人挑选\n" +
"[03:39.74]如果还能看出我有爱你的那面\n" +
"[03:44.99]请剪掉那些情节让我看上去体面\n" +
"[03:50.29]可你曾经那么爱我干嘛演出细节\n" +
"[03:55.46]不在意的样子是我最后的表演\n" +
"[04:01.32]是因为爱你我才选择表演 这种成全\n" +
"[04:09.39]\n";
window.onload = function(){
document.getElementById("currentSong").innerHTML = "薛之谦--演员";
getLyrics(); //默认先播放第一首歌
var audio = document.getElementById("audio");
audio.addEventListener('timeupdate', scroll_lyrics, true);
};
//从服务器获得歌词
function getLyrics(){
parseLyrics(""+lyricsText+"");
create_lyrics();
}
//对歌词进行解析
function parseLyrics(lyrics){
var lyrics_self = lyrics;
//获取歌词内容
var lrcArray = lyrics_self.split("\n");
lyricsobj.song.lrcArray_line.length = 0;
lyricsobj.song.lrcTimeArray.length = 0;
for (var i = 0; i < lrcArray.length; i++){
var lrcVal = lrcArray[i].replace(/[dd:dd.dd]/g,":");
var str = lrcVal.substr(1, 8).split(':');
var seconds = 0;
seconds = parseInt(str[0])*60 + parseInt(str[1]);
var lyrics_line = lrcVal.substring(10);
if (i == 0) {
lyricsobj.song.name = lyrics_line;
}
lyricsobj.song.lrcArray_line.push(lyrics_line);
lyricsobj.song.lrcTimeArray.push(seconds);
}
}
//让歌词显示在页面
function create_lyrics(){
var lyricsp = document.getElementById("lyricslist");
var text = "";
var timelist = lyricsobj.song.lrcTimeArray;
var lyricslist = lyricsobj.song.lrcArray_line;
for (var i = 0; i < timelist.length; i++){
text += '<p name="' + timelist[i] +'">'+lyricslist[i] + '</p>';
}
lyricsp.innerHTML = '';
lyricsp.innerHTML = text;
var audio = document.getElementById("audio");
audio.autoplay = true;
}
//没有歌词时显示
function create_noLyrics(){
var lyricsp = document.getElementById("lyricslist");
lyricsp.innerHTML = '';
lyricsp.innerHTML = '<h1>此歌曲暂无歌词!</h1>';
}
//让歌词滚动
function scroll_lyrics(){
var audio = document.getElementById("audio");
var timelist = lyricsobj.song.lrcTimeArray;
var lyricslist = lyricsobj.song.lrcArray_line;
var p = document.getElementsByTagName('p');
for (var i = 0; i < timelist.length; i++){
if (timelist[i] <= audio.currentTime + 0.5) {
if (i > 0) {
p[i - 1].style.color = 'white';
}
p[i].style.color = 'yellow';
var ptop =p[i].offsetTop; //获得当前歌词距离浏览器顶部的距离
var parent = p[i].parentNode.offsetTop; //获得滚动窗口距离浏览器的距离
var parentScroll = p[i].parentNode.scrollTop; //获得滚动窗口的滚动距离
if (ptop - parent - parentScroll > 220){ //比较当前歌词距离滚动窗口顶部的距离,大于220,就让窗口滚动20,根据自己的布局设置
p[i].parentNode.scrollTop = p[i].parentNode.scrollTop + 20;
}
else{
//控制让当前歌词显示在中间,根据自己的布局设置
p[i].parentNode.scrollTop = ptop - parent - 220;
}
}
}
}
好了就写到这里,css样式什么的没怎么弄,主要是让大家看懂代码就ok了。
精品好课