加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 一、pcm
    • 二、WAV文件
    • 三、i2s音頻波形分析
    • 四、如何在各種音頻格式之間進(jìn)行轉(zhuǎn)換
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

瑞芯微-I2S | 語音文件格式wav與pcm快速入門-4

05/21 08:18
5619
閱讀需 24 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

一口君后面會陸續(xù)更新基于瑞芯微rk3568的I2S系列文章。預(yù)計(jì)10篇左右。有對語音感興趣的朋友,可以收藏該專題。

《瑞芯微 | I2S-音頻基礎(chǔ) -1》

《瑞芯微-I2S | 音頻驅(qū)動調(diào)試基本命令和工具-基于rk3568-2》

《瑞芯微-I2S | ALSA基礎(chǔ)-3 》

調(diào)試I2S,最常用到的測試文件就是wav格式和pcm格式,本文主要講解語音格式相關(guān)知識點(diǎn)。

本文還用到邏輯分析儀,使用方法如下:《推薦最近在使用的還不錯(cuò)的一款邏輯分析儀》

本文用到的 音頻文件+邏輯分析儀軟件+i2s數(shù)據(jù)波形 后臺回復(fù):i2s

一、pcm

與pcm相關(guān)的幾個(gè)參數(shù):

1. PCM數(shù)據(jù)常用量化指標(biāo)

    采樣率(Sample rate):每秒鐘采樣多少次,以Hz為單位。采樣率表示音頻信號每秒的數(shù)字快照數(shù)。該速率決定了音頻文件的頻率范圍。采樣率越高,數(shù)字波形的形狀越接近原始模擬波形。低采樣率會限制可錄制的頻率范圍,這可導(dǎo)致錄音表現(xiàn)原始聲音的效果不佳。

根據(jù) 奈奎斯特采樣定理,為了重現(xiàn)給定頻率,采樣率必須至少是該頻率的兩倍。例如,CD 的采樣率為每秒 44,100 個(gè)采樣,因此可重現(xiàn)最高為 22,050 Hz 的頻率,此頻率剛好超過人類的聽力極限 20,000 Hz。

位深度(Bit-depth):表示用多少個(gè)二進(jìn)制位來描述采樣數(shù)據(jù),一般為16bit。位深度決定動態(tài)范圍。采樣聲波時(shí),為每個(gè)采樣指定最接近原始聲波振幅的振幅值。較高的位深度可提供更多可能的振幅值,產(chǎn)生更大的動態(tài)范圍、更低的噪聲基準(zhǔn)和更高的保真度。

字節(jié)序:表示音頻PCM數(shù)據(jù)存儲的字節(jié)序是大端存儲(big-endian)還是小端存儲(little-endian),為了數(shù)據(jù)處理效率的高效,通常為小端存儲。

聲道數(shù)(channel number):當(dāng)前PCM文件中包含的聲道數(shù),是單聲道(mono)、雙聲道(stereo)?此外還有5.1聲道等。

采樣數(shù)據(jù)是否有符號(Sign):要表達(dá)的就是字面上的意思,需要注意的是,使用有符號的采樣數(shù)據(jù)不能用無符號的方式播放。

以FFmpeg中常見的PCM數(shù)據(jù)格式s16le為例:

    它描述的是有符號16位小端PCM數(shù)據(jù)
s表示有符號,
16表示位深,
le表示小端存儲。

2. PCM數(shù)據(jù)流

PCM (Pulse Code Modulation) 也被稱為脈沖編碼調(diào)制。PCM 音頻數(shù)據(jù)是未經(jīng)壓縮的音頻采樣數(shù)據(jù)裸流,它是由模擬信號經(jīng)過采樣、量化、編碼轉(zhuǎn)換成的標(biāo)準(zhǔn)的數(shù)字音頻數(shù)據(jù)。

PCM 音頻數(shù)據(jù)的存儲

