如何用 vanilla javascript 绘制音频频谱?

How to draw audio spectrum with vanilla javascript?

我需要使用 vanilla javascript 从用户的媒体文件中绘制 canvas 上的音频频谱。但是,我无法解决那个问题。因为,每个人都使用 savesurfer.js.

我确实在网络音频上使用了 createAnalyser API。但是,'CreateAnalyser' 无法获取用户媒体文件的频率。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <input type="file" id="file">
    <canvas id="canvas" width="500" height="250"></canvas>
    <script>

        // draw an oscilloscope of the current audio source
        var canvas = document.getElementById('canvas');
        var canvasCtx = canvas.getContext('2d');
        var WIDTH = canvas.width;
        var HEIGHT = canvas.height;
        var audio = null;

        document.getElementById('file').addEventListener('change', function(e) {
            var audioCtx = new AudioContext();
            var file = e.target.files[0];
            var fileName = file.name;
            var fileReader = new FileReader();
            var audio = new Audio(fileName);
            var analyser = audioCtx.createAnalyser();

            fileReader.onload = function(e) {
                var buffer = e.target.result;
                var source = audioCtx.createBufferSource();
                audioCtx.decodeAudioData(buffer, (buffer) => {
                    source.loop = true;

                    var offlineAudioCtx = new OfflineAudioContext(buffer);

                    offlineAudioCtx.startRendering().then(function(buffer) {
                        source.buffer = buffer;
                        source.connect(analyser);
                        source.connect(audioCtx.destination);
                        var dataArray = new Uint8Array(analyser.frequencyBinCount);
                        analyser.getByteTimeDomainData(dataArray);
                        console.log(dataArray);
                    });
                });
            }
            fileReader.readAsArrayBuffer(file);
        });
    </script>
</body>
</html>

您在这里遗漏了一些东西。首先,你没有连接到分析器节点的输入,所以你需要做一些类似

的事情
source.connect(analyser);

您现在应该得到非常量输出。

您可能不想在每个事件上都创建一个新的 AudioContext(和 AnalyserNode)。每一种你只需要一个。

您可能还想在每个事件中多次调用 analyser.getByteTimeDomainData(),但这没关系。还有,时空数据的实际长度是fftSize,而不是frequencyBinCount。您在这里所做的只是复制可用时域数据的一半。也许这也可以满足您的需求。