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编码就可以实现了。