如果是單聲道的音頻文件,采樣數(shù)據(jù)按時(shí)間的先后順序依次存入(有的時(shí)候也會采用 LRLRLR 方式存儲,只是另一個(gè)聲道的數(shù)據(jù)為 0),如果是雙聲道的話通常按照 LRLRLR 的方式存儲,存儲的時(shí)候還和機(jī)器的大小端有關(guān)。

小端模式如下圖所示:

PCM 音頻數(shù)據(jù)是未經(jīng)壓縮的數(shù)據(jù),所以通常都比較大,常見的 MP3 格式都是經(jīng)過壓縮的,128Kbps 的 MP3 壓縮率可以達(dá)到 1:11

PCM 音頻數(shù)據(jù)的參數(shù)

一般我們描述 PCM 音頻數(shù)據(jù)的參數(shù)的時(shí)候有如下描述方式:

44100HZ 16bit stereo:

每秒鐘有?44100?次采樣,?
采樣數(shù)據(jù)用?16?位(2?字節(jié))記錄,?
雙聲道(立體聲)

44100Hz 指的是采樣率,它的意思是每秒取樣 44100 次。采樣率越大,存儲數(shù)字音頻所占的空間就越大。

16bit 指的是采樣精度,意思是原始模擬信號被采樣后,每一個(gè)采樣點(diǎn)在計(jì)算機(jī)中用 16 位(兩個(gè)字節(jié))來表示。采樣精度越高越能精細(xì)地表示模擬信號的差異。

Stereo 指的是聲道數(shù),也即采樣時(shí)用到的麥克風(fēng)的數(shù)量,麥克風(fēng)越多就越能還原真實(shí)的采樣環(huán)境(當(dāng)然麥克風(fēng)的放置位置也是有規(guī)定的)。

其他格式例子:

22050HZ 8bit ?mono:

每秒鐘有?22050?次采樣,?采樣數(shù)據(jù)用?8?位(1?字節(jié))記錄,?單聲道

48000HZ 32bit 51ch:

每秒鐘有?48000?次采樣,?采樣數(shù)據(jù)用?32?位(4?字節(jié)浮點(diǎn)型)記錄,?5.1?聲道

二、WAV文件

WAV 是 Microsoft 和 IBM 為 PC 開發(fā)的一種聲音文件格式,它符合 RIFF(Resource Interchange File Format)文件規(guī)范,用于保存 Windows 平臺的音頻信息資源,被 Windows 平臺及其應(yīng)用程序所廣泛支持。

1. wav文件頭

WAVE 文件通常只是一個(gè)具有單個(gè) “WAVE” 塊的 RIFF 文件,該塊由兩個(gè)子塊(”fmt” 子數(shù)據(jù)塊和 ”data” 子數(shù)據(jù)塊)。

該格式的實(shí)質(zhì)就是在 PCM 文件的前面加了一個(gè)文件頭,各字段含義如下:

偏移與大小 名稱 說明
0 4 ChunkID 包含 ASCII 形式的字母“RIFF”(0x52494646 大端形式)。
4 4 ChunkSize 36 + SubChunk2Size,或更準(zhǔn)確地說:4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)這是此數(shù)字之后的塊的其余部分的大小。這是整個(gè)文件的大小(以字節(jié)為單位)減去未包含在此計(jì)數(shù)中的兩個(gè)字段的 8 字節(jié):ChunkID 和 ChunkSize。
8 4 格式 包含字母“WAVE”(0x57415645 大端形式)。
12 4 Subchunk1ID 包含字母“fmt”(0x666d7420 大端格式)。
16 4 Subchunk1Size 16 用于 PCM。這是該數(shù)字之后的其余子塊的大小。
20 2 AudioFormat PCM = 1(即線性量化)1 以外的值表示某種形式的壓縮。
22 2 NumChannels Mono = 1、Stereo = 2 等
24 4 SampleRate 8000、44100 等
28 4 ByteRate == SampleRate * NumChannels * BitsPerSample/8
32 2 BlockAlign == NumChannels * BitsPerSample/8 1 的字節(jié)數(shù)樣本包括所有通道。
34 2 BitsPerSample 8 位 = 8,16 位 = 16,等等
2 ExtraParamSize 如果是 PCM,則不存在
X ExtraParams 用于額外參數(shù)的空間
36 4 Subchunk2ID 包含字母“數(shù)據(jù)”(0x64617461 大端形式)。
40 4 Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 這是數(shù)據(jù)中的字節(jié)數(shù)。您還可以將其視為該數(shù)字后面的子塊的讀取大小。
44 * Data 實(shí)際的聲音數(shù)據(jù)。

