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);
}
}