lamejs的使用

    技术2022-07-13  57

    lamejs的简单使用

    lamejs是一个用JS重写的mp3编码器。lamejs是对jump3r-code的重写,而后者是对libmp3lame的重写。

    github项目地址:https://github.com/zhuker/lamejs

    一、快速上手

    先看一个简单的例子:

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>example</title> </head> <body> <script src="lame.all.js"></script> <script> // channelNum {Number} 声道数 // sampleRate {Number} PCM数据的采样率 // samples {int16Array} 16位有符号的PCM数据 function encodeMono (channelNum, sampleRate, samples) { var buffer = []; // 128是指输出的MP3音频的比特率bitrate,单位是kbps var mp3enc = new lamejs.Mp3Encoder(channelNum, sampleRate, 128); var remaining = samples.length; var maxSamples = 1152; for (var i = 0; remaining >= maxSamples; i += maxSamples) { var mono = samples.subarray(i, i + maxSamples); var mp3buf = mp3enc.encodeBuffer(mono); if (mp3buf.length > 0) { buffer.push(new Int8Array(mp3buf)); } remaining -= maxSamples; } var flushData = mp3enc.flush(); if(flushData.length > 0){ buffer.push(new Int8Array(flushData)); } // 播放编码后的MP3 console.log('done encoding, size=', buffer.length); var blob = new Blob(buffer, {type: 'audio/mp3'}); var bUrl = window.URL.createObjectURL(blob); console.log('Blob created, URL:', bUrl); window.myAudioPlayer = document.createElement('audio'); window.myAudioPlayer.src = bUrl; window.myAudioPlayer.setAttribute('controls', ''); window.myAudioPlayer.play(); } var url = "http://localhost/data/demo.pcm"; var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.responseType = "arraybuffer"; xhr.onload = function () { var samples = new Int16Array(xhr.response); encodeMono(1, 44100, samples); }; xhr.send(); </script> </body> </html>

    我们还可以通过npm安装lamejs:

    npm install lamejs

    对应的引入方法如下:

    var lamejs = require("lamejs"); // 也可以使用别的方法

    对于上面提供的例子中,比较关键的信息是以下两点:

    PCM数据的采样率、声道数编码后MP3的比特率

    例子中提供的PCM数据是单声道,采样率为44100Hz,编码后MP3的比特率为128kbps。一般来说,比特率越高,传送的数据越大,MP3的音质越好。lamejs提供的最低比特率是8kbps,最大为320kbps,默认值为128kbps。

    如果编码后的MP3进行播放时,声音是低沉冗长的,或者是刺耳的,极有可能是PCM的采样率或者声道数设置有问题。

    二、双声道编码

    上面的例子中,是对单声道的PCM数据进行编码。如果想要编码双声道,那么需要对PCM数据进行左右声道分离。双声道的PCM数据通常采用交错立体声的方式进行存储,假设PCM中每一个量化样本为16位,编码步骤大致如下:

    // pcm {int16Array} 16位有符号的双声道PCM数据 function encodeStereo(pcm) { var leftChunk = pcm.filter(function (element, index, array) { return index % 2 === 0; }); var rightChunk = pcm.filter(function (element, index, array) { return index % 2; }); var mp3Buffer = mp3Encoder.encodeBuffer(leftChunk, rightChunk); return mp3Buffer; }

    需要注意的是leftChunk、rightChunk的长度要保持一致。lamejs在编码执行encodeBuffer时,会对创建编码器时输入的声道数channelNum进行判断,如果是单声道,那么rightChunk将被赋值为leftChunk:

    function encoderBuffer (leftChunk, rightChunk) { if (channelNum === 1) { rightChunk = leftChunk; } // 忽略剩余的代码 }

    三、WAV转MP3

    WAV是一种无损的音频文件格式,其结构示意图如下图所示。 因为lamejs编码输入的是PCM数据,所以我们需要去掉WAV头部信息,得到PCM数据才能进行编码。lamejs已经提供了相应的解析方法。结合上面的例子,假设请求的是WAV文件,使用WavHeader.readHeader可以解析WAV文件的头部,得到声道数和采样率,以及PCM数据的偏移位置:

    var audioData = request.response; var wav = lamejs.WavHeader.readHeader(new DataView(audioData)); var samples = new Int16Array(audioData, wav.dataOffset, wav.dataLen / 2); encodeMono(wav.channels, wav.sampleRate, samples);

    以此类推,其他格式的音频数据使用lamejs转成MP3,可以先转为PCM数据,再进行MP3编码就可以实现了。

    Processed: 0.009, SQL: 9