一、前言
因为业务有这个需求,之前一直在网上没有找到好的方法,搜索了很多的方法及资料才完成,最终用时一坤天;首先,需要知道的一些信息:
1、AMR,全称为Adaptive Multi-Rate(自适应多速率),主要用于移动设备上的音频压缩编码标准。这种格式的音质通常较差,但其压缩比非常高,特别适用于语音类的音频压缩,如通话和人声录音。
2、AMR文件格式分为两种:AMR-NB和AMR-WB【 记住它们的采样频率,后面要考 : ) 】
- AMR-NB(AMR-NarrowBind):语音带宽范围:300 - 3700Hz,8KHz采样频率;
- AMR-WB(AMR-WideBand):语音带宽范围50 - 7000Hz,16KHz采样频率;
3、AMR文件一般为录音文件,并不能直接放在audio标签上播放;
二、解决思路
既然不能直接放在audio标签上播放,那就转换格式,那怎么转换呢?哎~,有这么一个库amrnb.js是处理amr格式的,里面有个方法toWAV,没错就是你想的那样,就是把amr格式转为wav格式的,看代码是处理为Uint8Array数据,那么用这个Uint8Array数据生成一个Blob对象,在使用URL.createObjectURL(blob)生成一个临时地址放在audio标签上不就行了,思路方法已有,开始实现。
三、实现
1、HTML代码
引入amrnb.js库
<script src="js/amrjs/amrnb.js"></script>
通过文件上传获取文件
<div>
<input type="file" onchange="fileChange(event)" accept=".mp3,.wav,.ogg,.amr,.m4a">
</div>
<audio id="audio" src="" controls></audio>
2、JavaScript代码
用FileReader读取为ArrayBuffer数据转为Uint8Array才能调用AMR.toWAV将arm格式转换为wav格式:
function fileChange(e) {
const file = e.target.files[0]
const audioElement = document.getElementById('audio')
if (!file) {
audioElement.src = ''
return
}
const reader = new FileReader()
reader.onload = function(e) {
if (file.name.indexOf('.amr') !== -1) {
const data = new Uint8Array(e.target.result);
const buffer = AMR.toWAV(data) // amr转wav
const url = URL.createObjectURL(new Blob([buffer], {
type: 'audio/x-wav'
}))
audioElement.src = url
} else {
const buffer = e.target.result
const url = URL.createObjectURL(new Blob([buffer], {
type: 'audio/x-wav'
}))
audioElement.src = url
}
}
reader.readAsArrayBuffer(file)
}
四、完全解决了?
不,只解决了一半,有些.amr文件播放不了,之前说过AMR文件格式有两种:AMR-NB(#!AMR)和AMR-WB(#!AMR-WB),查看它们的二进制文件头你会发现只能播放 #!AMR 的不能播放#!AMR-WB的,也就是说amrnb.js库只支持AMR-NB格式的amr文件,不支持AMR-WB的。
五、amrwb-js库
一顿搜索后,发现一个amrwb-js库,但里面没有toWAV的方法,其他的解码、加密方法都有,名称都一样,那能不能用amrnb.js库的toWAV方法呢,我复制拿来试了一下,不行o(╥﹏╥)o。
正当我一筹莫展时,搜索里有个AMR-NB和AMR-WB的介绍引起了我的注意,还记得之前让你们记住他们的采样频率吗,8KHz、16KHz,再仔细看了一下toWAV方法里有个变量sample_rate = 8e3,难道......马上啊,很快我把变量值改为sample_rate = 16e3,waoo~ amazing OK了,难我天!
六、JavaScript最终代码
<script src="js/amrjs/amrnb.js"></script>
<script src="js/amrjs/amrwb.js"></script>
<script src="js/amrjs/amrwb-util.js"></script>
function fileChange(e) {
const file = e.target.files[0]
const audioElement = document.getElementById('audio')
if (!file) {
audioElement.src = ''
return
}
const reader = new FileReader()
reader.onload = function(e) {
if (file.name.indexOf('.amr') !== -1) {
const data = new Uint8Array(e.target.result);
if (AMRWB.getAMRHeader(data) === AMRWB.AMR_HEADER) {
// #!AMR-WB文件头
AMRWB.decodeInit()
const buffer = AMRWB.toWAV(data) // amr转wav
AMRWB.decodeExit()
const url = URL.createObjectURL(new Blob([buffer], {
type: 'audio/wav'
}))
audioElement.src = url
} else if (AMR.getAMRHeader(data) === AMR.AMR_HEADER){
// #!AMR文件头
const buffer = AMR.toWAV(data) // amr转wav
const url = URL.createObjectURL(new Blob([buffer], {
type: 'audio/x-wav'
}))
audioElement.src = url
} else {
alert('文件格式不支持!')
}
} else {
const buffer = e.target.result
const url = URL.createObjectURL(new Blob([buffer], {
type: 'audio/x-wav'
}))
audioElement.src = url
}
}
reader.readAsArrayBuffer(file)
}