This is how I combined MediaRecorder
and Format converter based on great CuriousChad answer. Just needed to consider MP3 encoder as Stereo to work.
First, set AudioFormat equals to 'WEBM' (Chrome), 'MP3', or 'WAV':
this.mediaRecorder.onstop = e => {
if (AudioFormat === 'MP3' || AudioFormat === 'WAV')
{
var data = this.chunks[0];
var blob = new Blob(this.chunks, { type : 'video/webm' });
const audioContext = new AudioContext();
const fileReader = new FileReader();
fileReader.onloadend = () => {
const arrayBuffer = fileReader.result;
audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => {
console.log(audioBuffer)
var MP3Blob = this.audioBufferToWav(audioBuffer);
onStop(MP3Blob,audioBuffer);
})
}
fileReader.readAsArrayBuffer(blob)
}
else {
var data = this.chunks[0];
var blob = new Blob(this.chunks, { type : 'audio/mpeg' });
onStop(blob,data)
}
this.chunks = [];
};
Second, convert Buffer to Wav:
audioBufferToWav(aBuffer) {
let numOfChan = aBuffer.numberOfChannels,
btwLength = aBuffer.length * numOfChan * 2 + 44,
btwArrBuff = new ArrayBuffer(btwLength),
btwView = new DataView(btwArrBuff),
btwChnls = [],
btwIndex,
btwSample,
btwOffset = 0,
btwPos = 0;
setUint32(0x46464952);
setUint32(btwLength - 8);
setUint32(0x45564157);
setUint32(0x20746d66);
setUint32(16);
setUint16(1);
setUint16(numOfChan);
setUint32(aBuffer.sampleRate);
setUint32(aBuffer.sampleRate * 2 * numOfChan);
setUint16(numOfChan * 2);
setUint16(16);
setUint32(0x61746164);
setUint32(btwLength - btwPos - 4);
for (btwIndex = 0; btwIndex < aBuffer.numberOfChannels; btwIndex++)
btwChnls.push(aBuffer.getChannelData(btwIndex));
while (btwPos < btwLength) {
for (btwIndex = 0; btwIndex < numOfChan; btwIndex++) {
btwSample = Math.max(-1, Math.min(1, btwChnls[btwIndex][btwOffset]));
btwSample = (0.5 + btwSample < 0 ? btwSample * 32768 : btwSample * 32767) | 0;
btwView.setInt16(btwPos, btwSample, true);
btwPos += 2;
}
btwOffset++;
}
let wavHdr = lamejs.WavHeader.readHeader(new DataView(btwArrBuff));
let data = new Int16Array(btwArrBuff, wavHdr.dataOffset, wavHdr.dataLen / 2);
let leftData = [];
let rightData = [];
for (let i = 0; i < data.length; i += 2) {
leftData.push(data[i]);
rightData.push(data[i + 1]);
}
var left = new Int16Array(leftData);
var right = new Int16Array(rightData);
if (AudioFormat === 'MP3')
{
if (wavHdr.channels===2)
return this.wavToMp3Stereo(wavHdr.channels, wavHdr.sampleRate, left,right);
else if (wavHdr.channels===1)
return this.wavToMp3Mono(wavHdr.channels, wavHdr.sampleRate, data);
}
else
return new Blob([btwArrBuff], {type: "audio/wav"});
function setUint16(data) {
btwView.setUint16(btwPos, data, true);
btwPos += 2;
}
function setUint32(data) {
btwView.setUint32(btwPos, data, true);
btwPos += 4;
}
}
Third, convert WAV to MP3:
I had to switch to Stereo as I have 2 channels for MP3Encoder left & right.
wavToMp3(channels, sampleRate, left, right = null) {
var buffer = [];
var mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
var remaining = left.length;
var samplesPerFrame = 1152;
for (var i = 0; remaining >= samplesPerFrame; i += samplesPerFrame) {
if (!right)
{
var mono = left.subarray(i, i + samplesPerFrame);
var mp3buf = mp3enc.encodeBuffer(mono);
}
else {
var leftChunk = left.subarray(i, i + samplesPerFrame);
var rightChunk = right.subarray(i, i + samplesPerFrame);
var mp3buf = mp3enc.encodeBuffer(leftChunk,rightChunk);
}
if (mp3buf.length > 0) {
buffer.push(mp3buf);
}
remaining -= samplesPerFrame;
}
var d = mp3enc.flush();
if(d.length > 0){
buffer.push(new Int8Array(d));
}
var mp3Blob = new Blob(buffer, {type: 'audio/mp3'});
return mp3Blob;
}