WaveFile.cpp
上传用户:goak128
上传日期:2013-07-17
资源大小:155k
文件大小:7k
源码类别:

控制台编程

开发平台:

C/C++

  1. //////////////////////////////////////////////////////////////////////////
  2. // class CWaveFile
  3. //
  4. // 功能: 实现wav文件的操作
  5. // 创建人: 陈文凯 (chwkai@gmail.com)
  6. // 创建日期:2005年5月19日
  7. // 修改人:
  8. // 修改日期:
  9. // 版本
  10. #include "StdAfx.h"
  11. #include ".wavefile.h"
  12. //////////////////////////////////////////////////////////////////////////
  13. // 默认构造函数
  14. CWaveFile::CWaveFile()
  15. {
  16. this->Close();
  17. }
  18. //////////////////////////////////////////////////////////////////////////
  19. // 构造函数
  20. CWaveFile::CWaveFile(LPCTSTR lpszFileName, UINT nOpenFlags)
  21. {
  22. this->Open(lpszFileName, nOpenFlags);
  23. }
  24. //////////////////////////////////////////////////////////////////////////
  25. // 系构函数
  26. CWaveFile::~CWaveFile(void)
  27. {
  28. this->Close();
  29. }
  30. //////////////////////////////////////////////////////////////////////////
  31. // 打开wav文件,并读入header信息
  32. BOOL CWaveFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags)
  33. {
  34. // 若文件已经打开则先关闭
  35. this->Close();
  36. // 打开文件
  37. BOOL bRet = this->m_wavFile.Open(lpszFileName, nOpenFlags);
  38. // 判断文件是否打开
  39. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  40. {
  41. // 读取文件头信息
  42. this->ReadHeader();
  43. }
  44. return bRet;
  45. }
  46. //////////////////////////////////////////////////////////////////////////
  47. // 关闭wave文件,且将数据置0
  48. void CWaveFile::Close()
  49. {
  50. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  51. {
  52. this->m_wavFile.Close();
  53. }
  54. this->m_nDataStartFrom = 0;
  55. this->m_dwDataChunkSize = 0;
  56. this->m_nBytesWritten = 0;
  57. }
  58. //////////////////////////////////////////////////////////////////////////
  59. // wave文件指针返回到数据部分起始位置
  60. void CWaveFile::Reset()
  61. {
  62. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  63. {
  64. this->m_wavFile.Seek(this->m_nDataStartFrom, CFile::begin);
  65. }
  66. }
  67. //////////////////////////////////////////////////////////////////////////
  68. // 返回wave文件的format chunk信息
  69. WAVEFORMATEX CWaveFile::GetWaveFormat() const
  70. {
  71. WAVEFORMATEX fmt;
  72. fmt.nAvgBytesPerSec = this->m_format.dwAvgBytesPerSec;
  73. fmt.nBlockAlign = this->m_format.wBlockAlign;
  74. fmt.nChannels = this->m_format.wChannels;
  75. fmt.nSamplesPerSec = this->m_format.dwSamplesPerSec;
  76. fmt.wBitsPerSample = this->m_format.wBitsPerSample;
  77. fmt.wFormatTag = this->m_format.wFormatTag;
  78. fmt.cbSize = this->m_format.wReserved;
  79. return fmt;
  80. }
  81. //////////////////////////////////////////////////////////////////////////
  82. // 用于wave读取,读取wave的Format信息,并记录data开始位置
  83. void CWaveFile::ReadHeader()
  84. {
  85. INT nOffSet= 0;
  86. UINT nRead = 0;
  87. FormatChunk fmt;
  88. DataChunkHeader dataHeader;
  89. char chunkId[5];
  90. DWORD chunkSize;
  91. // 文件是否打开
  92. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  93. {
  94. // 计算Riff header的长度, 文件指针移到riff header之后
  95. nOffSet = sizeof(RiffHeader);
  96. this->m_wavFile.Seek(nOffSet, CFile::begin);
  97. // 读取format chunk
  98. nRead = this->m_wavFile.Read(&fmt, sizeof(fmt));
  99. // 读取Data Chunk header信息
  100. // 计算fmt chunk的长度,移动到下一个chunk的起始处
  101. nOffSet = fmt.chunkSize + sizeof(fmt.chunkId) + sizeof(fmt.chunkSize) - nRead;
  102. this->m_wavFile.Seek(nOffSet, CFile::current);
  103. // 实现strcmp判断
  104. chunkId[4] = '';
  105. // 忽略其他的chunk
  106. while (nRead > 0)
  107. {
  108. nRead = this->m_wavFile.Read(chunkId, sizeof(chunkId) - sizeof(char));
  109. // 查找data chunk
  110. if (strcmp(chunkId, DEFAULT_DATA_ID) == 0)
  111. {
  112. // 返回data chunk起始位置
  113. nOffSet = sizeof(char) - sizeof(chunkId);
  114. this->m_wavFile.Seek(nOffSet, CFile::current);
  115. this->m_wavFile.Read(&dataHeader, sizeof(dataHeader));
  116. break;
  117. }
  118. else
  119. {
  120. // 忽略其他chunk
  121. nRead = this->m_wavFile.Read(&chunkSize, sizeof(chunkSize));
  122. this->m_wavFile.Seek(chunkSize, CFile::current);
  123. }
  124. }
  125. // 保存裸音频数据起始位置
  126. this->m_nDataStartFrom = this->m_wavFile.GetPosition();
  127. // 保存format信息
  128. this->m_format = fmt;
  129. // 保存裸音频数据总长度
  130. this->m_dwDataChunkSize = dataHeader.chunkSize;
  131. }
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134. // 用于wave读取,桉字节数读取裸数据
  135. UINT CWaveFile::ReadBytes(void* pData, UINT nCount)
  136. {
  137. UINT nRead = 0;
  138. // 文件是否打开
  139. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  140. {
  141. nRead = this->m_wavFile.Read(pData, nCount);
  142. }
  143. return nRead;
  144. }
  145. //////////////////////////////////////////////////////////////////////////
  146. // 按bytes写入数据
  147. void CWaveFile::WriteBytes(void* pData, UINT nCount)
  148. {
  149. // 文件是否打开
  150. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  151. {
  152. this->m_wavFile.Write(pData, nCount);
  153. //记录所写入的总字节数
  154. this->m_nBytesWritten += nCount;
  155. }
  156. }
  157. //////////////////////////////////////////////////////////////////////////
  158. // 用于wave写入,写入wave文件的Format和Riff信息
  159. void CWaveFile::WriteHeader()
  160. {
  161. RiffHeader riff;
  162. DataChunkHeader dataHeader;
  163. // 文件是否打开
  164. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  165. {
  166. // 准备data header
  167. dataHeader.chunkId[0] = 'd';
  168. dataHeader.chunkId[1] = 'a';
  169. dataHeader.chunkId[2] = 't';
  170. dataHeader.chunkId[3] = 'a';
  171. dataHeader.chunkSize = this->m_nBytesWritten;
  172. // 准备Riff header
  173. riff.groupId[0] = 'R';
  174. riff.groupId[1] = 'I';
  175. riff.groupId[2] = 'F';
  176. riff.groupId[3] = 'F';
  177. riff.riffTypeId[0] = 'W';
  178. riff.riffTypeId[1] = 'A';
  179. riff.riffTypeId[2] = 'V';
  180. riff.riffTypeId[3] = 'E';
  181. // 计算并写入riff chunksize
  182. riff.chunkSize = sizeof(riff.riffTypeId) + sizeof(FormatChunk) + 
  183. sizeof(DataChunkHeader) + this->m_nBytesWritten;
  184. // 经头部信息写入文件
  185. this->m_wavFile.Seek(0, CFile::begin);
  186. this->m_wavFile.Write(&riff, sizeof(RiffHeader));
  187. this->m_wavFile.Write(&this->m_format, sizeof(FormatChunk));
  188. this->m_wavFile.Write(&dataHeader, sizeof(DataChunkHeader));
  189. }
  190. }
  191. //////////////////////////////////////////////////////////////////////////
  192. // 用于wave写入,在wave文件首部预留写入riff header + format chunk + data chunk header的空间,
  193. // 并设定wave的format chunk
  194. void CWaveFile::PrepareWriteHeader(WAVEFORMATEX& fmt)
  195. {
  196. UINT nOffSet = 0;
  197. // 文件是否打开
  198. if (this->m_wavFile.m_hFile != CFile::hFileNull)
  199. {
  200. // 设定format信息
  201. this->m_format.dwSamplesPerSec = fmt.nSamplesPerSec;
  202. this->m_format.wBitsPerSample = fmt.wBitsPerSample;
  203. this->m_format.wChannels = fmt.nChannels;
  204. this->m_format.wBlockAlign = 
  205. this->m_format.wChannels * (this->m_format.wBitsPerSample % 8);
  206. this->m_format.dwAvgBytesPerSec = 
  207. this->m_format.wBlockAlign * this->m_format.dwSamplesPerSec;
  208. this->m_format.wFormatTag = WAVE_FORMAT_PCM;
  209. this->m_format.chunkSize = 
  210. sizeof(FormatChunk) - sizeof(this->m_format.chunkId) - sizeof(this->m_format.chunkSize);
  211. // 设定format chunk id
  212. this->m_format.chunkId[0] = 'f';
  213. this->m_format.chunkId[1] = 'm';
  214. this->m_format.chunkId[2] = 't';
  215. //wave文件头部预留空间写入riff header + format chunk + data chunk header
  216. nOffSet = sizeof(RiffHeader) + sizeof(FormatChunk) + sizeof(DataChunkHeader);
  217. this->m_wavFile.Seek(nOffSet, CFile::begin);
  218. }
  219. }