Python解析Wav文件並繪製波形的方法

資源下載

#本文PDF版下載python

Python解析Wav文件並繪製波形的方法git

#本文代碼下載github

Wav波形繪圖代碼windows

#本文實例音頻文件night.wav下載數組

音頻文件下載 (石進-夜的鋼琴曲)學習

前言

在如今繁忙的生活中,咱們常常會聽些歌來放鬆一下本身,咱們常常會從各類播放軟件中聽本身喜歡的歌,而且每每咱們會下載一部分歌曲,而如今音頻的種類也至關繁多,像是Wav,Mp3,FLAC,AAC等等不少格式,最近因爲須要作一個可以分析Wav格式音頻的波形來取得一些數據好比獲取人錄音時是否說完等等用途.本週先對解析Wav並用Python繪製其波形進行了一些探索.測試

 

Wav文件格式

咱們先來看看wikipedia上對於wav音頻格式的解釋:編碼

「Waveform Audio File Format(WAVE,又或者是由於擴展名而被大衆所知的WAV),是微軟與IBM公司所開發在我的電腦存儲音頻流的編碼格式,在Windows平臺的應用軟件受到普遍的支持,地位上相似於麥金塔電腦裏的AIFF.此格式屬於資源交換檔案格式(RIFF)的應用之一,一般會將採用脈衝編碼調製的音頻資存儲在區塊中。也是其音樂發燒友中經常使用的指定規格之一.因爲此音頻格式未通過壓縮,因此在音質方面不會出現失真的狀況,但檔案的體積於是在衆多音頻格式中較爲大.」spa

咱們能夠看到上面提到了兩個個關鍵詞RIFF和脈衝編碼調製.因此咱們接下來先解釋一下 RIFF「資源交換檔案格式」是什麼.code

 

RIFF格式

咱們一樣的來看一下wikipedia對RIFF的解釋
「 Resource Interchange File Format(簡稱RIFF),資源交換文件格式,是一種按照標記區塊存儲數據(tagged chunks)的通用文件存儲格式,多用於存儲音頻、視頻等多媒體數據.Microsoft在windows下的AVI、ANI 、WAV等都是基於RIFF實現的.

RIFF是由Microsoft和IBM於1991年,在windows 3.1中引入的,做爲windows 3.1默認的多媒體文件格式。RIFF是參考Interchange File Format來的,兩者主要的區別是字節序大端、小端的問題.在基於IBM的80x86系列主機下,RIFF的字節序是小端的;而在IFF原有的格式中是按照大端存儲整型數據的.」

RIFF是由chunk構成的,chunk是RIFF組成的基本單位,每一個CHUNK可看做存貯了視頻的一幀數據或者是音頻的一幀數據,因此下面咱們來討論一下chunk的結構是怎麼樣的.

CHUNK的結構

CHUNK總共由三個部分組成:

  • FOURCC   使用4字節的ASIIC字符標識類型
  • SIZE            數據的大小
  • DATA          用於存放數據

結構示意圖以下:

CHUNK結構

           CHUNK的結構

  • CHUNK在通常狀況下不能嵌套,可是當CHUNK的FOURCC爲「RIFF」或者是「LIST」的時候能夠嵌套數據.
  • 「RIFF」的第一個CHUNK的FOURCC必定是「RIFF」,因此LIST爲FOURCC的必定是子CHUNK及SUBCHUNK.

下面是一個包含了子CHUNK的結構示意圖:

包含子CHUNK的示意圖

 

       包含了SUBCHUNK的結構示意圖

  •  「RIFF」的CHUNK在DATA區域的前四個字節稱爲「Form Type」記錄了數據的類型,好比咱們的wav文件的Form Type就是「WAV」

Form Type結構示意圖以下:

包含了Form Type的結構示意圖

 

      包含了Form Type的結構示意圖 

  • 一樣的FOURCC爲LIST的 SUBCHUNK 的DATA區域也包含了LIST Type,用於表示LIST中數據區域格式

脈衝編碼調製(PCM)

咱們先來看看百度百科對它的解釋:
「PCM 脈衝編碼調製是Pulse Code Modulation的縮寫,脈衝編碼調製是數字通訊的編碼方式之一.主要過程是將話音、圖像等模擬信號每隔必定時間進行取樣,使其離散化,同時將抽樣值按分層單位四捨五入取整量化,同時將抽樣值按一組二進制碼來表示抽樣脈衝的幅值.」
咱們從上面的介紹能夠理解爲:
經過三個過程-抽樣、量化和編碼講音頻的模擬信號轉化爲數字信號.

抽樣

抽樣是因爲模擬信號是連續的,經過必定頻率對模擬信號進行取樣,近似獲得,以下面的圖中灰色框中就是取了必定頻率進行抽樣的示意圖:

