Marco86
Marco86

Reputation: 41

Lamejs exports mp3 compressed audio file with no sound

I have to export an AudioBuffer object to mp3 compressed file, in javascript, but the output has no sound.

lamejs is not outputting any audible sound: this is a duplicate, but no answer and I can't add a comment for ask if it's solved (need 50 reputation).

I use the same library, but I found a new maintained version, that fixes some bugs: https://github.com/shijinyu/lamejs

I can export the AudioBuffer in wav file. It works very well.

https://github.com/zhuker/lamejs/issues/68: here he says that encoder accepts PCM audio only. So I call getChannelData function (Web Audio API) from the AudioBuffer source.

// 2 channels
async encodeAudioBufferLame(audioBuffer) {

    var mp3encoder = new Mp3Encoder(2, 44100, 128);

    var mp3Data = [];

    const [left, right] =  [audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)];

    const sampleBlockSize = 1152; //can be anything but make it a multiple of 576 to make encoders life easier

    for (var i = 0; i < left.length; i += sampleBlockSize) {
        const leftChunk = left.subarray(i, i + sampleBlockSize);
        const rightChunk = right.subarray(i, i + sampleBlockSize);

        var mp3buf = mp3encoder.encodeBuffer(leftChunk, rightChunk);

        if (mp3buf.length > 0) {
            mp3Data.push(mp3buf);
        }
    }
    var mp3buf = mp3encoder.flush();   //finish writing mp3

    if (mp3buf.length > 0) {
            mp3Data.push(mp3buf);
    }

    return mp3Data;

}

And then:

const mp3Data = await encodeAudioBufferLame(audioBuffer);
const blob = new Blob(mp3Data, {type: 'audio/mp3'});
const url = window.URL.createObjectURL(blob);


const downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.setAttribute('download', `myAudio.mp3`);
downloadLink.click();

The output result has same original duration/length, but no sound. My sound card is good and the audio desktop is on.

I tried other libraries too, but I encountered other bugs.

All help is really appreciated!!

Upvotes: 0

Views: 591

Answers (1)

Marco86
Marco86

Reputation: 41

Great!! Thanks to James, who found a link with solution (see comment).

The solution:

async encodeAudioBufferLame(audioBuffer) {

        var mp3encoder = new Mp3Encoder(2, audioBuffer.sampleRate, 128); // 44100 is replaced. It needs the real AudioBuffer sample rate. In my test case 48000.

        var mp3Data = [];

        const [left, right] =  [audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)];

        // The transformed data, this is what you will pass to lame instead
        // If you are sure to use a Float32Array you can skip this and use [left, right] const.
        const l = new Float32Array(left.length); 
        const r = new Float32Array(right.length);

        //Convert to required format
        for(var i=0;i<left.length;i++) {
                l[i] = left[i]*32767.5;
                r[i] = right[i]*32767.5;
        }

        const sampleBlockSize = 1152; //can be anything but make it a multiple of 576 to make encoders life easier

        for (var i = 0; i < l.length; i += sampleBlockSize) {
            const leftChunk = l.subarray(i, i + sampleBlockSize);
            const rightChunk = r.subarray(i, i + sampleBlockSize);

            var mp3buf = mp3encoder.encodeBuffer(leftChunk, rightChunk);

            if (mp3buf.length > 0) {
                mp3Data.push(mp3buf);
            }
        }
        var mp3buf = mp3encoder.flush();   //finish writing mp3

        if (mp3buf.length > 0) {
                mp3Data.push(mp3buf);
        }

        return mp3Data;

    }

Thanks a lot James!!

I can't vote your comment, maybe for my poor reputation.

Upvotes: 3

Related Questions