首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在三维webgl空间中渲染音频分析器

如何在三维webgl空间中渲染音频分析器
EN

Stack Overflow用户
提问于 2022-10-22 11:02:38
回答 1查看 45关注 0票数 0

我在试着做一个音频分析仪。我从它开始使用HTML画布的2D上下文,它看起来已经很好了。

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Audio Analyser</title>
    <style>
        body {
            background-color: black;
        }
        canvas {
            position: fixed;
            left:0;
            top:0;
        }
    </style>
</head>
<body>
    <audio src="track/life to take.wav" id="audio-master"></audio>
    <canvas id="canvas"></canvas>
    <script>
        var audio = document.getElementById("audio-master");
        var canvas = document.getElementById("canvas");
        var actx = null, ctx = canvas.getContext("2d"), analyser, source;
        window.onload = drawPlayButton;
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        window.onclick = function () {
            if (audio.paused) {
                if (actx == null) {
                    actx = new AudioContext();
                    analyser = actx.createAnalyser();
                    source = actx.createMediaElementSource(audio);
                }
                var spectrum = new Uint8Array(analyser.frequencyBinCount);
                var peekSpectrum = new Float32Array(64);
                var peekVelocities = new Float32Array(64);
                source.connect(analyser);
                analyser.connect(actx.destination);
                analyser.fftSize = 2048;
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;
                function render() {
                    if (!audio.paused) {
                        requestAnimationFrame(render);
                    } else {
                        drawPlayButton();
                        return;
                    }
                    ctx.clearRect(0,0,canvas.width,canvas.height);
                    analyser.getByteFrequencyData(spectrum);
                    var bandamount = analyser.frequencyBinCount;
                    var bandwidth = canvas.width / 64;
                    var bottom = canvas.height;
                    for(let i=0;i<64;i++) {
                        let j = toLog(i*bandamount/64+1, 1, bandamount);
                        let k = spectrum[Math.floor(j)], l = spectrum[Math.ceil(j)];
                        let m = k + (l - k) * (j%1);
                        if (isNaN(l)) m = k;
                        let n = Math.pow(m, 3+i/128) * bottom / 0x4000000;
                        if (n >= peekSpectrum[i]) {
                            peekVelocities[i] = (peekSpectrum[i]-n)/10;
                            peekSpectrum[i] = n;
                        } else {
                            peekSpectrum[i] -= (peekVelocities[i]+=bottom/1000);
                        }
                        let o = peekSpectrum[i] + 16;
                        let grad = ctx.createLinearGradient(0,0,0,bottom);
                        grad.addColorStop(0,"#0000ff");
                        grad.addColorStop(0.3,"#6600ff");
                        grad.addColorStop(1-m/1000,"#ff00ff");
                        grad.addColorStop(1,new Color(255, m, 255, 1.0));
                        ctx.fillStyle = grad;
                        drawBand(bandwidth*i+4, bottom-n, bandwidth*(i+1)-4, bottom, 8);
                        drawPeek(bandwidth*i+4, bottom-o, bandwidth-8, 8);
                    }
                }
                // Logarithmic formula by Gerard Abello
                function toLog(value, min, max) {
                    var exp = (value-min) / (max-min);
                    return min * Math.pow(max/min, exp);
                }
                function drawBand(x1, y1, x2, y2, r) {
                    ctx.beginPath();
                    ctx.moveTo(x1, y2);
                    ctx.lineTo(x1, y1+r);
                    ctx.arcTo(x1, y1, x1+r, y1, r);
                    ctx.lineTo(x2-r, y1);
                    ctx.arcTo(x2, y1, x2, y1+r, r);
                    ctx.lineTo(x2, y2);
                    ctx.closePath();
                    ctx.fill();
                }
                function drawPeek(x, y, w, r) {
                    ctx.beginPath();
                    ctx.arc(x+r, y, r, Math.PI*0.5, Math.PI*1.5);
                    ctx.lineTo(x+w-r, y-r);
                    ctx.arcTo(x+w, y-r, x+w, y, r);
                    ctx.arcTo(x+w, y+r, x+w-r, y+r, r);
                    ctx.closePath();
                    ctx.fill();
                }
                audio.play();
                render();
            } else {
                audio.pause();
                audio.currentTime = 0;
            }
        }
        function drawPlayButton() {
            ctx.beginPath();
            ctx.arc(canvas.width/2, canvas.height/2, 80, 0, Math.PI*2);
            ctx.fillStyle = "#404040C0";
            ctx.fill();
            ctx.beginPath();
            ctx.moveTo(canvas.width/2-40, canvas.height/2-40);
            ctx.lineTo(canvas.width/2-40, canvas.height/2+40);
            ctx.lineTo(canvas.width/2+40, canvas.height/2);
            ctx.closePath();
            ctx.fillStyle = "#ffffffc0";
            ctx.fill();
        }
        function Color(red, green, blue, alpha) {
            this.red = red & 255;
            this.green = green & 255;
            this.blue = blue & 255;
            this.alpha = arguments.length > 3 ? alpha : 1;
            this.toString = function() {
                if (this.alpha === 1) {
                    return (0x1000000 | this.red << 16 | this.green << 8 | this.blue).toString(16).replace(/^1/,"#");
                } else {
                    return (0x100000000 + this.red * 0x1000000 + this.green * 0x10000 + this.blue * 256 + this.alpha * 255 & 255).toString(16).replace(/^1/,"#");
                }
            }
        }
    </script>
</body>
</html>

不过,我想把它变成3D的。我想用墙上的分析器做一个走廊。所以我需要把这整件事转换成WebGL。我不知道从哪里开始。正如你所看到的,分析器也有一些曲线。我知道您不能在WebGL中绘制曲线,但是应该有一个方法可以绕过它。

EN

回答 1

Stack Overflow用户

发布于 2022-10-24 13:57:02

结果我把事情搞得太复杂了。我所要做的就是制作另一个画布,因为画布在WebGL中也被认为是一个有效的纹理。第一个画布隐藏并使用2D上下文绘制频谱,第二个画布复制第一个画布的全部内容,并将其粘贴到WebGL上下文中。我可以很容易地做多个这些,我不需要担心曲线。如果我知道事情会这么简单,我就不会问这个问题了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74162981

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档