带有THREE.js和Web Audio API的Music Visualiser

为了学习THREE.js(3D渲染WebGL框架和WebAudio API),我做了一些非常简单的方法来可视化音乐。 本文记录了整个过程。


https://www.w3.org/TR/webaudio/#ModularRouting

最简单的插图在上下文内部具有一个源和一个目的地,没有任何影响或处理。 为什么有人会使用这个? 也许他们只是想播放声音而没有任何变化。

左侧是更为复杂的设置示例,也可以使用此API进行设置。

让我们看一下可视化工具中的相关代码:

  //从用户可能的文件数组中获取音频文件,用户 
//上传
audio.src = URL.createObjectURL(files [0]); //加载文件,然后播放-全部使用HTML5音频元素的// API
audio.load();
audio.play(); / *
输入WebAudio API
* / var context = new AudioContext(); //创建上下文
var src =
context.createMediaElementSource(audio); //在ctx中创建src
var analyzer = context.createAnalyser(); //在ctx中创建分析器
src.connect(analyser); //将分析器节点连接到src
analyser.connect(context.destination); //连接目的地
//到分析器的节点
analyser.fftSize = 512;
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
/ *
...
...
...
让我们跳过介于两者之间的其他几件事
...
...
...
...
* / function render(){//此函数在每次更新时运行
analyser.getByteFrequencyData(dataArray); //将数组切成两半
var lowerHalfArray = dataArray.slice(0,(dataArray.length / 2)-1);
var upperHalfArray =
dataArray.slice((dataArray.length / 2)-1,dataArray.length-1); //做一些基本的归约/归一化
var lowerMax = max(lowerHalfArray);
var lowerAvg = avg(lowerHalfArray);
var upperAvg = avg(upperHalfArray); var lowerMaxFr = lowerMax / lowerHalfArray.length;
var lowerAvgFr = lowerAvg / lowerHalfArray.length;
var upperAvgFr = upperAvg / upperHalfArray.length; / *使用减少的值来调制3d对象* /
//这些是球体上方和下方的平面网格
makeRoughGround(plane,modulate(upperAvgFr,0,1,0.5,4));
makeRoughGround(plane2,modulate(lowerMaxFr,0,1,0.5,4));

//这会调制球体的形状。
makeRoughBall(
球,
modulate(Math.pow(lowerMaxFr,0.5),0,1,0,8),
调制(upperAvgFr,0,1,0,4)
); / *
...
跳过此处与WebAudio API不相关的其他内容
...
* /
}

关于WebAudio API,我们在此项目中使用它的唯一目的是提取音频信号的属性,并使用这些属性来更新视觉效果。 如果您查看上面的代码,则“分析器节点”可帮助我们实时分析这些音乐属性。 由于它不会干扰信号并且不会以任何方式改变它,因此它是我们使用的理想界面。

该接口(分析器节点接口)表示一个能够提供实时频率和时域分析信息的节点。 音频流将未经处理地从输入传递到输出。

FFT Size的默认值为2048,但我们选择了较低的分辨率512,因为它更容易计算-考虑到我使用的非常原始的拍子检测方法不需要很高的分辨率,此外,对于实时3D更新,因此我们可以放心地使用入门级的此值。 从这两个家伙那里可以学到更多关于FFT Cab的知识!

缓冲区长度等于bin数量,是FFT大小的一半。 对于512的FFT大小,缓冲区长度为256个数据点。 这意味着对于每次更新,我们有256个数据点对应于整个音频频谱,可用于可视化,即代码中的dataArray

我使用这些数据的方式是,我将阵列从中间切成两半,上半部分包含所有较高的频率-大约是高音,下半部分包含所有较低的频率。 我想要一些快速的东西,并使用较低频率的总和来近似节拍。 而上半部分的合并值用于可视化纹理。 通过一些简单的转换,这两种方法都降低为一组更自然的值。

基本构建块:

我仅从场景中的球体开始进行变换。 由于这是一个比较简单的任务,因此我稍后添加了两个平面网格,以使场景具有更大的深度。 关于THREE.js的好处是,完成基本设置后,专注于添加或删除内容就很容易了。

对于场景,我们需要一些基本的东西:

  • 一个包含所有内容的场景
  • 一两盏灯
  • 相机
  • 渲染器,渲染所有内容
  • 所有物体-我们的球体和飞机
  • 组(可选)—它们帮助您将对象分组在一起并帮助您保持一定顺序
  • 渲染循环,将在需要时更新场景

您可以查看其余的代码以查看所有细节。 如果您想对THREE.js进行适当的介绍,我发现本文以及@aerotwist的其他内容都非常有帮助。


可视化器的核心思想是基于节拍特征来调制球体的大小,并根据声音使球体表面变形。 为了使它有趣,我使用了程序噪声,使用音频数据作为输入,为球增加了一些物理纹理。

有几种经过实践检验的方法可以增加噪音,我决定使用Simplex Noise(更多详细信息,请参见此处)。 您可以查看下面的代码以了解实际的变形过程。

 函数makeRoughBall(mesh,bassFr,treFr){ 
mesh.geometry.vertices.forEach(function(vertex,i){
var offset = mesh.geometry.parameters.radius;
var time = window.performance.now();
vertex.normalize();
var distance =(offset + bassFr)+ noise.noise3D(
vertex.x +时间* 0.00007,
vertex.y + time * 0.00008,
vertex.z +时间* 0.00009
)*放大器* treFr;
vertex.multiplyScalar(distance);
});
mesh.geometry.verticesNeedUpdate = true;
mesh.geometry.normalsNeedUpdate = true;
mesh.geometry.computeVertexNormals();
mesh.geometry.computeFaceNormals();
}

当我们将所有内容放在一起时,我们会得到一个简单的音频可视化器。 让我知道您对此有何想法。 任何想法,改进等。