THREE.AudioAnalyser
音频分析
入参 (Input Parameters):
audio
: 一个THREE.Audio
实例,代表要分析的音频。fftSize
: 快速傅里叶变换(FFT)的大小,用于确定分析的精度和频率分辨率。smoothingTimeConstant
: 平滑时间常数,用于控制分析结果的平滑程度。
出参 (Output):
THREE.AudioAnalyser
可能不直接返回出参,而是提供方法来获取分析结果,如频谱数据或波形数据。
方法 (Methods):
getFrequencyData(array)
: 将当前音频的频谱数据填充到提供的数组中。getByteFrequencyData(array)
: 将当前音频的频谱数据(以字节形式)填充到提供的数组中。getByteTimeDomainData(array)
: 将当前音频的波形数据(以字节形式)填充到提供的数组中。start()
: 开始音频分析。stop()
: 停止音频分析。
属性 (Properties):
analyser
: 内部的AnalyserNode
实例,用于执行音频分析。frequencyBinCount
: FFT 的大小,即频率仓的数量。smoothingTimeConstant
: 平滑时间常数的当前值。
demo 案例
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webaudio - visualizer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<!-- 顶点着色器 -->
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
</script>
<!-- 片段着色器 -->
<script id="fragmentShader" type="x-shader/x-fragment">
uniform sampler2D tAudioData;
varying vec2 vUv;
void main() {
vec3 backgroundColor = vec3(0.125, 0.125, 0.125);
vec3 color = vec3(1.0, 1.0, 0.0);
float f = texture2D(tAudioData, vec2(vUv.x, 0.0)).r;
float i = step(vUv.y, f) * step(f - 0.0125, vUv.y);
gl_FragColor = vec4(mix(backgroundColor, color, i), 1.0);
}
</script>
</head>
<body>
<div id="overlay">
<button id="startButton">Play</button>
</div>
<div id="container"></div>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener noreferrer">three.js</a> webaudio - visualizer<br/>
music by <a href="http://www.newgrounds.com/audio/listen/376737" target="_blank" rel="noopener">skullbeatz</a>
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
// 导入所需的模块
import * as THREE from 'three';
// 定义全局变量
let scene, camera, renderer, analyser, uniforms;
// 获取开始按钮并添加点击事件监听器
const startButton = document.getElementById('startButton');
startButton.addEventListener('click', init);
// 初始化函数
function init() {
const fftSize = 128; // FFT 大小
// 移除遮罩
const overlay = document.getElementById('overlay');
overlay.remove();
// 获取容器元素
const container = document.getElementById('container');
// 创建渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
// 创建场景和相机
scene = new THREE.Scene();
camera = new THREE.Camera();
// 创建音频分析器
const listener = new THREE.AudioListener();
const audio = new THREE.Audio(listener);
const file = './sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3';
// 检查是否在 iOS 设备上运行
if (/iPad|iPhone|iPod/g.test(navigator.userAgent)) {
const loader = new THREE.AudioLoader();
loader.load(file, function (buffer) {
audio.setBuffer(buffer);
audio.play();
});
} else {
const mediaElement = new Audio(file);
mediaElement.play();
audio.setMediaElementSource(mediaElement);
}
// 创建音频分析器并设置数据纹理
analyser = new THREE.AudioAnalyser(audio, fftSize);
const format = (renderer.capabilities.isWebGL2) ? THREE.RedFormat : THREE.LuminanceFormat;
uniforms = {
tAudioData: { value: new THREE.DataTexture(analyser.data, fftSize / 2, 1, format) }
};
// 创建材质
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
});
// 创建几何体和网格
const geometry = new THREE.PlaneGeometry(1, 1);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize);
// 开始动画循环
animate();
}
// 窗口大小变化时更新渲染器尺寸
function onWindowResize() {
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
render();
}
// 渲染函数
function render() {
// 更新频谱数据
analyser.getFrequencyData();
uniforms.tAudioData.value.needsUpdate = true;
renderer.render(scene, camera);
}
</script>
</body>
</html>