儲存格式理解筆記(一)WAV格式分析,使用C++

时间:2021-09-01 19:44:47

不知道有何原因,無聊就想知道wav格式到底是長怎樣,一時興起就用C++寫了以下代碼來解析它,

先來看一下它的Header長什麼樣子,圖片來自維基百科。

儲存格式理解筆記(一)WAV格式分析,使用C++

經過整理之後,我們可以用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;