0

这是两个音频文件(.MP3)。A.mp3 & B.mp3 我想用 JavaScript 合成这些文件 (A & B) 并保存一个文件 (C)。请帮我。

4

1 回答 1

0

所以基本上 

  1. 创建离线音频上下文
  2. 为您的音轨创建两个音频缓冲区
  3. 获取音轨并将其转换为音频缓冲区
  4. 您可以添加到链增益节点(或您需要的)
  5. 将此连接到上下文目标
  6. 渲染音频 - 你得到 audioBuffer
  7. 将音频缓冲区转换为 wav/mp3 

你可以在这里找到一些帮助How to Convert an AudioBuffer to an Audio File with JavaScript and Stack

const context = new OfflineAudioContext();
const sourceA = context.createBufferSource();
const sourceB = context.createBufferSource();

const gainA = context.createGain()
const gainB = context.createGain();


sourceA.connect(gainA);
sourceB.connect(gainB);

gainA.connect(context.destination);
gainB.connect(context.destination);

const fetchTrack = async url => {
    const response = await fetch(url);
    const buffer = await response.arrayBuffer();
    return await context.decodeAudioData(buffer)
}

const audioBuffer = await Promise.all([fetchTrack("urlA", "urlB")])
    .then(([bufferA, bufferB]) => {
        sourceA.buffer = bufferA;
        sourceB.buffer = bufferB;
    })
    .then(() => {
        return context.startRendering()
    })

audioBufferToWav(audioBuffer)

从教程:

function 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); // "RIFF"
    setUint32(btwLength - 8); // file length - 8
    setUint32(0x45564157); // "WAVE"
    setUint32(0x20746d66); // "fmt " chunk
    setUint32(16); // length = 16
    setUint16(1); // PCM (uncompressed)
    setUint16(numOfChan);
    setUint32(aBuffer.sampleRate);
    setUint32(aBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
    setUint16(numOfChan * 2); // block-align
    setUint16(16); // 16-bit
    setUint32(0x61746164); // "data" - chunk
    setUint32(btwLength - btwPos - 4); // chunk length

    for (btwIndex = 0; btwIndex < aBuffer.numberOfChannels; btwIndex++)
        btwChnls.push(aBuffer.getChannelData(btwIndex));

    while (btwPos < btwLength) {
        for (btwIndex = 0; btwIndex < numOfChan; btwIndex++) {
            // interleave btwChnls
            btwSample = Math.max(-1, Math.min(1, btwChnls[btwIndex][btwOffset])); // clamp
            btwSample = (0.5 + btwSample < 0 ? btwSample * 32768 : btwSample * 32767) | 0; // scale to 16-bit signed int
            btwView.setInt16(btwPos, btwSample, true); // write 16-bit sample
            btwPos += 2;
        }
        btwOffset++; // next source sample
    }

    let wavHdr = lamejs.WavHeader.readHeader(new DataView(btwArrBuff));
    let wavSamples = new Int16Array(btwArrBuff, wavHdr.dataOffset, wavHdr.dataLen / 2);

    wavToMp3(wavHdr.channels, wavHdr.sampleRate, wavSamples);

    function setUint16(data) {
        btwView.setUint16(btwPos, data, true);
        btwPos += 2;
    }

    function setUint32(data) {
        btwView.setUint32(btwPos, data, true);
        btwPos += 4;
    }
}


function wavToMp3(channels, sampleRate, samples) {
    var buffer = [];
    var mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
    var remaining = samples.length;
    var samplesPerFrame = 1152;
    for (var i = 0; remaining >= samplesPerFrame; i += samplesPerFrame) {
        var mono = samples.subarray(i, i + samplesPerFrame);
        var mp3buf = mp3enc.encodeBuffer(mono);
        if (mp3buf.length > 0) {
            buffer.push(new Int8Array(mp3buf));
        }
        remaining -= samplesPerFrame;
    }
    var d = mp3enc.flush();
    if(d.length > 0){
        buffer.push(new Int8Array(d));
    }

    var mp3Blob = new Blob(buffer, {type: 'audio/mp3'});
    var bUrl = window.URL.createObjectURL(mp3Blob);

    // send the download link to the console
    console.log('mp3 download:', bUrl);

}
于 2020-12-07T14:44:40.517 回答