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編碼就可以實現了。