马黑黑 发表于 2022-2-16 14:08

audio播放器对lrc歌词同步的实现思路

本帖最后由 马黑黑 于 2022-2-16 22:41 编辑

这里假设我们已经把lrc歌词变成了我们的JS数组——

lrc歌词样式:

动身跋涉千里
追逐沿途的风景

经手动批量处理(Emeditor做这个事情再简单不过了),得出下面的JS二维数组样式:

["00:21.55","动身跋涉千里"],
["00:25.49","追逐沿途的风景"],

当然,以上的做法可以通过JS来完成,这个事将来再考虑,现在先来完成核心功能的部分。

先组织好lrc歌词数组(二维):

var lrcAr=[
    ["00:00.31","刘艺雯 - 听闻远方有你"],
    ["00:01.98","作词:刘钧"],
    // ......
    ["03:52.52","只为你的温柔"]
];

这个数组里,每一个子项的第一个数组对应lrc歌词中的时间信息,我们需要将其转换成秒数,因为audio的当前播放时间以秒数呈现。我们的思路是,通过监听audio的当前播放时间,拿去与lrc歌词的时间进行比较,只要当前的播放时间大于lrc的某个时间节点,就显示它所对应的歌词,即JS数组中各子数组第二个数组元素。这样,lrc时间消息我们只需读取到 xx:yy 便可,也就是分和秒,毫秒忽略。下面就是我们定义的将lrc时间信息转换为秒数的函数:

//lrc时间信息转为秒
function toSec(lrcTime) {
      let tmpAr = lrcTime.split(':');
      lrcTime = tmpAr * 60 + parseInt(tmpAr);
      return lrcTime;
}

这个函数需要一个事件参数 lrcTime,它就是 xx:yy 格式的lrc事件消息。我们通过符号 : 来拆分字符串,得到左边的分钟信息,它乘以60变成了秒数,右边的就是秒数,因为带有小数点,我们用 parseInt 内置函数将其强制变换为整数,然后将二者加起来并返回给调用者。

接下来调用上面这个函数将JS数组改装一下:

//处理lrc歌词数组:时间转换成秒
for(j=0; j<lrcAr.length; j++){
      lrcAr = toSec(lrcAr);
      //console.log(lrcAr, "-", lrcAr);//测试
}


这就差不多了,现在只缺少一个监听事件:

//audio监听事件
audio.ontimeupdate = function() {
      let tt = audio.currentTime;
      for(j=0; j<lrcAr.length; j++){
                if(tt > lrcAr) console.log(tt, "-", lrcAr, "-", lrcAr);
      }
}

监听事件(ontimeupdate)的匿名函数里,我们令 tt 获取 audio 的当前播放时间,将之放置在一个for循环里不断地与lrc歌词数组各子项的第一个数组比较,大于哪一个就在控制台中显示对应的歌词和其他信息。

下面是完整代码,我们的演示需要一个舞台和道具——audio和div标签:

<div id="lrcDiv" style="padding:10px; width:300px;height:30px;">歌词显示</div>
<audio id="myplayer" src="http://www.kumeiwp.com/sub/filestores/2022/01/31/12321664f29ec95b02bfbf62ddab082a.mp3" controls="controls" loop="loop"></audio>

<script language="javascript">

var lrcAr=[
["00:00.31","刘艺雯 - 听闻远方有你"],
["00:01.98","作词:刘钧"],
["00:03.04","作曲:刘钧"],
["00:04.18","编曲:刘钧"],
["00:17.67","听闻远方有你"],
["00:21.55","动身跋涉千里"],
["00:25.49","追逐沿途的风景"],
["00:29.13","还带着你的呼吸"],
["00:33.30","真的难以忘记"],
["00:37.17","关于你的消息"],
["00:41.11","陪你走过南北东西"],
["00:44.83","相随永无别离"],
["00:49.00","可不可以爱你"],
["00:52.71","我从来不曾歇息"],
["00:56.65","像风走了万里"],
["00:59.60","不问归期"],
["01:04.37","我吹过你吹过的风"],
["01:08.17","这算不算相拥"],
["01:12.18","我走过你走过的路"],
["01:15.97","这算不算相逢"],
["01:19.91","我还是那么喜欢你"],
["01:23.85","想与你到白头"],
["01:27.72","我还是一样喜欢你"],
["01:31.66","只为你的温柔"],
["02:07.40","听闻远方有你"],
["02:11.20","动身跋涉千里"],
["02:14.99","追逐沿途的风景"],
["02:18.70","还带着你的呼吸"],
["02:22.88","真的难以忘记"],
["02:26.82","关于你的消息"],
["02:30.77","陪你走过南北东西"],
["02:34.33","相随永无别离"],
["02:38.50","可不可以爱你"],
["02:42.37","我从来不曾歇息"],
["02:46.16","像风走了万里不问归期"],
["02:53.83","我吹过你吹过的风"],
["02:57.77","这算不算相拥"],
["03:01.71","我走过你走过的路"],
["03:05.57","这算不算相逢"],
["03:09.44","我还是那么喜欢你"],
["03:13.38","想与你到白头"],
["03:17.40","我还是一样喜欢你"],
["03:21.27","只为你的温柔"],
["03:25.30","我吹过你吹过的风"],
["03:29.01","这算不算相拥"],
["03:32.96","我走过你走过的路"],
["03:36.90","这算不算相逢"],
["03:40.76","我还是那么喜欢你"],
["03:44.70","想与你到白头"],
["03:48.49","我还是一样喜欢你"],
["03:52.52","只为你的温柔"]
];