抽樣過程示意圖

                           抽樣過程示意圖

  • 抽樣是要將模擬信號以其信號帶寬2倍以上的頻率提取樣值,變爲在時間軸上*離散*的抽樣信號,就可得到能取代原來連續音頻信號的抽樣信號.對一個正弦信號進行抽樣得到的抽樣信號是一個脈衝幅度調製(PAM)信號,以後對抽樣信號進行檢波和平滑濾波,便可還原出原來的模擬信號.

量化

抽樣信號離散的模擬信號,其取樣的值在必定的取值範圍內,由無限多種值可能性存在.爲了實現以數字碼表示樣值,咱們採用「四捨五入」的方法把樣值分級「取整」,使必定取值範圍內的樣值由無限多個值變爲有限個值.

編碼

量化後的抽樣信號在必定的取值範圍內僅有有限個可取的樣值,且信號正、負幅度分佈的對稱性使正、負樣值的個數相等,正、負向的量化級對稱分佈

WAV文件的CHUNK信息

WAVE文件是由若干個CHUNK組成的.按照文件中CHUNK的出現順序分別爲:RIFF Chunk, Format Chunk, Fact Chunk, Data Chunk,其中的Fact CHUNK爲非必要部分,結構具體以下圖所示:

WAV文件頭文件的CHUNK組成

 

              WAV文件頭文件的CHUNK組成

RIFF是頭CHUNK,而Format CHUNK裏面記錄了WAV的各類參數信息,詳細參數信息以下:

  • FormatTag            音頻數據的編碼方式,其中PCM方式爲1
  • Channels               聲道數,單聲道爲1,雙聲道爲2
  • SamplesPerSec    採樣率(每秒樣本數)
  • BytesPerSec*        音頻數據傳送速率
  • BlockAlign*           每次採樣的大小
  • BitsPerSample*    每一個聲道的採樣精度

而FACT CHUNK的做用是由於有些並無使用PCM格式,因此須要一個FACT CHUNK記錄數據解壓縮數據大小.
最後的DATA塊中裝的是真正的聲音數據.通常按照WAVE_FORMAT_PCM的數據格式存貯,即脈衝編碼調製PCM.

WAV的DATA部分

DATA塊內的信息是根據format chunk內的信息而決定的.由量化位數/聲道數/採樣率共同決定,下圖爲四種狀況下DATA區域存儲信息的格式:

DATA CHUNK的格式

                               DATA CHUNK的格式

Python讀取WAV文件的信息

在python中,咱們能夠直接經過許多音頻的庫對wav文件進行操做,好比自帶的標準庫wave庫,還有如eyeD3,PyAudio,Audacity等等.咱們先不介紹這種方式,咱們先經過傳統的文件操做以二進制的形式讀取Wav文件,來分析一下它的頭文件來驗證一下咱們前面有關CHUNK所學的知識.經過二進制操做音頻文件並取得前四個字節的代碼以下:(咱們的測試音頻是night.wav,已放在github中,經過個人博客園右上角的綠色圖標能夠連接到個人github界面,找到lab102下的w8目錄便可獲取該資源,或者找到本文博客園最上方資源):

#讀取wav前四個字節內容 -xlxw
 file = open("night.wav", "rb") s = file.read(4) print(s)

程序運行截圖:

運行截圖

 

咱們能夠看到最前面的字節和咱們認爲的沒錯,是RIFF,那咱們來讀取44個字節來看看其中的信息是怎麼樣的:

#讀取wav前44個字節內容 -xlxw
 file = open("night.wav", "rb") s = file.read(44) print(s)

程序運行截圖:

運行截圖

咱們能夠看到RIFF後面的字符串爲WAVE的Form Type,以及fmt,data這幾個FOURCC,而其餘用十六進制表示的就是數據大小/數據了.因此咱們經過二進制讀取的WAV文件的信息和咱們前面學習的CHUNK中的內容是一致的.

用Wave庫提取wav文件信息

在咱們前面中的介紹能夠知道wav文件的存儲方式,而且可以簡單的提取其中的信息了,而咱們知道wav文件最重要的就是聲音信息的存貯,這一部分咱們也能夠經過對CHUNK的DATA 進行分析,不過咱們在python中有更加簡單的得到聲音的方式,那就是利用python自帶的wave庫,咱們下面就來介紹一下wave庫的一些方法,爲後文作鋪墊.

  • 首先引入wave庫
import wave
  •  open()

打開一個聲音文件,使用方法wave.open(聲音文件地址,模式)
其中聲音文件地址就是wav文件位置,模式和文件讀寫差很少,如「wb」-只寫;「rb」-只讀方式 b表明以二進制模式打開.

  • close()

