javascripthtml5-audioweb-audio-apiaudiobuffer

Play AudioBuffer in existing HTML5 audio tag


I've created a website that contains an audio-tag as well as a working drop-area for file upload.

<body>
    <audio id="myPlayer" controls>Your browser does not support the audio-tag</audio>
    <div id="dropArea"></div>
</body>

A dragged audio-file then gets converted into an ArrayBuffer and ultimately an AudioBuffer.

let audioContext = new (window.AudioContext || window.webkitAudioContext)();
let arrayBuffer = await readFileAsArrayBuffer(audioFile);

audioContext.decodeAudioData(arrayBuffer, buf => {
    console.log(buf);
});

The AudioBuffer can then be played in the function like this:

playSound(buffer) => {
  let source = context.createBufferSource();

  source.buffer = buffer;
  source.connect(context.destination);
  source.start(0);
}

All of the above works fine, but that's not what I'm after.

I want to the AudioBuffer to be played and controlled in the audio-player in my HTML instead. How can this be done?


Solution

  • To answer my own question, a data URL needs to be created from the uploaded file.

    The readAsDataURL method is used to read the contents of the specified Blob or File. When the read operation is finished, the readyState becomes DONE, and the loadend is triggered. At that time, the result attribute contains the data as a data: URL representing the file's data as a base64 encoded string.

    Example

    // Helper Function
    function readAsDataURL(file) {
      return new Promise((resolve, reject) => {
        if (file instanceof File) {
          reader.onload = () => {
            resolve(reader.result);
          };
          reader.readAsDataURL(file);
        } else {
          reject(new Error("This type of object is not supported"));
        }
      });
    }
    
    // Set URL for audio player
    (async () => {
      const url = await readAsDataURL(event.dataTransfer.files[0]);
      const audioElement = document.querySelector("#audio-player");
    
      audioElement.src = url;
    })();