2. wav文件頭結(jié)構(gòu)體

wav文件頭信息對應(yīng)結(jié)構(gòu)體

typedef?struct?{
????char??????????ChunkID[4];?//內(nèi)容為"RIFF"
????unsigned?long?ChunkSize;??//存儲文件的字節(jié)數(shù)(不包含ChunkID和ChunkSize這8個(gè)字節(jié))
????char??????????Format[4];??//內(nèi)容為"WAVE“
}?WAVE_HEADER;

typedef?struct?{
???char???????????Subchunk1ID[4];?//內(nèi)容為"fmt"
???unsigned?long??Subchunk1Size;??//存儲該子塊的字節(jié)數(shù)(不含前面的Subchunk1ID和Subchunk1Size這8個(gè)字節(jié))
???unsigned?short?AudioFormat;????//存儲音頻文件的編碼格式,例如若為PCM則其存儲值為1。
???unsigned?short?NumChannels;????//聲道數(shù),單聲道(Mono)值為1,雙聲道(Stereo)值為2,等等
???unsigned?long??SampleRate;?????//采樣率,如8k,44.1k等
???unsigned?long??ByteRate;???????//每秒存儲的bit數(shù),其值?=?SampleRate?*?NumChannels?*?BitsPerSample?/?8
???unsigned?short?BlockAlign;?????//塊對齊大小,其值?=?NumChannels?*?BitsPerSample?/?8
???unsigned?short?BitsPerSample;??//每個(gè)采樣點(diǎn)的bit數(shù),一般為8,16,32等。
}?WAVE_FMT;

typedef?struct?{
???char??????????Subchunk2ID[4];?//內(nèi)容為“data”
???unsigned?long?Subchunk2Size;??//接下來的正式的數(shù)據(jù)部分的字節(jié)數(shù),其值?=?NumSamples?*?NumChannels?*?BitsPerSample?/?8
}?WAVE_DATA;

3. WAV 文件頭解析實(shí)例

下面通過提供給大家的音頻文件《xiaoniao.wav》來詳細(xì)講解wav文件格式,該音頻文件格式為:S16_LE

peng@ubuntu:~/test$?ls?-l?xiaoniao.wav?
-rwxrw-rw-?1?peng?peng?1764448?May?10?20:41?xiaoniao.wav

用ue打開該文件,自動顯示為十六進(jìn)制數(shù)字,

文件頭信息解析如下圖:

數(shù)據(jù)是小端,比如采樣率4個(gè)字段是 44 AC 00 00實(shí)際數(shù)據(jù)是0x0000ac44,轉(zhuǎn)換成10進(jìn)制是44100

讀者對照結(jié)構(gòu)體,可以解析出改文件的所有信息。

三、i2s音頻波形分析

wav文件格式我們搞清楚了,那么它和i2s是什么關(guān)系呢?

1. 嵌入式設(shè)備音頻架構(gòu)

一個(gè)典型的嵌入式設(shè)備的音頻架構(gòu)大致如下【以rk3568為例】,

當(dāng)我們使用aplay工具播放wav文件時(shí):

    解析wav文件頭,讀取相應(yīng)信息然后通過i2s控制器驅(qū)動,將pcm音頻流通過i2s接口發(fā)送給codec rk809,codec rk809會將pcm音頻流進(jìn)行DAC轉(zhuǎn)換成對應(yīng)的模擬信號,并通過耳機(jī)/喇叭播放出去。

