声控光影!用Web API制作智能拾音灯
引言
近几日偶然刷到的一个关于拾音灯的视频(下图),一时兴起想搞个玩一玩!不过这种东西在我手里肯定也就几分钟热度。。。思索片刻不如码上小搞一搞!
在数字时代,技术与艺术的结合为我们带来了无限可能。拾音灯作为一种将声音与光影
结合的互动装置,不仅能够响应音乐的节奏,还能创造出令人着迷的视觉效果。
本文将引导你如何制作一个个性化的拾音灯,让你在web的世界中体验光与声的完美融合。
audio API
Web API
,即 Web 应用程序接口
,是现代 Web 应用开发的核心。通过使用 Web API,我们可以访问浏览器提供的丰富功能,如音频处理、图形渲染等,从而在网页上实现复杂的交互效果。
今天要提的叫做audio API
,它是专门处理音频数据的,允许开发者对音频添加特效,使音频可视化,添加空间效果(如平移),等等。
这套API的详细内容我就不细说了,大家有兴趣的可以查阅资料自行学习(https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
)。要实现拾音灯效果,要了解两个概念:
- 处理节点:处理音频数据会经过很多的环节,每一个环节就是一个节点
- 比如一段音频数据,将噪音全部去除,之后把处理过的数据再重新输出,这就是一个节点的功能。
- 每个节点是连接的,上一个节点处理完成之后将数据交给下一个节点(如噪音节点交给变声节点),全部处理完了之后还可以将音频数据交给输出设备,比如音箱,音箱展现出的就是处理之后的音频。
- 在拾音灯的效果当中,不需要很多节点,主要是使用分析节点,帮助我们分析音频数据,获取数据之后将数据可视化,即拾音灯。
- 音频上下文(AudioContext):可以理解为所有处理节点的集合,是一个环境对象,在这个环境中管理一系列节点。
逻辑编写
以下相关代码全部使用
Vue3
编写
- 初始化变量
const isInit = ref(false); //是否初始化上下文
const analyser = ref(null); //分析节点
const buffer = ref([]); //分析数据
- 点击播放初始化音频上下文
音频上下文只需要创建一次即可,但是播放事件点击一次就是执行一次,使用一个变量isInit
来管控该行为
if (isInit.value) {
return;
}
//创建音频上下文
const audioCtx = new AudioContext();
- 创建分析节点
//创建分析节点
analyser.value = audioCtx.createAnalyser();
使用getByteFrequencyData
方法进行分析,方法接收一个数组,分析的结果会保存到该数组里面,具体过程就是:以调用这个方法的时间点为准,得到一小段时间内的数据,比如10毫秒,之后再得到下一个10毫秒的音频相关数据,将分析结果放进数组里面去。根据此过程了解到后续需要不断的调用这个方法,以持续输出分析结果,我们需要使用requestAnimationFrame 动画帧API
。
function update() {
requestAnimationFrame(update);
// 没有初始化上下文,return
if (!isInit.value) {
return;
}
analyser.value.getByteFrequencyData(buffer.value); //分析,传递一个类型数组 buffer
sclList.value = reflection.map(e => Array.from(buffer.value)[e] * 2); //对数据的一些处理
// console.log(sclList.value);
}
update();
上面代码中分析了数据,那么到底是什么数据呢,有两种:
-
频率数据:调用
getByteFrequencyData
方法获取 -
时域数据:调用
getByteTimeDomainData
方法获取
两个方法用法一样,至于频率数据和时域数据,大家可以自行了解。
- 类型数组
getByteFrequencyData
方法要求传递一个类型数组Uint8Array
(无符号字节数组,下标取值范围在0 - 255)。
数组的长度决定分析的结果有多精细,如果数组的长度小于 分析节点的frequencyBinCount
属性, 那么分析节点多出的元素会被删除,如果是大于,那么数组多余的元素会被忽略。通过分析节点的fftSize
属性设置精细程度。
frequencyBinCount
的数值刚好是fftSize
的一半。
analyser.value.fftSize = 512;
buffer.value = new Uint8Array(analyser.value.frequencyBinCount);
- 配置音频来源
创建一个音频来源节点source,连接分析节点,连接音频输出节点(播放音频)
const source = audioCtx.createMediaElementSource(audioEle.value);
source.connect(analyser.value);
analyser.value.connect(audioCtx.destination);
- 之后点击播放则可以持续输出分析数据
- 数据渲染
拿到数据之后要做的事情就是数据渲染,这个分析数据有256条,数组是倒序排列的,前面的数值比后面的数值大。为了美观可以在里面随意选取适当多的数据并打乱顺序,下标映射:
const reflection = [94, 45, 4, 110, 116, 34, 123, 52, 100, 32, 99, 103, 2, 32, 126, 74]; //下标随机映射 16条(16根拾音灯)
const colors = ["#fe0034","#f7343a","#f96336","#f9883c","#e9a437","#e4b333","#dfbe38","#cfcc3d","#bcd738","#94dd2f","#04ec35","#01f635","#01eb89","#05debe","#04d8d7","#09c9e9","#04acfc","#0396ff","#0e6eff","#1930ff","#5025fe","#7121fd","#8c1eff","#ad1af9","#b61efb","#c71afe","#d716f2","#da14de","#f811d1","#c20780",
]; //色块列表 30个
效果
实现效果如下:
接下来使用一个视频展示拾音灯的具体效果,界面随手画的!
这里不允许上传本地视频,只允许西瓜视频链接,感兴趣可以移步公众号观看:小新学研社。如果有需要源码的公众号回复关键字:拾音灯。
转载自:https://juejin.cn/post/7396254541916880948