How to create an AudioBuffer from a Blob?
Asked Answered
T

5

23

I have an audio file/blob that has been created using the MediaRecorder api:

let recorder = new MediaRecorder(this.stream)
let data = [];
recorder.ondataavailable = event => data.push(event.data);

and then later when the recording is finished:

let superBlob = new Blob(data, { type: "video/webm" });

How can I use this blob to create an AudioBuffer? I need to either :

  • Transform the Blob object into an ArrayBuffer which I could use with AudioContext.decodeAudioData (returns an AudioBuffer) or
  • Transform the Blob object into an Float32Array, where I could copy it into the AudioBuffer with AudioBuffer.copyToChannel()

Any tips on how to achieve that are appreciated. Cheers!

Trypsin answered 1/11, 2016 at 15:33 Comment(0)
T
17

To convert a Blob object to an ArrayBuffer, use FileReader.readAsArrayBuffer.

let fileReader = new FileReader();
let arrayBuffer;

fileReader.onloadend = () => {
    arrayBuffer = fileReader.result;
}

fileReader.readAsArrayBuffer(superBlob);
Trypsin answered 1/11, 2016 at 16:36 Comment(5)
I am using this in my implementation but the fileReader.result always returns an empty ArrayBuffer - do you know what could be happening? Further details can be found in this question that I askedBik
Are you sure you are checking fileReader.result in the onloadend event?Lamblike
Yea I've managed to get it working, it was a trivial mistake on my end so sorry about that. Thanks a lot for posting this answer though, it has been very helpful!Bik
not sure how trivial the mistake was. I found that you can't access the resulting array buffer directly. I used data = new Uint8Array(reader.result);Angelangela
As stated by PAT-O-MATION, this returns an arrayBuffer, not audioBufferVehicle
G
12

The accepted answer is great but only gives an array buffer which is not an audio buffer. You need to use the audio context to convert the array buffer into an audio buffer.

const audioContext = new AudioContext();
const fileReader = new FileReader();

// Set up file reader on loaded end event
fileReader.onloadend = () => {

    const arrayBuffer = fileReader.result as ArrayBuffer

    // Convert array buffer into audio buffer
    audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => {
    
      // Do something with audioBuffer
      console.log(audioBuffer)
    
    })
      
}

//Load blob
fileReader.readAsArrayBuffer(blob)

I wish the answer had included an example using decodeAudioData. I had to find it somewhere else and I thought since this is the top search for "Blob to Audio Buffer" I would add some helpful information for the next person that comes down this rabbit hole.

Gym answered 2/2, 2020 at 10:33 Comment(1)
do not use this answer, #66450767, decodeAudioData only works with fileRattat
B
6

All the answers are true. However, in the modern web browsers like Chrome 76 and Firefox 69, there is a much simpler way: using Blob.arrayBuffer()

Since Blob.arrayBuffer() returns a Promise, you can do either

superBlob.arrayBuffer().then(arrayBuffer => {
  // Do something with arrayBuffer
});

or

async function doSomethingWithAudioBuffer(blob) {
  var arrayBuffer = await blob.arrayBuffer();
  // Do something with arrayBuffer;
}
Bina answered 5/6, 2020 at 6:22 Comment(4)
Just tried that, and what you get back is an arrayBuffer, not an audioBufferVehicle
@Vehicle Would you read the question more carefully? The questioner is aware of how to convert an ArrayBuffer into an AudioBuffer. The question isn't about getting an AudioBuffer from a Blob.Bina
Read your code more carefully then... Don't write 'audioBuffer' where you get in fact an arrayBuffer.Vehicle
Thanks for taking the timeVehicle
F
3

A simplified version using an async function:

async function blobToAudioBuffer(audioContext, blob) {
  const arrayBuffer = await blob.arrayBuffer();
  return await audioContext.decodeAudioData(arrayBuffer);
}

I put audioContext as a param, because I recommend reusing instances.

Flynt answered 15/5, 2022 at 20:31 Comment(1)
#69453045Rattat
P
2

Both Answers are true, there are some minor changes. This is the function I finally used:

function convertBlobToAudioBuffer(myBlob) {

  const audioContext = new AudioContext();
  const fileReader = new FileReader();

  fileReader.onloadend = () => {

    let myArrayBuffer = fileReader.result;

    audioContext.decodeAudioData(myArrayBuffer, (audioBuffer) => {

      // Do something with audioBuffer

    });
  };

  //Load blob
  fileReader.readAsArrayBuffer(myBlob);
}
Pneumo answered 30/4, 2020 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.