2. 播放命令

播放命令:

root@ATK-DLRK356X:/sdcard#?aplay?-v?xiaoniao.wav
Playing?WAVE?'xiaoniao.wav'?:?Signed?16?bit?Little?Endian,?Rate?44100?Hz,?Stereo
ALSA?<->?PulseAudio?PCM?I/O?Plugin
Its?setup?is:
??stream???????:?PLAYBACK
??access???????:?RW_INTERLEAVED
??format???????:?S16_LE
??subformat????:?STD
??channels?????:?2
??rate?????????:?44100
??exact?rate???:?44100?(44100/1)
??msbits???????:?16
??buffer_size??:?22050
??period_size??:?5512
??period_time??:?125000
??tstamp_mode??:?NONE
??tstamp_type??:?GETTIMEOFDAY
??period_step??:?1
??avail_min????:?5512
??period_event?:?0
??start_threshold??:?22050
??stop_threshold???:?22050
??silence_threshold:?0
??silence_size?:?0
??boundary?????:?6206523236469964800

3.波形分析

現(xiàn)在我在圖中i2s控制器與codec之間位置用邏輯分析儀抓取了i2s數(shù)據(jù)波形,

【該操作需要飛線,建議找硬件工程師幫忙】

波形文件aplay_xiaoniao.kvdat

一口君實(shí)際測試的i2s控制器為24位小端格式。

由上圖可知:

    1. xiaomiao.wav文件為s16_le格式,所以i2s控制器依次每次讀取

data

    后面2個(gè)字節(jié)的數(shù)據(jù)根據(jù)幀時(shí)鐘,依次在左右聲道時(shí)隙,將pcm數(shù)據(jù)放到數(shù)據(jù)線中。因?yàn)榭刂破魇?4位,所以各channel會有24個(gè)bit的時(shí)鐘周期;根據(jù)i2s協(xié)議,默認(rèn)有效數(shù)據(jù)靠左,并且空1個(gè)bit的位置;多出來的8個(gè)bit位置默認(rèn)補(bǔ)充填0。

5. codec就會通過該波形提取對應(yīng)的pcm數(shù)據(jù),做出相應(yīng)處理之后就可以播放出去了。

四、如何在各種音頻格式之間進(jìn)行轉(zhuǎn)換

處于測試需要,我們還需要經(jīng)常轉(zhuǎn)換文件格式,可以通過FFmpeg工具

1. FFmpeg

對于其他格式的音頻文件,一般用FFmpeg軟件進(jìn)行轉(zhuǎn)換,先在當(dāng)前的設(shè)備安裝好FFmpeg軟件,然后用命令行就可以進(jìn)行轉(zhuǎn)換了,常用的示范如下:

    將mp4視頻提取wav格式:
ffmpeg?-i?D:input.mp4?-vn?-acodec?pcm_s16le?-ar?44100?-ac?2?D:output.wav
    將wav格式轉(zhuǎn)變?yōu)閜cm格式:
ffmpeg?-i?D:output.wav?-f?s16le?-acodec?pcm_s16le?D:output.pcm
    將pcm格式轉(zhuǎn)變?yōu)閣av格式:
ffmpeg?-f?s16le?-ar?44100?-ac?2?-i?D:output.pcm?c:output.wav

注意上面的命令中指定的采樣率為44.1k ,雙聲道,存儲格式是s16le

2. 編寫代碼實(shí)現(xiàn)PCM → WAV 代碼

下面是一個(gè)實(shí)現(xiàn)將pcm文件轉(zhuǎn)換成wav文件的代碼實(shí)例:

