www.pudn.com > hmmPlatform.rar > WaveFile.cpp


////////////////////////////////////////////////////////////////////////// 
// class CWaveFile 
// 
// 功能:	实现wav文件的操作 
// 创建人:	陈文凯 (chwkai@gmail.com) 
// 创建日期:2005年5月19日 
// 修改人: 
// 修改日期: 
// 版本 
 
#include "StdAfx.h" 
#include ".\wavefile.h" 
 
////////////////////////////////////////////////////////////////////////// 
// 默认构造函数 
CWaveFile::CWaveFile() 
{ 
	this->Close(); 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 构造函数 
CWaveFile::CWaveFile(LPCTSTR lpszFileName, UINT nOpenFlags) 
{ 
	this->Open(lpszFileName, nOpenFlags); 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 系构函数 
CWaveFile::~CWaveFile(void) 
{ 
	this->Close(); 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 打开wav文件,并读入header信息 
BOOL CWaveFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags) 
{ 
	// 若文件已经打开则先关闭 
	this->Close();	 
 
	// 打开文件 
	BOOL bRet = this->m_wavFile.Open(lpszFileName, nOpenFlags); 
 
	// 判断文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		// 读取文件头信息 
		this->ReadHeader(); 
	} 
 
	return bRet; 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 关闭wave文件,且将数据置0 
void CWaveFile::Close() 
{ 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		this->m_wavFile.Close(); 
	} 
 
	this->m_nDataStartFrom = 0; 
	this->m_dwDataChunkSize = 0; 
	this->m_nBytesWritten = 0; 
} 
 
////////////////////////////////////////////////////////////////////////// 
// wave文件指针返回到数据部分起始位置 
void CWaveFile::Reset() 
{ 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		this->m_wavFile.Seek(this->m_nDataStartFrom, CFile::begin); 
	} 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 返回wave文件的format chunk信息 
WAVEFORMATEX CWaveFile::GetWaveFormat() const 
{ 
	WAVEFORMATEX fmt; 
 
	fmt.nAvgBytesPerSec = this->m_format.dwAvgBytesPerSec; 
	fmt.nBlockAlign = this->m_format.wBlockAlign; 
	fmt.nChannels = this->m_format.wChannels; 
	fmt.nSamplesPerSec = this->m_format.dwSamplesPerSec; 
	fmt.wBitsPerSample = this->m_format.wBitsPerSample; 
	fmt.wFormatTag = this->m_format.wFormatTag; 
	fmt.cbSize = this->m_format.wReserved; 
 
	return fmt; 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 用于wave读取,读取wave的Format信息,并记录data开始位置 
void CWaveFile::ReadHeader() 
{	 
	INT nOffSet= 0; 
	UINT nRead = 0; 
	FormatChunk fmt; 
	DataChunkHeader dataHeader; 
 
	char chunkId[5]; 
	DWORD chunkSize; 
 
	// 文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		// 计算Riff header的长度, 文件指针移到riff header之后 
		nOffSet = sizeof(RiffHeader); 
		this->m_wavFile.Seek(nOffSet, CFile::begin); 
 
		// 读取format chunk 
		nRead = this->m_wavFile.Read(&fmt, sizeof(fmt)); 
 
		// 读取Data Chunk header信息 
		 
		// 计算fmt chunk的长度,移动到下一个chunk的起始处 
		nOffSet = fmt.chunkSize + sizeof(fmt.chunkId) + sizeof(fmt.chunkSize) - nRead; 
		this->m_wavFile.Seek(nOffSet, CFile::current); 
		// 实现strcmp判断 
		chunkId[4] = '\0'; 
 
		// 忽略其他的chunk 
		while (nRead > 0) 
		{ 
			nRead = this->m_wavFile.Read(chunkId, sizeof(chunkId) - sizeof(char)); 
 
			// 查找data chunk 
			if (strcmp(chunkId, DEFAULT_DATA_ID) == 0) 
			{ 
				// 返回data chunk起始位置 
				nOffSet = sizeof(char) - sizeof(chunkId); 
				this->m_wavFile.Seek(nOffSet, CFile::current); 
				this->m_wavFile.Read(&dataHeader, sizeof(dataHeader)); 
 
				break; 
			} 
			else 
			{ 
				// 忽略其他chunk 
				nRead = this->m_wavFile.Read(&chunkSize, sizeof(chunkSize)); 
 
				this->m_wavFile.Seek(chunkSize, CFile::current); 
			} 
		} 
 
		// 保存裸音频数据起始位置 
		this->m_nDataStartFrom = this->m_wavFile.GetPosition(); 
		// 保存format信息 
		this->m_format = fmt; 
		// 保存裸音频数据总长度 
		this->m_dwDataChunkSize = dataHeader.chunkSize; 
	} 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 用于wave读取,桉字节数读取裸数据 
UINT CWaveFile::ReadBytes(void* pData, UINT nCount) 
{ 
	UINT nRead = 0; 
 
	// 文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		nRead = this->m_wavFile.Read(pData, nCount); 
	} 
 
	return nRead; 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 按bytes写入数据 
void CWaveFile::WriteBytes(void* pData, UINT nCount) 
{ 
	// 文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		this->m_wavFile.Write(pData, nCount); 
 
		//记录所写入的总字节数 
		this->m_nBytesWritten += nCount; 
	} 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 用于wave写入,写入wave文件的Format和Riff信息 
void CWaveFile::WriteHeader() 
{ 
	RiffHeader riff; 
	DataChunkHeader dataHeader; 
 
	// 文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		// 准备data header 
		dataHeader.chunkId[0] = 'd'; 
		dataHeader.chunkId[1] = 'a'; 
		dataHeader.chunkId[2] = 't'; 
		dataHeader.chunkId[3] = 'a'; 
		dataHeader.chunkSize = this->m_nBytesWritten; 
 
		// 准备Riff header 
		riff.groupId[0] = 'R'; 
		riff.groupId[1] = 'I'; 
		riff.groupId[2] = 'F'; 
		riff.groupId[3] = 'F'; 
		riff.riffTypeId[0] = 'W'; 
		riff.riffTypeId[1] = 'A'; 
		riff.riffTypeId[2] = 'V'; 
		riff.riffTypeId[3] = 'E'; 
		// 计算并写入riff chunksize 
		riff.chunkSize = sizeof(riff.riffTypeId) + sizeof(FormatChunk) +  
			sizeof(DataChunkHeader) + this->m_nBytesWritten; 
 
		// 经头部信息写入文件 
		this->m_wavFile.Seek(0, CFile::begin); 
		this->m_wavFile.Write(&riff, sizeof(RiffHeader)); 
		this->m_wavFile.Write(&this->m_format, sizeof(FormatChunk)); 
		this->m_wavFile.Write(&dataHeader, sizeof(DataChunkHeader)); 
	} 
} 
 
////////////////////////////////////////////////////////////////////////// 
// 用于wave写入,在wave文件首部预留写入riff header + format chunk + data chunk header的空间, 
// 并设定wave的format chunk 
void CWaveFile::PrepareWriteHeader(WAVEFORMATEX& fmt) 
{ 
	UINT nOffSet = 0; 
 
	// 文件是否打开 
	if (this->m_wavFile.m_hFile != CFile::hFileNull) 
	{ 
		// 设定format信息 
		this->m_format.dwSamplesPerSec = fmt.nSamplesPerSec; 
		this->m_format.wBitsPerSample = fmt.wBitsPerSample; 
		this->m_format.wChannels = fmt.nChannels; 
		this->m_format.wBlockAlign =  
			this->m_format.wChannels * (this->m_format.wBitsPerSample % 8); 
		this->m_format.dwAvgBytesPerSec =  
			this->m_format.wBlockAlign * this->m_format.dwSamplesPerSec; 
		this->m_format.wFormatTag = WAVE_FORMAT_PCM; 
		this->m_format.chunkSize =  
			sizeof(FormatChunk) - sizeof(this->m_format.chunkId) - sizeof(this->m_format.chunkSize); 
 
		// 设定format chunk id 
		this->m_format.chunkId[0] = 'f'; 
		this->m_format.chunkId[1] = 'm'; 
		this->m_format.chunkId[2] = 't'; 
 
		//wave文件头部预留空间写入riff header + format chunk + data chunk header 
		nOffSet = sizeof(RiffHeader) + sizeof(FormatChunk) + sizeof(DataChunkHeader); 
 
		this->m_wavFile.Seek(nOffSet, CFile::begin); 
	} 
}