U.Dev
U.Dev

Reputation: 113

How to draw audio spectrum with vanilla javascript?

I need draw audio spectrum on canvas from user's media file with vanilla javascript. but, I cannot solve that problem. because, everybody use savesurfer.js.

I did use createAnalyser on Web audio API. but, 'CreateAnalyser' is cannot get frequency of user's media file.

<!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>

Upvotes: 0

Views: 779

Answers (1)

Raymond Toy
Raymond Toy

Reputation: 6048

You are missing a few things here. First, you have nothing connected to the input of the analyser node, so you need to do something like

source.connect(analyser);

You should now get non-constant output.

You probably don't want to create a new AudioContext (and AnalyserNode) on each event. You only need one of each.

You probably also want to call analyser.getByteTimeDomainData() more than once per event, but maybe that's ok. Also, the actual length of the time dome data is fftSize, not frequencyBinCount. What you've done here is only copy half of the time-domain data that's available. Maybe that's ok for what you want too.

Upvotes: 1

Related Questions