Search code examples
javascripthtmlgoogle-chromeoperating-systemweb-audio-api

Why are decodeAudioData() results different on different OS


Update 2: Run the script here. It will show the sample rate when clicking the "LOAD" button.

function decode() {
    // If the default naming is not enabled, use the Chrome one
    if (!window.AudioContext) {
        if (!window.webkitAudioContext) {
            alert("No AudioContext found.");
        }
        window.AudioContext = window.webkitAudioContext;
    }
    var audioContext = new AudioContext();
    alert("sample rate: " + audioContext.sampleRate);
    var sourceNode;

    var BUFFER_SIZE = 1024;

    // Create buffer node and download file to buffer
    createAudioNodes();
    var fileURL = "http://plaay.in/decode-audio-data/decode-this-audio.wav";
    downloadAudioFromURL(fileURL);

    function createAudioNodes() {
        sourceNode = audioContext.createBufferSource();
        sourceNode.connect(audioContext.destination);
    }

    function downloadAudioFromURL(url) {
        var request = new XMLHttpRequest();
        request.open("GET", url, true);
        request.responseType = "arraybuffer";
        request.addEventListener("progress", updateProgress);

        request.onload = function() {
            audioContext.decodeAudioData(request.response, function(buffer) {
                setSourceBuffer(buffer);
            }, onError);
        };
        request.send();
    }

    function updateProgress(progress) {
        if (progress.lengthComputable) {
            var percentComplete = Math.round(progress.loaded / progress.total * 100);
            document.getElementById("progress").innerHTML = "Loading... " + percentComplete.toString() + "%";
        }
    }

    function setSourceBuffer(buffer) {
        var leftInBuffer = buffer.getChannelData(0);
        console.log("leftInBuffer length: " + leftInBuffer.length);
        for (var i = 0; i < leftInBuffer.length; i++) {
            console.log(leftInBuffer[i]);
        }
    }

    function onError(e) {
        console.log(e);
    }
}
<!doctype html>
<html lang="en-US">

<head>
    <meta charset="utf-8">
    <title>Decode Audio Data</title>
</head>

<body>
    <script src="decode.js"></script>
    <button id="playButton" type="button" style="height:40px;width:150px" onclick="decode()">LOAD</button>
    <p id="progress">File download progress</p>
</body>

</html>

Update: filed an issue here.

I want to decode an audio file and get its raw data for processing in the following step. The idea is to use decodeAudioData() of Web Audio API. The weird problem is the decode results will depend on the operating system. Did anyone encounter the same problem, or know the reason why?

I made a quick demo and tested it on Mac OS (10.11) and Windows 7 and the browsers are both Chrome (v46.0+), but their results are different. To visualize the results:

enter image description here

Everyone can run this demo, just click the "LOAD" button and the results will be logged in the console.


Solution

  • Finally I found OfflineAudioContext can set the sample rate for my later decodeAudioData(). To decode a 30 seconds long stereo audio with 44.1kHz sample rate, create an offlineAudioContext like the following, and don't forget webkit prefix for Safari.

    window.OfflineAudioContext = window.offlineAudioContext || window.webkitOfflineAudioContext;
    var offlineAudioContext = new OfflineAudioContext(2, 44100 * 30, 44100);