var myaud = document.getElementById('myplayer'); //播放器标识
var lrcDiv = document.getElementById('lrcDiv'); //歌词显示div标识

//处理lrc歌词数组:时间转换成秒
for(j=0; j<lrcAr.length; j++){
      lrcAr = toSec(lrcAr);
}

//lrc时间信息转为秒
function toSec(lrcTime) {
      let tmpAr = lrcTime.split(':');
      lrcTime = tmpAr * 60 + parseInt(tmpAr);
      return lrcTime;
}

//同步显示歌词
myaud.ontimeupdate = function() {
      let tt = myaud.currentTime;
      for(j=0; j<lrcAr.length; j++){
                if(tt > lrcAr) lrcDiv.innerHTML = lrcAr;
      }
}

</script>



马黑黑 发表于 2022-2-16 14:08

本帖最后由 马黑黑 于 2022-2-16 14:17 编辑 <br /><br /><div id="lrcDiv" style="padding:10px; width:300px;height:30px;">歌词显示</div>
<audio id="myplayer" src="http://www.kumeiwp.com/sub/filestores/2022/01/31/12321664f29ec95b02bfbf62ddab082a.mp3" controls="controls" loop="loop"></audio>

<script language="javascript">

var lrcAr=[
["00:00.31","刘艺雯 - 听闻远方有你"],
["00:01.98","作词:刘钧"],
["00:03.04","作曲:刘钧"],
["00:04.18","编曲:刘钧"],
["00:17.67","听闻远方有你"],
["00:21.55","动身跋涉千里"],
["00:25.49","追逐沿途的风景"],
["00:29.13","还带着你的呼吸"],
["00:33.30","真的难以忘记"],
["00:37.17","关于你的消息"],
["00:41.11","陪你走过南北东西"],
["00:44.83","相随永无别离"],
["00:49.00","可不可以爱你"],
["00:52.71","我从来不曾歇息"],
["00:56.65","像风走了万里"],
["00:59.60","不问归期"],
["01:04.37","我吹过你吹过的风"],
["01:08.17","这算不算相拥"],
["01:12.18","我走过你走过的路"],
["01:15.97","这算不算相逢"],
["01:19.91","我还是那么喜欢你"],
["01:23.85","想与你到白头"],
["01:27.72","我还是一样喜欢你"],
["01:31.66","只为你的温柔"],
["02:07.40","听闻远方有你"],
["02:11.20","动身跋涉千里"],
["02:14.99","追逐沿途的风景"],
["02:18.70","还带着你的呼吸"],
["02:22.88","真的难以忘记"],
["02:26.82","关于你的消息"],
["02:30.77","陪你走过南北东西"],
["02:34.33","相随永无别离"],
["02:38.50","可不可以爱你"],
["02:42.37","我从来不曾歇息"],
["02:46.16","像风走了万里不问归期"],
["02:53.83","我吹过你吹过的风"],
["02:57.77","这算不算相拥"],
["03:01.71","我走过你走过的路"],
["03:05.57","这算不算相逢"],
["03:09.44","我还是那么喜欢你"],
["03:13.38","想与你到白头"],
["03:17.40","我还是一样喜欢你"],
["03:21.27","只为你的温柔"],
["03:25.30","我吹过你吹过的风"],
["03:29.01","这算不算相拥"],
["03:32.96","我走过你走过的路"],
["03:36.90","这算不算相逢"],
["03:40.76","我还是那么喜欢你"],
["03:44.70","想与你到白头"],
["03:48.49","我还是一样喜欢你"],
["03:52.52","只为你的温柔"]
];

var myaud = document.getElementById('myplayer'); //播放器标识
var lrcDiv = document.getElementById('lrcDiv'); //歌词显示div标识

//处理lrc歌词数组:时间转换成秒
for(j=0; j<lrcAr.length; j++){
        lrcAr = toSec(lrcAr);
}

//lrc时间信息转为秒
function toSec(lrcTime) {
        let tmpAr = lrcTime.split(':');
        lrcTime = tmpAr * 60 + parseInt(tmpAr);
        return lrcTime;
}

//同步显示歌词
myaud.ontimeupdate = function() {
        let tt = myaud.currentTime;
        for(j=0; j<lrcAr.length; j++){
                if(tt > lrcAr) lrcDiv.innerHTML = lrcAr;
        }
}

</script>

红影 发表于 2022-2-16 14:43

外加提供的秒数,能跟音乐播放的秒数对应起来,这个功能{:4_199:}

马黑黑 发表于 2022-2-16 14:43

本帖最后由 马黑黑 于 2022-2-16 14:48 编辑

附:用Emeditor将lrc歌词转换为JS数组的操作方法——

