首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Uint8Array对象-合并时放错了位置

Uint8Array对象-合并时放错了位置
EN

Stack Overflow用户
提问于 2021-06-23 03:32:15
回答 1查看 29关注 0票数 1

我正在尝试将许多Audio BLOB对象的列表合并到单个Audio BLOB中。合并已完成。但是,在收听声音时,Audio BLOB会错误地放在单个BLOB的输出中。

示例:

我已经关注了BLOBs

代码语言:javascript
复制
BLOB-1 (10KB)
BLOB-2 (10KB)
BLOB-3 (10KB)
BLOB-4 (10KB)

在合并并开始监听单个Audio之后,上述BLOBs被合并为

代码语言:javascript
复制
BLOB-1 + BLOB-2 + BLOB-4 + BLOB-3

如上所述,BLOB-3 and BLOB-4被放错了位置。这种错位以任何顺序发生。

注意:我有更多的100 BLOBs用于合并。

我在JavaScript文件wav_merger.js中编写了以下代码

代码语言:javascript
复制
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()方法。但是,它也可以是任何其他问题。

代码语言:javascript
复制
 var _bufferLength = 0;
        $.each(_UbyteArray, function (index, buffer) {
            //Combine array bytes of original wavs buffers.
            tmp.set(buffer, _bufferLength);
            _bufferLength += buffer.byteLength;
        });

我不知道我该为这个错位做些什么。如何解决这个问题,这样,Audio才能流畅地播放。

EN

回答 1

Stack Overflow用户

发布于 2021-06-23 03:44:42

我想这个问题可能是由于这个原因。

代码语言:javascript
复制
$.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 )。

您可以通过两种方式处理它,要么使用同步(阻塞)进程,要么存储索引

代码语言:javascript
复制
// 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);
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68089737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档