书又接上文,感觉逼格不够大,所以鼓捣了个音频可视化

Web Audio API

Web Audio API可以获取音频的包括频率、波形的信息,能用于选频、加特效、做可视化、添加空间效果等,就像是音频版的canvas

MDN网站已经给出音频可视化案例了,我只需魔改一下就行了

编码

在MDN的案例基础上加了点自己的个性化需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import debounce from "../Tools/debounce.js"

export default (canvas, audio) => {

// 快速傅立叶变换(Fast Fourier Transform),一定要是2的倍数,默认为2048
const FFT = 512

// 实例化AudioContext音频上下文对象
const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
// 创建AnalyserNode节点
const analyser = audioCtx.createAnalyser()
// 让fft变小可以使每个频率条有一定宽度
analyser.fftSize = FFT

// 将AnalyserNode节点和声源连接
// 从audio中获取声音源文件
const audioSrc = audioCtx.createMediaElementSource(audio)
audioSrc.connect(analyser)
analyser.connect(audioCtx.destination)

// AnalyserNode数据解析,获得瞬时音频数据
const bufferLength = analyser.frequencyBinCount
const dataArray = new Uint8Array(bufferLength)
analyser.getByteFrequencyData(dataArray)

// -------------------------------------

// 画布大小响应(因为要铺满整个背景)
const canvasResize = ()=> {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
canvasResize()
window.addEventListener("resize", debounce(canvasResize,100))

if (canvas.getContext) {
const ctx = canvas.getContext("2d")

ctx.clearRect(0, 0, canvas.width, canvas.height)

// 开画
const draw = () => {
// 动画帧
requestAnimationFrame(draw)

// 获取该帧的音频信息
analyser.getByteFrequencyData(dataArray)

// 每一帧都要先清空画布,不然旧内容会保留
ctx.clearRect(0, 0, canvas.width, canvas.height)

// 设置条的宽高
const barWidth = (canvas.width / bufferLength)
let barHeight

// 记录条当前位置
let x = 0

// 遍历每一条(每一个音频信息)
for (var i = 0; i < bufferLength; i++) {

// 给条高赋值
barHeight = ((dataArray[i] * 3) / (FFT)) * canvas.height

// 给条上喜欢的颜色,因为我是人类所以使用hsl颜色
ctx.fillStyle = `hsl(${120 + (x / canvas.width) * 120},${10 + (barHeight / canvas.height) * 90}%,60%)`

// 将条绘制到画布伤
ctx.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight)

// 每个条之间留个间距
x += barWidth + 3
}
}
draw()
}
}

然后是笨办法之轮询等播放器初始化(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import makeVisual from "./makeVisual.js"

window.addEventListener("load", ()=> {

const timer = setInterval(() => {
if(window.fixedap) {
const audio = window.fixedap.audio
const canvas = document.getElementById("music-visualization")

// 浏览器策略不准自动播放音频,总之音频解析行为必须放在用户确认之后
const canplay = ()=> {
makeVisual(canvas,audio)
window.removeEventListener("click", canplay)
}
window.addEventListener("click", canplay)
clearInterval(timer)
}
}, 500)
})

在Meting.js中的恰当位置加一句,否则不能跨域获取音频信息

1
aplayers.forEach(ap=> {ap.audio.crossOrigin="anonymous"})

最后就是把canvas标签加进butterfly inject配置项

1
2
3
4
inject:
head:
# ......省略
<canvas id="music-visualization" style="position:fixed;z-index:-900"></canvas>

为了让可视化效果更好看,我顺便把原本页面上纯色的内容块改成了半透明,感觉还不错~