步骤一:将lrc歌词粘贴到Emeditor,把与歌词无关的头部消息去掉,仅保留有“时间+歌词”的内容;

步骤二:按 Ctrl + H 调出替换窗口,然后(所查找和替换的都是小角符号)——

① 确保不启用正则表达式,在查找处输入小角 [ ,在替换处输入一个小角 [ 和一个小角双引号 " ,即 [" ,点击“全部替换”;

② 在查找处输入小角中括号反(这里我输入老被吃掉) ,替换处输入"," ,点“全部替换”

③ 启用正则表达式,即点击“正则表达式”,在查找处输入 $ ,在替换处输入 "], ,点“全部替换”。

至此,文档变成这样的样式:

["00:00.31","刘艺雯 - 听闻远方有你"],
["00:01.98","作词:刘钧"],
["00:03.04","作曲:刘钧"],
["00:04.18","编曲:刘钧"],
["00:17.67","听闻远方有你"],


④ 我们加上JS数组的头尾,并把最后一行末尾处的逗号去掉即可大功告成:

var lrcAr=[
["00:00.31","刘艺雯 - 听闻远方有你"],
["00:01.98","作词:刘钧"],
["00:03.04","作曲:刘钧"],
["00:04.18","编曲:刘钧"],
["00:17.67","听闻远方有你"]

];

马黑黑 发表于 2022-2-16 14:44

红影 发表于 2022-2-16 14:43
外加提供的秒数,能跟音乐播放的秒数对应起来,这个功能

手动制作JS歌词数组的方法看地板楼

红影 发表于 2022-2-16 14:44

“我们用 parseInt 内置函数将其强制变换为整数”

这个是直接舍去小数还是大于多少就进位?

马黑黑 发表于 2022-2-16 14:49

红影 发表于 2022-2-16 14:44
“我们用 parseInt 内置函数将其强制变换为整数”

这个是直接舍去小数还是大于多少就进位?

parse是强制,Int是整数,强制转换成整数,没有小数点

红影 发表于 2022-2-16 15:02

马黑黑 发表于 2022-2-16 14:44
手动制作JS歌词数组的方法看地板楼

Emeditor加这些符号真方便{:4_204:}

红影 发表于 2022-2-16 15:03

马黑黑 发表于 2022-2-16 14:49
parse是强制,Int是整数,强制转换成整数,没有小数点

嗯,就是后面不管多大都舍去。

马黑黑 发表于 2022-2-16 15:07

红影 发表于 2022-2-16 15:03
嗯,就是后面不管多大都舍去。

这思路其实挺经济(不用处理毫秒 ),也合理(歌词会提前省去的毫秒数出现)

红影 发表于 2022-2-16 15:18

马黑黑 发表于 2022-2-16 15:07
这思路其实挺经济(不用处理毫秒 ),也合理(歌词会提前省去的毫秒数出现)

遇到超过1小时的唱歌, 还要多加一组数据吧。

你之前的那个很多歌曲的那个,要是做歌词同步,要每个歌曲都嵌进去这个同步命令吧。

马黑黑 发表于 2022-2-16 16:11

红影 发表于 2022-2-16 15:18
遇到超过1小时的唱歌, 还要多加一组数据吧。

你之前的那个很多歌曲的那个,要是做歌词同步,要每个歌 ...

这个我考虑过,数组不用加,但要处理一下小时数,把小时数变为秒数就可以了的

红影 发表于 2022-2-16 20:54

马黑黑 发表于 2022-2-16 16:11
这个我考虑过,数组不用加,但要处理一下小时数,把小时数变为秒数就可以了的

乘以3600.

马黑黑 发表于 2022-2-16 22:32

红影 发表于 2022-2-16 20:54
乘以3600.

我数学不好,我不值得{:5_117:}

马黑黑 发表于 2022-2-16 22:33

一个使用例子:单曲播放器+宽幅

https://www.huachaowang.com/forum.php?mod=viewthread&tid=57079&extra=page%3D1

小辣椒 发表于 2022-2-16 22:45

这个歌词的时间设置还没有做过,还要改变一下?

马黑黑 发表于 2022-2-16 22:47

小辣椒 发表于 2022-2-16 22:45
这个歌词的时间设置还没有做过,还要改变一下?

有空你仔细看看教程,看不懂没关系,关键是找到lrc歌词和如何构建 JS数组

小辣椒 发表于 2022-2-16 22:47

黑黑你真的太厉害了,居然歌词同步都出来了,太佩服了{:4_199:}

马黑黑 发表于 2022-2-16 22:48

小辣椒 发表于 2022-2-16 22:47
黑黑你真的太厉害了,居然歌词同步都出来了,太佩服了

这个不是太难,你看代码都不是很多

小辣椒 发表于 2022-2-16 22:49

马黑黑 发表于 2022-2-16 22:47
有空你仔细看看教程,看不懂没关系,关键是找到lrc歌词和如何构建 JS数组

好的,看见你写着是手动的,我就把歌词直接修改一下可以吗
页: [1] 2
查看完整版本: audio播放器对lrc歌词同步的实现思路