不知道有何原因,無聊就想知道wav格式到底是長怎樣,一時興起就用C++寫了以下代碼來解析它,
先來看一下它的Header長什麼樣子,圖片來自維基百科。
經過整理之後,我們可以用C++定義出如下的structure。
//Wav.h #ifndef _WAVHPP #define _WAVHPP #include "StdInclude.h" typedef struct _sWavFormat //begin offset { uint32_t dwSectionLabel; //0 uint32_t dwSize; //4 uint32_t dwFormat; //8 uint32_t dwSubSectionOneLable; //12 uint32_t dwSubSectionOneSize; //16 uint16_t wAudioFormat; //20 uint16_t wNumOfChannels; //22 uint32_t dwSamplingFrequency; //24 uint16_t wBytesFrequency; //28 uint16_t wAlign; //32 uint16_t wBytesDepth; //34 uint32_t dwSubSectionTwoLable; //36 uint32_t dwSubSectionTwoSize; //40 //remain data begin on 44 is all usefull data. }sWavFormat; #endif
接著主程式
#include "StdInclude.h" #include "wav.h" using namespace std; int main() { string strFileName; cout<<"FileNamne:"<<endl; cin>>strFileName; ifstream fs; fs.open(strFileName.c_str(),std::ifstream::binary);//用binary方式開啟,不然默認是文字模式 sWavFormat swf; fs.seekg(0,ios::end); //將讀寫指針移到最後 cout<<"FileSize is: "<<fs.tellg()<<"bytes"<<endl;//讀取指針位置,獲取文件大小 cout<<"Read from structure."<<endl;//開始用我們剛剛定義過的結構進行讀取 cout<<string(60,'=')<<endl; //ReadMetaData fs.seekg(0,fs.beg);//將文件指針重新設定回文件頭部 fs.read((char*)&swf,sizeof(swf));//讀取一整個我們剛剛定義過的structure大小的資料 //PrintValue int ofs=80; //格式化一下打印的樣式 cout<<"swf.dwSize"<<setw(ofs)<<swf.dwSize<<endl; //讀進來的數轉換成ascii編碼 char buffer[5];//大小為4byte但是要預留空自浮標示結尾。 memcpy(buffer,&(swf.dwFormat),sizeof(swf.dwFormat)); buffer[5]='\0'; cout<<"swf.dwFormat"<<setw(ofs)<<string(buffer)<<endl;//開始打印 memcpy(buffer,&(swf.dwSubSectionOneLable),sizeof(uint32_t)); cout<<"swf.dwSectionOneLabel"<<setw(ofs)<<string(buffer)<<endl; cout<<"swf.dwSectionOneSize"<<setw(ofs)<<swf.dwSubSectionOneSize<<endl; cout<<"swf.wAudioFormat"<<setw(ofs)<<swf.wAudioFormat<<endl; cout<<"swf.wNumOfChannels"<<setw(ofs)<<swf.wNumOfChannels<<endl; cout<<"swf.dwSamplingFrequency"<<setw(ofs)<<swf.dwSamplingFrequency<<endl; cout<<"swf.dwBytesFrequency"<<setw(ofs)<<swf.wBytesFrequency<<endl; cout<<"swf.wAlign"<<setw(ofs)<<swf.wAlign<<endl; cout<<"swf.wBytesDepth"<<setw(ofs)<<swf.wBytesDepth<<endl; cout<<"swf.dwSubSectionTwoLable"<<setw(ofs) \ <<swf.dwSubSectionTwoLable<<endl; cout<<"swf.dwSubSectionTwoSize"<<setw(ofs) \ <<swf.dwSubSectionTwoSize<<endl; return 0; };//end main
如果上面有看到"StdInclude.h"這個頭文件,其實它只是將平常要用的標準頭文件進行引入而已
#ifndef _STDINCLUDEHPP #define _STDINCLUDEHPP #include <iostream> #include <windows.h> #include <utility> #include <iomanip> #include <vector> #include <string> #include <functional> #include <fstream> #include <cinttypes> #endif
其中<cinttypes>是我第一次用過的頭文件,以前都用windows.h中定義的WORD、DWORD進行資料結構宣告,
用了這個之後發現代碼可讀性更高且它是內建標準,
示範一下:
uint8_t =8 byte;
uint16_t =16 byte;
uint32_t =32byte;