痞子衡嵌入式:PCM編碼與Waveform音頻文件(.wav)格式詳解

来源:https://www.cnblogs.com/henjay724/archive/2018/08/12/9463296.html
-Advertisement-
Play Games

嵌入式里有時候也會和音頻打交道,比如最近特別火的智能音箱產品,離不開前端的音頻信號採集、降噪,中間的語音識別(ASR)、自然語言處理(NLP),以及後端的文語合成(TTS)、音頻播放。音頻信號採集是處理聲音的第一步,要採集音頻就離不開PCM編碼,音頻採集完成自然需要保存,waveform格式(.wa... ...



  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是PCM編碼及Waveform音頻文件格式

  嵌入式里有時候也會和音頻打交道,比如最近特別火的智能音箱產品,離不開前端的音頻信號採集、降噪,中間的語音識別(ASR)、自然語言處理(NLP),以及後端的文語合成(TTS)、音頻播放。音頻信號採集是處理聲音的第一步,要採集音頻就離不開PCM編碼,音頻採集完成自然需要保存,waveform格式(.wav)是一種最經典的音頻文件格式。今天痞子衡就給大家詳細介紹PCM編碼以及waveform文件格式。

一、聲音基礎

  眾所周知,聲音是由物體振動產生的聲波,聲音通過介質(空氣或固體、液體)傳播並能被人聽覺器官所感知。發音物體情況(材料,距離,振動強度等)不同,產生的聲音也不同。為了區分不同的聲音,我們主要用如下三個參數來描述聲音的特征:

  • 音量:人主觀上感覺到的聲音大小(也叫響度),由“振幅”(amplitude)和人離聲源的距離決定。
  • 音調:聲音的高低(高音、低音),由“頻率”(frequency)決定,頻率越高音調越高。
  • 音色:音色是一種抽象的東西,波形決定了聲音的音色。聲音因不同發聲物體材料而具有不同特性,波形是把這個抽象特性直觀的表現出來。典型的音色波形有方波,鋸齒波,正弦波,脈衝波等。

  三大參數里除了音色沒有度量單位外(可以認為音色是聲音的UID,每種音色都是獨一無二的),音量和音調均有度量單位,這意味著音量和音調是可調整的,也是聲音之間可對比的特征參數。

1.1 音量單位-分貝(dB)

  聲波是一種機械波(壓力波)。聲波(空氣質點)的連續振動,使空氣分子不斷交替的壓縮和鬆弛,使大氣壓迅速產生起伏,這種氣壓的起伏部分,就稱為聲壓。聲壓的振幅表示質點離開平衡位置的距離,反映從波形波峰到波谷的壓力變化,以及波所攜帶的能量的多少。
  聲壓值雖然可以反映音量大小,但人們日常生活中遇到的聲音,若以聲壓值表示,變化範圍非常大(達到六個數量級以上),並且人體聽覺對聲信號強弱刺激反應不是線形的,而是成對數比例關係。因此音量並不是聲壓值來計量,而是用分貝來計量,首先來看分貝計算的標準公式:

NdB = 10 * log10 (Pi / Po)

  上述公式中Po為基準聲壓值,NdB即是聲壓信號Pi對基準聲壓Po的分貝值。從公式可以看出分貝是指兩個相同類型物理量(Pi、Po)的比較結果,它是無量綱的。分貝又稱為被量度量Pi的"級",它代表被量度量比基準量高出多少"級"。下麵列舉常見分貝值:

分貝值 人耳感覺
1dB 剛能聽到的聲音
1 - 15dB 感覺非常安靜
20 - 40dB 耳語音,冰箱的嗡嗡聲
40 - 60dB 室內正常交談的聲音
60 - 70dB 走在鬧市區的感覺,有點吵
70 - 85dB 汽車穿梭在馬路上,85dB是保護聽力的一般要求
85 - 100dB 摩托車啟動,裝修電鑽
100 - 150dB 飛機起飛、燃放煙花爆竹

1.2 音調單位-頻率(Hz)

  頻率是每秒經過一給定點的聲波周期數量,其單位是Hz,1KHz表示每秒經過一給定點的聲波有1000個周期。根據頻率範圍,我們將聲波分為如下三種:

聲波類別 頻率範圍 特性與應用
次聲波 低於20Hz 部分動物(狗、大象)能發出/感知,常用於自然災害監測
可聞聲 20Hz ~ 20KHz 人的聽覺感知範圍
超聲波 高於20KHz 部分動物(狗、蝙蝠)能發出/感知,常用於深海探測(聲吶)、醫學檢查(B超)

  關於聲波頻率特別要提的是,聲波可以被分解為不同頻率不同強度正弦波的疊加,這種變換(或分解)的過程,稱為傅立葉變換(Fourier Transform)

二、PCM編碼原理

  聲波是一種在時間上和振幅上均連續的模擬量,在嵌入式里要想研究聲波,首先需要將聲波轉換成一連串電壓變化的模擬電信號,麥克風器件就是一種採集聲波信號並將其轉換成模擬電壓信號輸出的裝置。
  有了聲波的模擬電壓信號,下一步需要將模擬信號數字化,即將模擬信號經過模數轉換器(A/D)後變成數字信號,說白了就是將聲音數字化。最常見的聲音數字化方式就是脈衝編碼調製PCM(Pulse Code Modulation),PCM是70年代末發展起來的技術,最早應用於由飛利浦和索尼公司共同推出的CD上,下圖給出了PCM編碼全過程:

  從上圖中我們可以看到PCM編碼主要有三個過程:採樣、量化、編碼,在這過程中主要有4個參數用於評價PCM:聲道數、採樣率、量化位數、編碼方式。痞子衡會在下麵逐一介紹PCM編碼過程時穿插介紹這4個參數:

2.1 採樣

  所謂採樣,即按一定的採樣頻率將模擬信號變成時間軸上離散的抽樣信號的過程。原則上採樣頻率越高,聲音的質量也就越好,聲音的還原也就越真實。
  採樣率即每秒從模擬信號中提取並組成離散信號的採樣個數,用赫茲(Hz)來表示。說到採樣率有一個不得不提的著名定律,即香農(Shannon)/奈奎斯特(Nyquist)採樣定律,該定律表明採樣頻率必須大於或等於所傳輸的模擬信號的最高頻率的2倍,才能不失真地恢復模擬信號

最常說的“無損音頻”,一般都是指傳統CD格式中的44.1kHz/16bit的文件格式,而之所以稱為無損壓縮,是因為其包含了20Hz-22.05kHz這個完全覆蓋人耳可聞範圍的聲音頻率而得名。

  關於聲道數,其實非常好理解,就是採集聲音的通道數,我們知道有單聲道(mono),立體聲(雙聲道stereo)、杜比7.1環繞聲,其實就是聲音採集的通道數有差別,聲道越多,越能體現聲音的空間立體效果。

2.2 量化

  前面採樣得到的抽樣信號雖然是時間軸上離散的信號,但仍然是模擬信號,其採樣值在一定的取值範圍內,可有無限多個值,必須採用“四捨五入”的方法把樣值分級“取整”,使一定取值範圍內的樣值由無限多個值變為有限個值,這一過程稱為量化。
  量化位數指的是描述數字信號所使用的位數。如麥克風采集的電壓範圍為0-3.3V,8bit的量化精度為3.3V/256,16bit的量化精度為3.3V/65536。

2.3 編碼

  量化後的抽樣信號就轉化為按抽樣時序排列的一串十進位數字碼流,即十進位數字信號。簡單高效的數據系統是二進位碼系統,因此,應將十進位數字碼變換成二進位編碼,這種把量化的抽樣信號變換成給定字長(量化位數)的二進位碼流的過程稱為編碼。
  編碼方式種類非常多,其對比可見 Comparison of audio coding formats,PCM音頻格式編碼常見有四種:PCM(Linear PCM)、ADPCM(Adaptive differential PCM)、 A-law(A律13折線碼)、μ-law(μ律15折線碼),最簡單的當然是下圖所示的LPCM(示例為4bit),這是一種均勻量化編碼,廣泛用於 Audio CD, AES3, WAV, AIFF, AU, M2TS, VOB中。

  除LPCM外,A-law和μ-law是兩種不得不提的非均勻量化編碼,這兩種非均勻量化編碼是為了提高小信號的信噪比,其基本思想是在量化之前先讓信號經過一次處理,對大信號進行壓縮而對小信號進行較大的放大,這一處理過程通常也稱為“壓縮量化”。壓縮量化的實質是“壓大補小”,使小信號在整個動態範圍內的信噪比基本一致。下麵是這兩種編碼與LPCM的 對比圖

三、Waveform文件格式解析

  前面講的PCM編碼後的聲音數據是需要保存的,WAVE文件常常用來保存PCM編碼數據。WAVE文件是微軟公司(Microsoft)開發的一種聲音文件格式,用於保存Windows平臺的音頻信息資源,被Windows平臺及其應用程式所廣泛支持,WAVE文件預設打開工具是WINDOWS的媒體播放器。

3.1 RIFF文件格式標準

  WAVE文件是以微軟RIFF格式為標準的,RIFF全稱為資源互換文件格式(Resources Interchange File Format),是Windows下大部分多媒體文件遵循的一種文件結構。RIFF文件所包含的數據類型由該文件的擴展名來標識,能以RIFF格式存儲的數據有很多:音頻視頻交錯格式數據(.AVI)、波形格式數據(.WAV)、點陣圖數據格式(.RDI)、MIDI格式數據(.RMI)、調色板格式(.PAL)、多媒體電影(.RMN)、動畫游標(.ANI)等。
  如下代碼所示的CK結構體是RIFF文件的基本單元,該基本單元也稱 Chunk。其中ckID用於標識塊中所包含的數據類型,其取值可有'RIFF'、'LIST'、'fmt '、'data'等;ckSize表示存儲在ckData域中的數據長度(不包含ckID和ckSize的大小);ckData存儲數據,數據以位元組為單位存放,如果數據長度為奇數,則最後添加一個空位元組。

由於RIFF文件結構最初是由Microsoft和IBM為PC機所定義,RIFF文件是按照小端little-endian位元組順序寫入的。

typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef DWORD         FOURCC;    // Four-character code

typedef struct { 
     FOURCC ckID;          // The unique chunk identifier 
     DWORD ckSize;         // The size of field <ckData> 
     BYTE ckData[ckSize];  // The actual data of the chunk 
} CK; 

  Chunk是可以嵌套的,但是只有ckID為'RIFF'或者'LIST'的Chunk才能包含其他的Chunk。標誌為'RIFF'的Chunk是比較特殊的,每一個RIFF文件首先存放的必須是一個'RIFF' Chunk,並且只能有這一個標誌為'RIFF'的Chunk。

  更多RIFF的知識詳見這個網站鏈接 RIFF (Resource Interchange File Format),鏈接里收集了很多介紹RIFF的資源。

3.2 WAVE文件結構

  WAVE是Microsoft開發的一種音頻文件格式,它符合上面提到的RIFF文件格式標準,可以看作是RIFF文件的一個具體實例。既然WAVE符合RIFF規範,其基本的組成單元也是Chunk。一個 WAVE文件 通常有三個Chunk以及一個可選Chunk,其在文件中的排列方式依次是:RIFF Chunk,Format Chunk,Fact Chunk(附加塊,可選),Data Chunk,如下圖所示:

  根據上面的WAVE文件結構圖,可以定義如下44bytes的wave_head_t用來描述WAVE文件的頭。如果你曾經接觸過Windows的音頻介面API,你會發現wave_fmt_t中的部分結構與標準MSDN里的 WAVEFORMAT 是一致的。

typedef char    int8_t;    //有符號8位整數
typedef short   int16_t;   //有符號16位整數
typedef int     int32_t;   //有符號32位整數

struct _wave_tag
{
    int8_t     riff[4];            //"RIFF",資源交換文件標誌
    int32_t    filesize;           //文件大小(從下個地址開始到文件尾的總位元組數)
    int8_t     wave[4];            //"WAVE",文件標誌
} wave_tag_t;
struct _wave_format
{
    int8_t     fmt[4];             //"fmt ",波形格式標誌 
    int32_t    chunksize;          //文件內部Chunk信息大小
    int16_t    wFormatTag;         //音頻數據編碼方式
    int16_t    wChanles;           //聲道數
    int32_t    nSamplesPerSec;     //採樣率
    int32_t    nAvgBytesPerSec;    //波形數據傳輸速率(每秒平均位元組數)
    int16_t    nBlockAlign;        //數據的調整數(按位元組計算)
    int16_t    wBitsPerSample;     //樣本數據位數
} wave_fmt_t;
struct _wave_data
{
    int8_t     data[4];            //"data",數據標誌符
    int32_t    datasize;           //採樣數據總長度
} wave_dat_t;

struct _wave_head
{
    wave_tag_t   waveTag;
    wave_fmt_t   waveFmt;
    wave_dat_t   waveDat;
} wave_head_t;

  wave_head_t結構體內除了wFormatTag成員之外,其他都可以根據字面上的意思來理解。關於wFormatTag的具體定義,可見Windows SDK里的 mmreg.h文件,下麵列舉了幾個最常見Format的Tag值定義:

  當WAVE文件的頭被解析成功後,下一步便是獲取WAVE文件里的聲音源數據,我們知道聲音文件有單聲道和多聲道之分,對於單聲道文件很好理解,聲音數據就是按序排放,而如果是立體聲(2聲道)文件,那麼左右聲道的聲音數據到底是怎麼排放的呢?下麵以一個示例立體聲文件數據(僅分析前72bytes)進行解釋:

offset(h)
00000000: 52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20
00000010: 10 00 00 00 01 00 02 00 22 56 00 00 88 58 01 00
00000020: 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
00000030: 24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6
00000040: 3c f2 24 f2 11 ce 1a 0d

  下圖是這個72bytes數據解析圖,從圖中可以看到,左右聲道的聲音數據是按塊(nBlockAlign指定)交替排放的。

  更多WAVE的知識詳見這兩個網站鏈接 WAVE Audio File FormatAudio File Format Specifications,鏈接里收集了很多介紹WAVE的資源。

3.3 WAVE文件實例分析

  WAVE文件格式我們都瞭解透徹了,下麵我們嘗試分析一個經典的WAVE文件:"Windows XP 啟動.wav",這個文件可以說是最知名的WAVE文件了,痞子衡特別喜歡這段music,讓我們直接用二進位編輯器HxD打開它:

  按wave_head_t解析WAVE頭可知,這段wave是44.1kHz/16bit雙聲道線性PCM碼音頻,實際音頻數據總長度為1361076bytes(1361076(datasize)/176400(nAvgBytesPerSec)=7.7158秒),最後再用Adobe Audition(原Cool Edit)打開查看其波形圖:

  至此,PCM編碼及Waveform音頻文件格式痞子衡便介紹完畢了,掌聲在哪裡~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在VS 2017 8月2號發佈15.7.6版本後,在8月7號推送了helpview程式中的絕大部分更新文檔,在本次推送中多數Cab文件出現了無法進行安裝的簽名問題, 不論是單個下載,還是刪除本地所有已有文檔,亦或者重置電腦從新安裝VS 2017下載這些幫助文檔都會因為簽名問題而更新失敗。 並且在安裝 ...
  • 直接把網站根目錄添加上everyone許可權即可 ...
  • 學到新東西就記錄一下。也許正好有人需要~~~~~~ 由於需要記錄當前線上用戶,emmmm又是沒做過的。。。 本來想用資料庫的形式,但是想想這麼簡單的功能百度肯定有。遨游一波百度,有所收穫。。。。 雖然老是那麼幾篇文章重覆。。。。 大概就是在用戶登錄時Session記錄下數據,前臺獲取展示。下麵這個文 ...
  • 以前在學習STM32時候關註過STM32的位帶操作,那時候只是知道位帶是啥,用來幹嘛用,說句心裡話,並沒有深入去學習,知其然而不知其所以然。但一直在心中存在疑惑,故今日便仔細看了一下,寫下心得供日後參考。 位帶操作,我所理解的是就是像51單片機那樣驅動IO引腳一樣,比如要驅動P1埠的第一個引腳直接 ...
  • whoami // 查看當前用戶名稱 ipconfig // 查看本機ip信息,可加 /all 參數 netstat -ano // 查看埠清況 dir c:\ // 查看目錄 type c:\Users\admin\Desktop\1.txt // 查看制定位置文件內容,一般為文本文件 echo ...
  • 打開虛擬機,用Xshell連接之前,首先我們要獲取IP的地址 先輸入獲取 IP的命令 ip addr 獲取ipifup (網卡名字) #網卡啟動ifdown (網卡名字) #網卡關閉 沒有獲取到的話 我們要開始按照下麵的順序排查故障: 沒有獲取到的話 我們要開始按照下麵的順序排查故障: 按照上面的步 ...
  • LVM學習邏輯捲管理創建邏輯捲遇到的問題 1 實驗環境 系統 | 內核 | 發行版本 | | CentOS | 2.6.32 754.2.1.el6.x86_64 | CentOS release 6.10 (Final) 由於是最小化安裝沒有xfs命令, 安裝如下包支持此命令 2 用gdisk分區 ...
  • 系統狀態查看命令: w 查看用戶 top 系統進程監控 uptime 查看某台伺服器運行了多久 htop 更加先進的互動式監控工具(需要安裝) iotop 監控並實時顯示磁碟IO輸入和輸出和程式進程(需要安裝) iftop 網路帶寬監控(需要安裝) 查看進程: ps ps -ef 查看所有進程 ps ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...