我正在尝试将许多Audio BLOB对象的列表合并到单个Audio BLOB中。合并已完成。但是,在收听声音时,Audio BLOB会错误地放在单个BLOB的输出中。
示例:
我已经关注了BLOBs
BLOB-1 (10KB)
BLOB-2 (10KB)
BLOB-3 (10KB)
BLOB-4 (10KB)在合并并开始监听单个Audio之后,上述BLOBs被合并为
BLOB-1 + BLOB-2 + BLOB-4 + BLOB-3如上所述,BLOB-3 and BLOB-4被放错了位置。这种错位以任何顺序发生。
注意:我有更多的100 BLOBs用于合并。
我在JavaScript文件wav_merger.js中编写了以下代码
var _index;
function getBufferFromBlobs(blobArray) {
return new Promise((resolve, reject) => {
var _arrBytes = [];
var _promises = [];
var _completedBlobObj = [];
if (blobArray.length > 0) {
$.each(blobArray, function (index, blobObj) {
_index = index;
var dfd = $.Deferred();
readFileAsync(blobObj).then(function (blobObj) {
_completedBlobObj.push(blobObj);
//_arrBytes.push(byteArray);
dfd.resolve();
});
_promises.push(dfd);
});
$.when.apply($, _promises).done(function () {
var _sortedBlobObjs = _completedBlobObj.sort(compare);
$.each(_sortedBlobObjs, function (index, blobObj) {
_arrBytes.push(blobObj.buffer);
});
var _blob = combineWavsBuffers(_arrBytes);
resolve(_blob);
});
}
});
}
function readFileAsync(blobObj) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
var _blobObj = blobObj;
reader.addEventListener("loadend", function () {
_blobObj.buffer = reader.result;
resolve(_blobObj);
});
reader.onerror = reject;
reader.readAsArrayBuffer(blobObj.blob);
})
}
function loadWav(blobArray) {
return getBufferFromBlobs(blobArray);
debugger;
// .then(function (bufferArray) {
// return combineWavsBuffers(bufferArray); //Combine original wav buffer and play
//});
}
function combineWavsBuffers(bufferArray) {
if (bufferArray.length > 0) {
var _bufferLengths = bufferArray.map(buffer => buffer.byteLength);
// Getting sum of numbers
var _totalBufferLength = _bufferLengths.reduce(function (a, b) {
return a + b;
}, 0);
//Allocate the entire buffer size.
var tmp = new Uint8Array(_totalBufferLength);
//Get buffer1 audio data to create the new combined wav
var audioData = getAudioData.WavHeader.readHeader(new DataView(bufferArray[0]));
var _UbyteArray = [];
$.each(bufferArray, function (index, buffer) {
_UbyteArray.push(new Uint8Array(buffer));
});
var _bufferLength = 0;
$.each(_UbyteArray, function (index, buffer) {
//Combine array bytes of original wavs buffers.
tmp.set(buffer, _bufferLength);
_bufferLength += buffer.byteLength;
});
//Send combined buffer and send audio data to create the audio data of combined
var arrBytesFinal = getWavBytes(tmp, {
isFloat: false, // floating point or 16-bit integer
numChannels: audioData.channels,
sampleRate: audioData.sampleRate,
});
//Create a Blob as Base64 Raw data with audio/wav type
return new Blob([arrBytesFinal], { type: 'audio/wav; codecs=MS_PCM' });//
}
return null;
}
//Other functions //////////////////////////////////////////////////////////////
// Returns Uint8Array of WAV bytes
function getWavBytes(buffer, options) {
const type = options.isFloat ? Float32Array : Uint16Array
const numFrames = buffer.byteLength / type.BYTES_PER_ELEMENT
const headerBytes = getWavHeader(Object.assign({}, options, { numFrames }))
const wavBytes = new Uint8Array(headerBytes.length + buffer.byteLength);
// prepend header, then add pcmBytes
wavBytes.set(headerBytes, 0)
wavBytes.set(new Uint8Array(buffer), headerBytes.length)
return wavBytes
}
// adapted from https://gist.github.com/also/900023
// returns Uint8Array of WAV header bytes
function getWavHeader(options) {
const numFrames = options.numFrames
const numChannels = options.numChannels || 2
const sampleRate = options.sampleRate || 44100
const bytesPerSample = options.isFloat ? 4 : 2
const format = options.isFloat ? 3 : 1
const blockAlign = numChannels * bytesPerSample
const byteRate = sampleRate * blockAlign
const dataSize = numFrames * blockAlign
const buffer = new ArrayBuffer(44)
const dv = new DataView(buffer)
let p = 0
function writeString(s) {
for (let i = 0; i < s.length; i++) {
dv.setUint8(p + i, s.charCodeAt(i))
}
p += s.length
}
function writeUint32(d) {
dv.setUint32(p, d, true)
p += 4
}
function writeUint16(d) {
dv.setUint16(p, d, true)
p += 2
}
writeString('RIFF') // ChunkID
writeUint32(dataSize + 36) // ChunkSize
writeString('WAVE') // Format
writeString('fmt ') // Subchunk1ID
writeUint32(16) // Subchunk1Size
writeUint16(format) // AudioFormat
writeUint16(numChannels) // NumChannels
writeUint32(sampleRate) // SampleRate
writeUint32(byteRate) // ByteRate
writeUint16(blockAlign) // BlockAlign
writeUint16(bytesPerSample * 8) // BitsPerSample
writeString('data') // Subchunk2ID
writeUint32(dataSize) // Subchunk2Size
return new Uint8Array(buffer)
}
function getAudioData() {
function WavHeader() {
this.dataOffset = 0;
this.dataLen = 0;
this.channels = 0;
this.sampleRate = 0;
}
function fourccToInt(fourcc) {
return fourcc.charCodeAt(0) << 24 | fourcc.charCodeAt(1) << 16 | fourcc.charCodeAt(2) << 8 | fourcc.charCodeAt(3);
}
WavHeader.RIFF = fourccToInt("RIFF");
WavHeader.WAVE = fourccToInt("WAVE");
WavHeader.fmt_ = fourccToInt("fmt ");
WavHeader.data = fourccToInt("data");
WavHeader.readHeader = function (dataView) {
var w = new WavHeader();
var header = dataView.getUint32(0, false);
if (WavHeader.RIFF != header) {
return;
}
var fileLen = dataView.getUint32(4, true);
if (WavHeader.WAVE != dataView.getUint32(8, false)) {
return;
}
if (WavHeader.fmt_ != dataView.getUint32(12, false)) {
return;
}
var fmtLen = dataView.getUint32(16, true);
var pos = 16 + 4;
switch (fmtLen) {
case 16:
case 18:
w.channels = dataView.getUint16(pos + 2, true);
w.sampleRate = dataView.getUint32(pos + 4, true);
break;
default:
throw 'extended fmt chunk not implemented';
}
pos += fmtLen;
var data = WavHeader.data;
var len = 0;
while (data != header) {
header = dataView.getUint32(pos, false);
len = dataView.getUint32(pos + 4, true);
if (data == header) {
break;
}
pos += (len + 8);
}
w.dataLen = len;
w.dataOffset = pos + 8;
return w;
};
getAudioData.WavHeader = WavHeader;
}
function compare(a, b) {
try {
if (a.audio_recording_id < b.audio_recording_id) {
return -1;
}
if (a.audio_recording_id > b.audio_recording_id) {
return 1;
}
return 0;
} catch (e) {
FDSCS.CORE.Logger.Log("compare()", e);
}
}
getAudioData();我怀疑Uint8Array().set()方法。但是,它也可以是任何其他问题。
var _bufferLength = 0;
$.each(_UbyteArray, function (index, buffer) {
//Combine array bytes of original wavs buffers.
tmp.set(buffer, _bufferLength);
_bufferLength += buffer.byteLength;
});我不知道我该为这个错位做些什么。如何解决这个问题,这样,Audio才能流畅地播放。
发布于 2021-06-23 03:44:42
我想这个问题可能是由于这个原因。
$.each(blobArray, function (index, blobObj) {
_index = index;
var dfd = $.Deferred();
readFileAsync(blobObj).then(function (blobObj) {
_completedBlobObj.push(blobObj);
//_arrBytes.push(byteArray);
dfd.resolve();
});
_promises.push(dfd);
});您使用的是readFileAsync,它将并行读取文件,并且不能保证以相同的顺序读取文件(并解析promises )。
您可以通过两种方式处理它,要么使用同步(阻塞)进程,要么存储索引
// use obj instead of array
_completedBlobObj = {};
///
$.each(blobArray, function (index, blobObj) {
_index = index;
var dfd = $.Deferred();
readFileAsync(blobObj).then(function (blobObj) {
// use _index to store order
_completedBlobObj[_index] = (blobObj);
dfd.resolve();
});
_promises.push(dfd);
});https://stackoverflow.com/questions/68089737
复制相似问题