一、前言
因為業(yè)務(wù)有這個需求哟玷,之前一直在網(wǎng)上沒有找到好的方法狮辽,搜索了很多的方法及資料才完成,最終用時一坤天巢寡;首先喉脖,需要知道的一些信息:
1、AMR抑月,全稱為Adaptive Multi-Rate(自適應(yīng)多速率)动看,主要用于移動設(shè)備上的音頻壓縮編碼標準。這種格式的音質(zhì)通常較差爪幻,但其壓縮比非常高,特別適用于語音類的音頻壓縮须误,如通話和人聲錄音挨稿。
2、AMR文件格式分為兩種:AMR-NB和AMR-WB【 記住它們的采樣頻率京痢,后面要考 : ) 】
- AMR-NB(AMR-NarrowBind):語音帶寬范圍:300 - 3700Hz奶甘,8KHz采樣頻率;
- AMR-WB(AMR-WideBand):語音帶寬范圍50 - 7000Hz祭椰,16KHz采樣頻率臭家;
3、AMR文件一般為錄音文件方淤,并不能直接放在audio標簽上播放钉赁;
二、解決思路
既然不能直接放在audio標簽上播放携茂,那就轉(zhuǎn)換格式你踩,那怎么轉(zhuǎn)換呢?哎~讳苦,有這么一個庫amrnb.js是處理amr格式的带膜,里面有個方法toWAV,沒錯就是你想的那樣鸳谜,就是把amr格式轉(zhuǎn)為wav格式的膝藕,看代碼是處理為Uint8Array數(shù)據(jù),那么用這個Uint8Array數(shù)據(jù)生成一個Blob對象咐扭,在使用URL.createObjectURL(blob)生成一個臨時地址放在audio標簽上不就行了芭挽,思路方法已有滑废,開始實現(xiàn)。
三览绿、實現(xiàn)
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數(shù)據(jù)轉(zhuǎn)為Uint8Array才能調(diào)用AMR.toWAV將arm格式轉(zhuǎn)換為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轉(zhuǎn)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),查看它們的二進制文件頭你會發(fā)現(xiàn)只能播放 #!AMR 的不能播放#!AMR-WB的瓢对,也就是說amrnb.js庫只支持AMR-NB格式的amr文件寿酌,不支持AMR-WB的。
五硕蛹、amrwb-js庫
一頓搜索后醇疼,發(fā)現(xiàn)一個amrwb-js庫,但里面沒有toWAV的方法法焰,其他的解碼秧荆、加密方法都有,名稱都一樣埃仪,那能不能用amrnb.js庫的toWAV方法呢乙濒,我復(fù)制拿來試了一下,不行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轉(zhuǎn)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轉(zhuǎn)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)
}