1. 程式人生 > >wav檔案格式分析(程式碼 C++ )

wav檔案格式分析(程式碼 C++ )

下面就來分析一下wav波形檔案的格式。

  我們先隨便找一個wav檔案,檢視其屬性,就能得到下面的結果。

        

  上面主要注意檔案大小,聲音長度與位元率。

  檔案佔用空間就不用關心了,如果有人想知道為什麼檔案佔用空間比檔案大小要大,我在這裡也解釋一下。這和檔案在硬碟中的組織方式有關係,這裡的硬碟分割槽是以最小4096Byte為單位的,我檔案的大小是1325044Byte,那麼1325044/4096=323.49,為了能把檔案對齊的放到硬碟中,所以佔用的空間就要是324*4096=1327104Byte了,所以佔用的空間就是這麼多了。你也可以建立一個只寫一個字母的txt檔案試試,檔案大小雖然為1Byte,不過佔用空間也為4096Byte。

  上面說的當然和wav檔案沒什麼關係,下面就正式說wav檔案的問題。

  用ultraedit開啟就是下面這個樣子:

  用表格說明一下檔案的格式:

起始地址

佔用空間

本地址數字的含義

00H

4byte

RIFF,資源交換檔案標誌。

04H

4byte

從下一個地址開始到檔案尾的總位元組數。高位位元組在後面,這裡就是001437ECH,換成十進位制是1325036byte,算上這之前的8byte就正好1325044byte了。

08H

4byte

WAVE,代表wav檔案格式。

0CH

4byte

FMT ,波形格式標誌

10H

4byte

00000010H,16PCM,我的理解是用16bit的資料表示一個量化結果。

14H

2byte

為1時表示線性PCM編碼,大於1時表示有壓縮的編碼。這裡是0001H。

16H

2byte

1為單聲道,2為雙聲道,這裡是0001H。

18H

4byte

取樣頻率,這裡是00002B11H,也就是11025Hz。

1CH

4byte

Byte率=取樣頻率*音訊通道數*每次取樣得到的樣本位數/8,00005622H,也就是22050Byte/s=11025*1*16/2。

20H

2byte

塊對齊=通道數*每次取樣得到的樣本位數/8,0002H,也就是2=1*16/8。

22H

2byte

樣本資料位數,0010H即16,一個量化樣本佔2byte。

24H

4byte

data,一個標誌而已。

28H

4byte

Wav檔案實際音訊資料所佔的大小,這裡是001437C8H即1325000,再加上2CH就正好是1325044,整個檔案的大小。

2CH

不定

量化資料。

  注意屬性中的位元率是176kbps,而1CH中為22050Byte/s,換算一下就會發現22050*8/1024並不等於176,而是等於172,這裡我想可能是通訊中的1K並不等於1024而是等於1000的原因(通訊原理書中好像有),如果按22050*8/1000這樣算,就正好等於176了。其實位元率也可以這樣算,總位元組除以時長得到每秒位元組率,再乘以8除以1000就得到位元率了,即(1325000/60)*8/1000=176kbps。

  最後是量化資料的表示。

  看資料結尾的表示吧,我這音訊最初那一段都是0,不好解釋。

  Ultraedit中的表示:

  Matlab中的表示:

  上面的matlab是662500個數,正好也是11325000的一半。可以看出資料是有正有負的浮點數,為正負雙向PCM量化編碼,得到的十六進位制位的最高位是一個符號位,為0表示正數,為1表示負數,正好表示-32768~32767。而且十六進位制的資料正數要除以32767,負數要除以32768才能得到結果,如果是單向PCM就要除以65535了。

  比如最後一位十六進位制為2710H,在Matlab中為0.3052,而2710H的十進位制10000除以32767正好近似為0.3052。

  再比如matlab中662472這個數為-0.0206,考慮到44位的偏差,在ultraedit中為1437BAH位上的FD5DH,表示為十進位制-675除以32768正好近似為-0.0206。

  當然,上面只是針對matlab和ultraedit中的資料進行具體的分析,真正程式設計處理時還是要根據情況有所不同的。量化位數的不同,32bit或是8bit處理又不同了。符號的表示也可能不同,原碼補碼反碼等等的知識可能也要用到。

這裡我只把基本的資料提取出來了,沒有進行下一步處理,資料提取出來,後面怎麼應用就看具體情況了。

複製程式碼
#include <iostream>
#include <fstream>
using namespace std;

struct wav_struct
{
    unsigned long file_size;        //檔案大小
    unsigned short channel;            //通道數
    unsigned long frequency;        //取樣頻率
    unsigned long Bps;                //Byte率
    unsigned short sample_num_bit;    //一個樣本的位數
    unsigned long data_size;        //資料大小
    unsigned char *data;            //音訊資料 ,這裡要定義什麼就看樣本位數了,我這裡只是單純的複製資料

};

int main(int argc,char **argv)
{
    fstream fs;
    wav_struct WAV;
    fs.open("B:\\output.wav",ios::binary|ios::in);

//    fs.seekg(0x04);                //從檔案資料中獲取檔案大小
//    fs.read((char*)&WAV.file_size,sizeof(WAV.file_size));
//    WAV.file_size+=8;
    
    fs.seekg(0,ios::end);        //用c++常用方法獲得檔案大小
    WAV.file_size=fs.tellg();

    fs.seekg(0x14);
    fs.read((char*)&WAV.channel,sizeof(WAV.channel));

    fs.seekg(0x18);
    fs.read((char*)&WAV.frequency,sizeof(WAV.frequency));

    fs.seekg(0x1c);
    fs.read((char*)&WAV.Bps,sizeof(WAV.Bps));

    fs.seekg(0x22);
    fs.read((char*)&WAV.sample_num_bit,sizeof(WAV.sample_num_bit));

    fs.seekg(0x28);
    fs.read((char*)&WAV.data_size,sizeof(WAV.data_size));

    WAV.data=new unsigned char[WAV.data_size];

    fs.seekg(0x2c);
    fs.read((char *)WAV.data,sizeof(char)*WAV.data_size);

    cout<<"檔案大小為  :"<<WAV.file_size<<endl;
    cout<<"音訊通道數  :"<<WAV.channel<<endl;
    cout<<"取樣頻率    :"<<WAV.frequency<<endl;
    cout<<"Byte率      :"<<WAV.Bps<<endl;
    cout<<"樣本位數    :"<<WAV.sample_num_bit<<endl;
    cout<<"音訊資料大小:"<<WAV.data_size<<endl;
    cout<<"最後20個數據:"<<endl;

    for (unsigned long i=WAV.data_size-20;i<WAV.data_size;i++)
    {
        printf("%x  ",WAV.data[i]);
    }
    fs.close();

    delete[] WAV.data;
    system("pause");

}
複製程式碼

執行結果: