在android中, 通過(guò)AudioRecord
獲取到音頻數(shù)據(jù)是PCM
格式的, 但是有時(shí)候我們需要的可能是更常見的WAV
格式, 此時(shí)我們就需要手動(dòng)把PCM
數(shù)據(jù)轉(zhuǎn)成WAV
.
對(duì)于PCM
和WAV
的其他信息我就不搬運(yùn)了, 本文僅關(guān)注
從
PCM
的byte數(shù)組得到WAV
的byte數(shù)組.
PCM
和WAV
的關(guān)系
簡(jiǎn)單地說(shuō), PCM
是音頻的原始數(shù)據(jù), WAV
則是一種封裝音頻數(shù)據(jù)的容器, 而且它的格式還很簡(jiǎn)單, 只是
在數(shù)據(jù)開頭添加一些和音頻數(shù)據(jù)相關(guān)的頭信息.
首先我們看一下WAV
的格式規(guī)則, 如下圖
千萬(wàn)不要被這圖嚇到, 上面的鏈接中也有對(duì)每一個(gè)值進(jìn)行說(shuō)明, 仔細(xì)閱讀后就會(huì)發(fā)現(xiàn)并不復(fù)雜. 接下來(lái)逐個(gè)分析.
橙色部分中的data
, 就是原始音頻數(shù)據(jù)(raw sound data), 也就是我們從AudioRecord
中獲取到的PCM
byte數(shù)組. 其余部分則是上文提到的音頻數(shù)據(jù)相關(guān)的頭信息.
圖中每一個(gè)方塊表示一個(gè)數(shù)據(jù)段, 從左側(cè)可以看到, 頭信息的總長(zhǎng)度是44個(gè)byte, 也可以知道每一個(gè)方塊的起始和結(jié)束下標(biāo), 例如Subchunk2ID
的下標(biāo)是36~40, 從右側(cè)可以看到每一個(gè)數(shù)據(jù)段的長(zhǎng)度, 例如ChunkID
占4個(gè)byte.
下面我們用header[n]
來(lái)表示頭信息的第n個(gè)byte, pcmLen
表示PCM
byte數(shù)組的長(zhǎng)度
接下來(lái)我們從下往上分析每個(gè)數(shù)據(jù)段的意思
-
data
, 占pcmLen
個(gè)byte, 表示原始的PCM
音頻數(shù)據(jù) -
Subchunk2Size
, 占4byte, 描述音頻數(shù)據(jù)的長(zhǎng)度, 就是pcmLen
, 注意先寫低位再寫高位, 即
header[40] = (byte) (pcmLen & 0xff);
header[41] = (byte) ((pcmLen >> 8) & 0xff);
header[42] = (byte) ((pcmLen >> 16) & 0xff);
header[43] = (byte) ((pcmLen >> 24) & 0xff);
-
SubchunkID
, 占4byte, 固定值"data", 即
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
-
BitPerSample
, 占2byte, 對(duì)應(yīng)AudioRecord
中的audioFormat
, 8 bits = 8, 16 bits = 16, 以16bits為例, 如下
header[34] = 16;
header[35] = 0;
-
BlockAlign
, 占2byte, 值為NumChannels * BitsPerSample / 8
-
ByteRate
, 占4byte, 值為SampleRate * BlockAlign
-
SampleRate
, 占4byte, 對(duì)應(yīng)AudioRecord
中的sampleRateInHz
, 即采樣頻率, 例如8000, 16000, 44100 -
NumChannels
, 占2byte, 對(duì)應(yīng)AudioRecord
中的channelConfig
, 單聲道Mono = 1, 立體聲Stereo = 2 -
AudioFormat
, 占2byte, 數(shù)據(jù)為PCM
時(shí), 值為1, 其他值表示數(shù)據(jù)進(jìn)行過(guò)某種壓縮, 本文不探討 -
Subchunk1Size
, 占4byte, 數(shù)據(jù)為PCM
時(shí), 值為16 -
Subchunk1ID
, 占4byte, 固定值"ftm "(注意空格補(bǔ)全4位) -
Format
, 占4byte, 固定值"WAVE" -
ChunkSize
, 占4byte, 值為4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
, 其中如果原始數(shù)據(jù)是PCM
, 簡(jiǎn)化為36 + SubChunk2Size
-
ChunkID
, 占4byte, 固定值"RIFF"
到這就分析完畢了, 所以如果我們有PCM
的原始數(shù)據(jù), 也知道這些數(shù)據(jù)的采集參數(shù), 例如單聲道/立體聲, 采樣頻率, 數(shù)據(jù)格式等, 就能夠按上述規(guī)則生成WAV
的頭部信息, 拼接PCM
byte數(shù)組后即得到WAV
的byte數(shù)組.
代碼戳PcmToWavUtil