最近没事的时候,看一些网站设计想着自己也做一个比较简单的页面啥的,想来想去最后还是打算做一个音乐可视化,因为我本身就挺喜欢听歌的,如果有一个看着比较舒服的界面听歌,发发呆感觉也是一种休息,所以music-radio完成啦🎉🎉🎉

因为以前就写过音乐相关可视化的功能,所以在绘制频谱哪一块就比较简单,就是画几条线 用到的相关canvas api也就那么几个。

这次在WEB上完成这个功能主要还是要用到WEB AUDIO相关的API,其主要操作流程就是:

  1. 声明一个AudioContext(音频上下文),我们的一些相关音频的操作都会在这个环境下操作,通过new AudioContext()来创建。

  2. 需要一个AudioBufferSourceNode对象,它代表一个音频源,通过AudioContext的createBufferSourceAPI来创建,它还需要一个AudioBuffer类型的音频资源。

利用AudioContext.decodeAudioData()方法从一个音频文件构建,或者利用 AudioContext.createBuffer()从原始数据构建。把音频放入AudioBuffer后,可以传入到一个 AudioBufferSourceNode进行播放。

来源 MDN

简单来说就是把我们网上的或者本地的又或者通过设备麦克风等获取的一段音频转换成AudioBuffer然后“喂”给AudioBufferSourceNode对象,这样我们这个音频源就可以播放啦。

  1. 最后我们还需要一个实时分析当前音源获取频域和时域信息的对象,用来画出我们所看到的可视化频谱,通过AudioContext的AnalyserNodeAPI即可创建,这一步也是做可视化音乐重要的一步,前面的都是加载音频播放,这里才是分析音频数据,把分析后的数据用来绘制到屏幕上实现动感效果。

创建好它们以后通过connect来把它们关联起来,这里一定要注意顺序:

音频源AudioBufferSourceNode -> 分析器AnalyserNode -> 输出地址AudioDestinationNode

即把我们的音频源数据绑定到分析器,这样分析器就可以分析我们音频源的数据,最后在把分析器绑定到我们的输出地址或设备,一般都是设备的扬声器,这样我们的设备才能正常的播放出来~ 伪代码如下:

1
2
3
4
5
6
7
8
9
const ac = new AudioContext()

const analyser = ac.createAnalyser()

const source = ac.createBufferSource()

source.connect(analyser)

analyser.connect(ac.destination)

整体差不多就是这样,说一下遇到的坑把:

  1. 我们创建的音频源只能播放一次,如果要重复播放,需要重复创建,如果我们需要播放下一段音频或者跳转到指定时间继续播放,都需要重新创建一个音频源。

  2. 音频源如果手动调用了stop函数以后会触发onended,解决办法:

1
2
3
4
5
6
7
8
9
source.onended = () => {
console.log('end')
}

// 点击stop
function stop () {
source.onended = null
source.stop()
}
  1. AudioContext的currentTime属性是上下文被创建以后就会一直累加,就算你不播放音频,这个时间也是会继续累加,所以用这个来判断当前播放时间是会问题的,解决办法:

在调用source.start(0)开始播放的时候,记录下当前的currentTime,这样获取音频当前时间就是用现在的currentTime - 记录的currentTime = 当前播放时间


其他的好像也就没啥了,这个也就是我随便写的,没用vue,react那些框架,也没用scss等预编译工具,手动一把梭,样式一些兼容前缀也没加,也用了比较新的一些API,如fetch等,所以嘛有一些游览器可能访问会有报错啥的,也没有考虑太多,代码写的也不是很简洁,有很多地方感觉还可以优化也懒得弄了 Orz。

游览地址: