如何在JavaScript中将PCM数据编码为MP3?

Raj*_*ajV 5 javascript mp3 html5-audio web-audio-api

我正在使用Recorder.js来录制麦克风的音频.该库可以在WAV中编码PCM数据,我可以使用它成功地播放它<audio>.但是,由此产生的WAV数据太大(5分钟录制时约为38MB).我尝试使用Speech-to-Server提供的libmp3lame.js .

recorderWorker.js,我正在导入Lame脚本:

importScripts("libmp3lame.js");
Run Code Online (Sandbox Code Playgroud)

然后,我改变了exportWAV()将PCM缓冲区编码为MP3而不是WAV的功能.

function exportWAV(type){
    var bufferL = mergeBuffers(recBuffersL, recLength);
    var bufferR = mergeBuffers(recBuffersR, recLength);
    //var interleaved = interleave(bufferL, bufferR);

    console.log("Start MP3 encoding");
    var mp3codec = Lame.init();
    Lame.set_mode(mp3codec, Lame.JOINT_STEREO);
    Lame.set_num_channels(mp3codec, 2);
    Lame.set_out_samplerate(mp3codec, sampleRate);
    Lame.set_bitrate(mp3codec, 128);
    Lame.init_params(mp3codec);

    var mp3data = Lame.encode_buffer_ieee_float(mp3codec, bufferL, bufferR);
    audioBlob = new Blob([mp3data.data], { type: "audio/mp3" });
    console.log("Done MP3 encoding");

    this.postMessage(audioBlob);
}
Run Code Online (Sandbox Code Playgroud)

但是,该Lame.encode_buffer_ieee_float方法抛出了这个错误:

Uncaught RangeError: Invalid array buffer length 
Run Code Online (Sandbox Code Playgroud)

这里的PCM数据是bufferLbufferRFloat32Array.我无法确定Lame.encode_buffer_ieee_float到底需要什么作为输入.

Lame.encode_buffer_ieee_float抛出错误的违规行是:

var arraybuf = new ArrayBuffer(nread);
Run Code Online (Sandbox Code Playgroud)

我放了一个断点并检查了它的值nread.它是-1.

所以,我的问题是如何在这种情况下使用Lame MP3 JavaScript库?谢谢.

小智 6

有一个用纯javascript编写的库,叫做lamejs.它比libmp3lame的emscripten编译快得多. https://github.com/zhuker/lamejs

用法示例:

lib = new lamejs();
mp3encoder = new lib.Mp3Encoder(1, 44100, 128); //mono 44.1khz encode to 128kbps
samples = new Int16Array(44100); //one second of silence
var mp3 = mp3encoder.encodeBuffer(samples); //encode mp3
Run Code Online (Sandbox Code Playgroud)


Kev*_*nis 2

我现在没有太多时间,所以我实际上无法下载库并进行测试,但我首先在此行之后放置一个断点:

var nread = Module.ccall('lame_encode_buffer_ieee_float', 'number', [ 'number', 'number', 'number', 'number', 'number', 'number' ], [ handle, inbuf_l, inbuf_r, channel_l.length, outbuf, BUFSIZE ])libmp3lame.js

然后设置一个监视表达式nreadvar arraybuf = new ArrayBuffer(nread);您想查看该值是多少,因为我很确定抛出的是下一行 ( )。

这至少可以让您了解正在发生的事情。

我还注意到该encode_buffer_ieee_float方法内部假设BUFSIZE = 8192. 我不完全确定这是否重要,但它让我想知道这种方法是否实际上仅用作编码单个 Mp3 帧而不是任意长度的缓冲区的方法。

不管怎样,如果你能看到 的价值是什么nread,那至少应该让你走上正确的道路,弄清楚正在发生什么。但看起来第二个和第三个参数肯定是Float32Arrays,所以我不认为你发送了错误类型的参数。

  • 我查看了 lame C 源代码,并跟踪问题确实是发送到 lame_encode_buffer_ieee_float 的非常小的缓冲区大小。我通过将 BUFSIZE 设置为 channel_l.length * 4 解决了该问题。现在,编码适用于短音频剪辑。但是,对于较大的剪辑再次失败。 (2认同)