Anatoliy
Anatoliy

Reputation: 1

How to synthesis multi audio files to one audio file(MP3) and save it with JavaScript

Here are two audio files(.MP3). A.mp3 & B.mp3 I want to synthesis these files(A & B) using JavaScript and save one file(C). Please help me.

Upvotes: 0

Views: 241

Answers (1)

Robert
Robert

Reputation: 2753

So basically 

  1. Create offline audio context
  2. Create two audio buffer for your track
  3. Fetch track and convert it to audio buffer
  4. You can add to chain gain nodes (or what you need)
  5. Connect this to context destination
  6. Render audio - you get audioBuffer
  7. Convert audio buffer to wav/mp3 

You can find some help here 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)

And from tutorial:

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);

}

Upvotes: 1

Related Questions