關閉聲音文件

  • getparams()

獲取wav文件的參數(以tuple形式輸出),依次爲(聲道數,採樣精度,採樣率,幀數,......)
以下圖爲本文例子night.wav的getparams()的信息:

程序截圖

 

  • readframes()

獲得每一幀的聲音數據,返回的值是二進制數據,在python中用字符串表示二進制數據,以下圖,因此咱們後面要進行轉化.
獲得的night.wav的前10幀的數據以下圖所示:

程序截圖

 

上面就基本上是wave庫的經常使用方法了.下面會對此進行應用了.

 

繪製WAV文件的波形

咱們常常在許多聲音軟件,好比CoolEdit,Audition等軟件中能看到聲音文件的波形,因此咱們在這裏利用Python以及前面介紹的wave庫,輔以numpy,Matplotlib來嘗試繪製night.wav文件的波形.
下面咱們來簡單講述一下繪製波形的步驟:(以night.wav爲例子)

  1. 經過wav庫得到night.wav的頭文件中的信息,如採樣率/聲道數等等.
  2. 提取出DATA區域的信息,用numpy將string格式數據轉化爲數組
  3. 經過斷定聲道數將DATA區域數據進行處理(對數組矩陣進行轉換)
  4. 獲得每一個繪製點的時間(x座標)
  5. 用matplotlib庫提供的方法繪製出波形圖

咱們來對這些步驟中的一些部分詳細說一下:

對DATA區域的處理

由於night.wav是一個雙聲道的WAV 文件,咱們從上文對DATA區域格式的介紹能夠知道儲存形式是左聲道/右聲道的形式存貯數據,因此在這裏咱們要對提取出的數據進行處理,這裏numpy庫爲咱們提供了很好的解決方法,咱們主要用到了改變形狀的Shape方法以及T轉置方法,咱們在這裏來舉一個例子:
咱們建立一個數組[1,2,3,4,5,6,7,8]裏面有8個元素,這時候根據咱們的分離方法,應該分爲左聲道[1,3,5,7]和右[2,4,6,8],咱們能夠經過shape先改變矩陣的形狀使數據變爲兩列分別爲左右聲道,再經過轉置獲得最終數據,咱們的例子能夠用以下圖所示理解:

將數據分爲左右聲道的例子 

            將數據分爲左右聲道的例子

繪製波形圖的matplotlib庫

這裏咱們要繪出波形,因此用matplotlib庫大大減小咱們的繪圖難度,咱們主要用到plt.subplot和plt.plot這兩個方法,因此咱們對這兩個方法進行解釋.

  •  plt.subplot()

這是用於matplotlib繪製多個子圖的方法,由於咱們這裏音頻文件要分爲兩個部分(左聲道/右聲道)
即分紅2X1的形式,因此咱們的第一個繪圖和第二個繪圖分別用
plt.subplot(211)和plt.subplot(212)來表示,以下圖所示:

matplotlib子圖

                  matplotlib子圖

  • plt.plot

plt.plot()是用於繪製線條的方法,咱們用到了其中的三個參數
(X座標,y座標,顏色)
就能用plot畫出最終的波形圖了

  • 其餘的方法這裏就不介紹了,可是matplotlib的繪圖功能至關強大.

 

繪製night.wav波形的代碼

用於繪製出wav文件波形的代碼以下(這裏咱們仍是以night.wav做爲例子)

#wave data -xlxw

#import
import wave as we import numpy as np import matplotlib.pyplot as plt def wavread(path): wavfile =  we.open(path,"rb") params = wavfile.getparams() framesra,frameswav= params[2],params[3] datawav = wavfile.readframes(frameswav) wavfile.close() datause = np.fromstring(datawav,dtype = np.short) datause.shape = -1,2 datause = datause.T time = np.arange(0, frameswav) * (1.0/framesra) return datause,time def main(): path = input("The Path is:") wavdata,wavtime = wavread(path) plt.title("Night.wav's Frames") plt.subplot(211) plt.plot(wavtime, wavdata[0],color = 'green') plt.subplot(212) plt.plot(wavtime, wavdata[1]) plt.show() main()

程序繪製出的波形圖的截圖:

運行截圖

 

                     night.wav聲音文件的雙聲道波形

總結&拓展

在本週我學到了wav文件的存貯格式以及怎麼用python讀取wav文件信息而且繪製出波形圖.其中在繪製了波形圖後,咱們能夠對波形多透露出的信息進行分析,好比:

  • 獲得聲音的特徵
  • 分析錄音時被錄音者是否中止說話

等等用途,能夠用於許多方面,如聲音識別,斷句(音頻分割)等等許多的場景.這裏在之後我也會繼續進行探索.

相關文章
相關標籤/搜索