11

I am trying to load an audio buffer from an URL, and then to play it. I got most of the code form this HTML5 Rocks Tutorial.

var request = new XMLHttpRequest();
request.open('GET', $(this).attr('data-url'), true);
request.responseType = 'arraybuffer';

request.onload = function() {
    console.log(request);
    context.decodeAudioData(request.response, function(buffer) {
        console.log(buffer);
        $('#play').click(function() {
              var source = context.createBufferSource();
              source.connect(context.destination);
              source.noteOn(0);
        }).removeAttr('disabled');
    }, function(err) { console.log(err); });
};
request.send();

However, then I press the #play button, nothing happens. source.noteOn(0) is called, I checked it using the debugger. And all of the objects are properly loaded and created, but I hear no sound.

Also, as it seems, I would need to rebuild a complete player with all controls when I am using this approach. What I'd like to do, to save work and to ensure this works better, is to put the buffer into an <audio/>, so it can be played there.

I know there is audio.src for putting the file name in there, but I need to use the audio buffer. I've tried

audio.src = buffer;
audio.load()

But that did not work.

Any info there?

Lanbo
  • 15,118
  • 16
  • 70
  • 147

2 Answers2

21

To answer the real question not with a "just don't use the audio element", I'd like to provide another solution. I've wanted to show the user the audio controls, thus I needed a solution for the question asked.

Actually you just need to convert the ArrayBuffer to a Blob, get an URL for it and map this to the <audio> element's src attribute:

const blob = new Blob([arrayBuffer], { type: "audio/wav" });
const url = window.URL.createObjectURL(blob);
audioElement.src = url;

Please don't forget to change the mime type accordingly and don't forget to call

window.URL.revokeObjectURL(url);

when unloading your page/component for garbage collection.

Michael Dimmitt
  • 826
  • 10
  • 23
sibbl
  • 3,203
  • 26
  • 38
  • 2
    Note that if you need to decode the arrayBuffer, this will detach the buffer, thus you won't be able to create the blob. Solution: get the array buffer, create the blob, decode the array buffer. – JohnDoe Mar 15 '20 at 09:47
2

If you just want to play audio-files, you probably want to use the <audio> tag for sake of simplicity. (and for not being limited to webkit browsers).

In your example you do not set the buffer of your buffer-source node:
if you want to keep the overall structure, you can simply add the line source.buffer = buffer, like:

context.decodeAudioData(request.response, function(buffer) {
    $('#play').click(function() {
          var source = context.createBufferSource();
          source.buffer = buffer;
          source.connect(context.destination);
          source.noteOn(0);
    }).removeAttr('disabled');
}, function(err) { console.log(err); })

(your code's readability would improve by separating the audio decoding from the event-handling).

your other question on audio.src:
you should set audio.src to the URL of the audio file.

kr1
  • 7,225
  • 1
  • 26
  • 29