J'Blog

threejs实现音频可视化效果

threejs实现音频可视化效果

音频分析

创建AudioAnalyser对象, 使用 AnalyserNode 去分析音频数据。将声波的波动转化为图形线条的起伏变化,从而表现出声音的音高、音量等信息。

核心代码

function createAudio() {
    const fftSize = 1024;
    if (!audio) {
        const listener = new THREE.AudioListener();
        audio = new THREE.Audio(listener);
        const file = '/assets/video.mp4'; // 音视频都可以

        mediaElement = new Audio(file);
        mediaElement.play();
        audio.setMediaElementSource(mediaElement);
    }

    analyser = new THREE.AudioAnalyser(audio, fftSize);

    bufferLength = analyser.analyser.frequencyBinCount;
    dataArray = new Uint8Array(bufferLength);
    analyser.getFrequencyData(dataArray);
    dataArray = analyser.data

    // 获取 ID 为 "oscilloscope" 的画布
    canvas = document.getElementById("oscilloscope");
    canvasCtx = canvas.getContext("2d");

    var canvasTexture = new THREE.CanvasTexture(canvas);
    // 创建平面
    var geometry = new THREE.PlaneGeometry(18, 2);
    var material = new THREE.MeshPhongMaterial({
        map: canvasTexture, // 设置纹理贴图
        transparent: true,
    });
    // 创建一个矩形平面网模型,Canvas画布作为矩形网格模型的纹理贴图
    var mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    // 绘制一个当前音频源的示波器
    function draw() {
        drawVisual = requestAnimationFrame(draw);
        canvasTexture.needsUpdate = true;

        analyser.getFrequencyData(dataArray);
        dataArray = analyser.data

	// 绘制柱形
        // canvase背景色透明
        canvasCtx.fillStyle = 'rgba(255, 255, 255, 0)';
        canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

        var barWidth = canvas.width / bufferLength * 4
        var barHeight;
        var x = 0;

        for (var i = 0; i < bufferLength; i++) {
            barHeight = dataArray[i];

            canvasCtx.fillStyle = 'rgb(' + barHeight + 100 + ',200,130)';
            canvasCtx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
            x += barWidth + 1;
        }

	// 绘制波形
        // canvasCtx.lineWidth = 2;
        // canvasCtx.strokeStyle = "rgb(0, 0, 0)";

        // canvasCtx.beginPath();

        // var sliceWidth = (canvas.width * 1.0) / bufferLength;
        // var x = 0;

        // for (var i = 0; i < bufferLength; i++) {
        //     var v = dataArray[i] / 128.0;
        //     var y = (v * canvas.height) / 2;

        //     if (i === 0) {
        //         canvasCtx.moveTo(x, y);
        //     } else {
        //         canvasCtx.lineTo(x, y);
        //     }

        //     x += sliceWidth;
        // }

        canvasCtx.lineTo(canvas.width, canvas.height / 2);
        canvasCtx.stroke();
    }

    draw();
}