Как преобразовать AudioBuffer в файл WAV?
Я пытаюсь преобразовать AudioBuffer в файл WAV, который я могу скачать. Я попробовал 2 метода: первый, я записываю все звуки, которые бросил mediaRecorder и делаю это:
App.model.mediaRecorder.ondataavailable = function(evt) {
// push each chunk (blobs) in an array
//console.log(evt.data)
App.model.chunks.push(evt.data);
};
App.model.mediaRecorder.onstop = function(evt) {
// Make blob out of our blobs, and open it.
var blob = new Blob(App.model.chunks, { 'type' : 'audio/wav; codecs=opus' });
createDownloadLink(blob);
};
Я создаю таблицу чанков, содержащую BLOB-объекты, а затем создаю новый BLOB-объект с этими чанками. Затем в функции "createDownloadLink()" я создаю аудио узел и ссылку для скачивания:
function createDownloadLink(blob) {
var url = URL.createObjectURL(blob);
var li = document.createElement('li');
var au = document.createElement('audio');
li.className = "recordedElement";
var hf = document.createElement('a');
li.style.textDecoration ="none";
au.controls = true;
au.src = url;
hf.href = url;
hf.download = 'myrecording' + App.model.countRecordings + ".wav";
hf.innerHTML = hf.download;
li.appendChild(au);
li.appendChild(hf);
recordingslist.appendChild(li);
}
Аудио узел создан, и я могу слушать звук, который записал, так что все, кажется, работает. Но когда я загружаю файл, он не может быть прочитан ни одним плеером. Я думаю, что это потому, что он не закодирован в WAV, поэтому он не понимает.
Второй метод такой же, как и выше, за исключением функции "createDownloadLink()".
function createDownloadLink(blob) {
var reader = new FileReader();
reader.readAsArrayBuffer(blob);
App.model.sourceBuffer = App.model.audioCtx.createBufferSource();
reader.onloadend = function()
{
App.model.recordBuffer = reader.result;
App.model.audioCtx.decodeAudioData(App.model.recordBuffer, function(decodedData)
{
App.model.sourceBuffer.buffer = decodedData;
})
}
Здесь я получаю AudioBuffer звуков, которые я записал, но я не нашел, как преобразовать его в файл WAV...
1 ответ
Можете ли вы использовать вариант этого? https://gist.github.com/asanoboy/3979747
Может как то так?
var wav = createWavFromBuffer(convertBlock(decodedData), 44100);
// Then call wav.getBuffer or wav.getWavInt16Array() for the WAV-RIFF formatted data
Другие функции здесь:
class Wav {
constructor(opt_params) {
this._sampleRate = opt_params && opt_params.sampleRate ? opt_params.sampleRate : 44100;
this._channels = opt_params && opt_params.channels ? opt_params.channels : 2;
this._eof = true;
this._bufferNeedle = 0;
this._buffer;
}
setBuffer(buffer) {
this._buffer = this.getWavInt16Array(buffer);
this._bufferNeedle = 0;
this._internalBuffer = '';
this._hasOutputHeader = false;
this._eof = false;
}
getBuffer(len) {
var rt;
if( this._bufferNeedle + len >= this._buffer.length ){
rt = new Int16Array(this._buffer.length - this._bufferNeedle);
this._eof = true;
}
else {
rt = new Int16Array(len);
}
for(var i=0; i<rt.length; i++){
rt[i] = this._buffer[i+this._bufferNeedle];
}
this._bufferNeedle += rt.length;
return rt.buffer;
}
eof() {
return this._eof;
}
getWavInt16Array(buffer) {
var intBuffer = new Int16Array(buffer.length + 23), tmp;
intBuffer[0] = 0x4952; // "RI"
intBuffer[1] = 0x4646; // "FF"
intBuffer[2] = (2*buffer.length + 15) & 0x0000ffff; // RIFF size
intBuffer[3] = ((2*buffer.length + 15) & 0xffff0000) >> 16; // RIFF size
intBuffer[4] = 0x4157; // "WA"
intBuffer[5] = 0x4556; // "VE"
intBuffer[6] = 0x6d66; // "fm"
intBuffer[7] = 0x2074; // "t "
intBuffer[8] = 0x0012; // fmt chunksize: 18
intBuffer[9] = 0x0000; //
intBuffer[10] = 0x0001; // format tag : 1
intBuffer[11] = this._channels; // channels: 2
intBuffer[12] = this._sampleRate & 0x0000ffff; // sample per sec
intBuffer[13] = (this._sampleRate & 0xffff0000) >> 16; // sample per sec
intBuffer[14] = (2*this._channels*this._sampleRate) & 0x0000ffff; // byte per sec
intBuffer[15] = ((2*this._channels*this._sampleRate) & 0xffff0000) >> 16; // byte per sec
intBuffer[16] = 0x0004; // block align
intBuffer[17] = 0x0010; // bit per sample
intBuffer[18] = 0x0000; // cb size
intBuffer[19] = 0x6164; // "da"
intBuffer[20] = 0x6174; // "ta"
intBuffer[21] = (2*buffer.length) & 0x0000ffff; // data size[byte]
intBuffer[22] = ((2*buffer.length) & 0xffff0000) >> 16; // data size[byte]
for (var i = 0; i < buffer.length; i++) {
tmp = buffer[i];
if (tmp >= 1) {
intBuffer[i+23] = (1 << 15) - 1;
}
else if (tmp <= -1) {
intBuffer[i+23] = -(1 << 15);
}
else {
intBuffer[i+23] = Math.round(tmp * (1 << 15));
}
}
return intBuffer;
}
}
// factory
function createWavFromBuffer(buffer, sampleRate) {
var wav = new Wav({
sampleRate: sampleRate,
channels: 1
});
wav.setBuffer(buffer);
return wav;
}
// ArrayBuffer -> Float32Array
var convertBlock = function(buffer) {
var incomingData = new Uint8Array(buffer);
var i, l = incomingData.length;
var outputData = new Float32Array(incomingData.length);
for (i = 0; i < l; i++) {
outputData[i] = (incomingData[i] - 128) / 128.0;
}
return outputData;
}