int?simplest_pcm16le_to_wave(?const?char?*pcmpath,?int?channels,?int?sample_rate,?const?char?*wavepath?)
{?//?省去錯(cuò)誤判斷
????short?pcmData;
????FILE*?fp?=?fopen(?pcmpath,?"rb"?);
????FILE*?fpout?=?fopen(?wavepath,?"wb+"?);
????
????//?填充?WAVE_HEADER
????WAVE_HEADER?pcmHEADER;
????memcpy(?pcmHEADER.ChunkID,?"RIFF",?strlen(?"RIFF"?)?);
????memcpy(?pcmHEADER.Format,?"WAVE",?strlen(?"WAVE"?)?);
????fseek(?fpout,?sizeof(?WAVE_HEADER?),?1?);
????
????//填充?WAVE_FMT?
????WAVE_FMT?pcmFMT;
????pcmFMT.SampleRate?=?sample_rate;
????pcmFMT.ByteRate?=?sample_rate?*?sizeof(?pcmData?);
????pcmFMT.BitsPerSample?=?8?*?sizeof(?pcmData?);
????memcpy(?pcmFMT.Subchunk1ID,?"fmt?",?strlen(?"fmt?"?)?);
????pcmFMT.Subchunk1Size?=?16;
????pcmFMT.BlockAlign?=?channels?*?sizeof(?pcmData?);
????pcmFMT.NumChannels?=?channels;
????pcmFMT.AudioFormat?=?1;
????fwrite(?&pcmFMT,?sizeof(?WAVE_FMT?),?1,?fpout?);

????//填充?WAVE_DATA;
????WAVE_DATA?pcmDATA;
????memcpy(?pcmDATA.Subchunk2ID,?"data",?strlen(?"data"?)?);
????pcmDATA.Subchunk2Size?=?0;
????fseek(?fpout,?sizeof(?WAVE_DATA?),?SEEK_CUR?);
????fread(?&m_pcmData,?sizeof(?short?),?1,?fp?);
????while?(?!feof(?fp?)?)?{
?????????pcmDATA.dwSize?+=?2;
?????????fwrite(?&m_pcmData,?sizeof(?short?),?1,?fpout?);
?????????fread(?&m_pcmData,?sizeof(?short?),?1,?fp?);
????}
????
????int?headerSize?=?sizeof(?pcmHEADER.Format?)?+?sizeof(?WAVE_FMT?)?+?sizeof(?WAVE_DATA?);?//?36
????pcmHEADER.ChunkSize?=?headerSize?+?pcmDATA.Subchunk2Size;

????rewind(?fpout?);
????fwrite(?&pcmHEADER,?sizeof(?WAVE_HEADER?),?1,?fpout?);
????fseek(?fpout,?sizeof(?WAVE_FMT?),?SEEK_CUR?);
????fwrite(?&pcmDATA,?sizeof(?WAVE_DATA?),?1,?fpout?);
????fclose(?fp?);
????fclose(?fpout?);
????return?0;
}

大家可以用我提供的sound.pcm、xiaoniao.wav語音文件,測試一下。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級 參考價(jià)格 更多信息
SN74LVC2G07DCKR 1 Texas Instruments 2-ch, 1.65-V to 5.5-V buffers with open-drain outputs 6-SC70 -40 to 125

ECAD模型

下載ECAD模型
$0.57 查看
PVT422SPBF 1 International Rectifier Transistor Output SSR, 2-Channel, 4000V Isolation, LEAD FREE, PLASTIC, SURFCAE MOUNT, DIP-8
$8.57 查看
CY7C1061G30-10ZSXIT 1 Cypress Semiconductor Standard SRAM, 1MX16, 10ns, CMOS, PDSO54, TSOP2-54
$51.08 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗(yàn)和培訓(xùn)經(jīng)驗(yàn)。曾任職ZTE,某研究所,華清遠(yuǎn)見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計(jì)算機(jī)網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實(shí)際項(xiàng)目出發(fā),保持原理+實(shí)踐風(fēng)格,適合Linux驅(qū)動新手入門和技術(shù)進(jìn)階。