wave文件也称波形文件,是非常常用的音频格式。和很多文件一样,包括头信息和音频数据。
wave文件格式是开源的,网上也有很多资料。大家可以自行查找学习。头信息大致如下:
偏移地址
|
大小
字节
|
数据块
类型
|
内容
|
00H~03H
|
4
|
4字符
|
资源交换文件标志(RIFF)
|
04H~07H
|
4
|
长整数
|
从下个地址开始到文件尾的总字节数
|
08H~0BH
|
4
|
4字符
|
WAV文件标志(WAVE)
|
0CH~0FH
|
4
|
4字符
|
波形格式标志(fmt ),最后一位空格。
|
10H~13H
|
4
|
整数
|
过滤字节(一般为00000010H)
|
14H~15H
|
2
|
整数
|
格式种类(值为1时,表示数据为线性PCM编码)
|
16H~17H
|
2
|
整数
|
通道数,单声道为1,双声道为2
|
18H~1BH
|
4
|
长整数
|
采样频率
|
1CH~1FH
|
4
|
长整数
|
波形数据传输速率(每秒平均字节数)
|
20H~21H
|
2
|
整数
|
DATA数据块长度,字节。 |
22H~23H
|
2
|
整数
|
PCM位宽
|
24H~27H | 4 | 4字符 |
“fact”,该部分一下是可选部分,即可能有,可能没有,一般到WAV文件由某些软件转换而成时,包含这部分。
|
28H~2BH | 4 |
长整数
|
size,数值为4 |
从上面的表格中可以看出头信息包含了文件的除了音频数据以外的详细信息,包括格式标识,文件大小,采样率,位宽,通道数,每秒钟数据量,数据块个数等等。
头的大小不是固定的,标准的是44字节。
在多声道WAVE文件中,样本是交替出现的。如16bit的单声道WAVE文件和双声道WAVE文件的数据采样格式分别如图四所示:
16位单声道:
采样一 |
采样二 |
…… |
||
低字节 |
高字节 |
低字节 |
高字节 |
…… |
16位双声道:
采样一 |
…… |
|||
左声道 |
右声道 |
…… |
||
低字节 |
高字节 |
低字节 |
高字节 |
…… |
对于WAV文件格式,我在这里不再多做叙述。网上资料确实很充分。
对于WAV文件头解析后,文件头的信息一般保存在我上一篇文章中提到的结构体中:
typedef struct tWAVEFORMATEX { WORD wFormatTag; // Integer identifier of the format WORD nChannels; // Number of audio channels DWORD nSamplesPerSec; // Audio sample rate DWORD nAvgBytesPerSec; // Bytes per second (possibly approximate) WORD nBlockAlign; // Size in bytes of a sample block (all channels) WORD wBitsPerSample; // Size in bits of a single per-channel sample WORD cbSize; // Bytes of extra data appended to this struct } WAVEFORMATEX;
typedef struct tWAVEFORMATEX { WORD wFormatTag;//类型 WORD nChannels;//通道数 DWORD nSamplesPerSec;//采样率 DWORD nAvgBytesPerSec;//每秒钟字节数 WORD nBlockAlign;//字节块 WORD wBitsPerSample;//位宽 WORD cbSize;//结构体大小 } WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;
那么如何解析WAV文件呢?鉴于WAV文件格式是完全公开的,完全可以自己写代码进行解析,但是肯定是比较麻烦的。
其实网上提供了WAV文件的解析类:CWaveFile类。CWaveFile类是网上提供的wav文件读写类。为了方便大家使用,我自己下载并上传了一份:http://download.csdn.net/detail/u011417605/9448136
详细代码如下:
#pragma once //----------------------------------------------------------------------------- // File: WaveFile.h // // Copyright (c) Microsoft Corp. All rights reserved. //----------------------------------------------------------------------------- #ifndef DXUTWAVEFILE_H #define DXUTWAVEFILE_H #include "dsound.h" #include "mmreg.h" #include "DxErr.h" #include "mmsystem.h" #pragma comment(lib, "winmm.lib") #pragma comment(lib, "dsound.lib") #pragma comment(lib, "DxErr.lib") #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } } #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } } #endif #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } #endif //----------------------------------------------------------------------------- // Typing macros //----------------------------------------------------------------------------- #define WAVEFILE_READ 1 #define WAVEFILE_WRITE 2 //----------------------------------------------------------------------------- // Name: class CWaveFile // Desc: Encapsulates reading or writing sound data to or from a wave file //----------------------------------------------------------------------------- class CWaveFile { public: WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure HMMIO m_hmmio; // MM I/O handle for the WAVE MMCKINFO m_ck; // Multimedia RIFF chunk MMCKINFO m_ckRiff; // Use in opening a WAVE file DWORD m_dwSize; // The size of the wave file MMIOINFO m_mmioinfoOut; DWORD m_dwFlags; BOOL m_bIsReadingFromMemory; BYTE* m_pbData; BYTE* m_pbDataCur; ULONG m_ulDataSize; CHAR* m_pResourceBuffer; protected: HRESULT ReadMMIO(); HRESULT WriteMMIO(WAVEFORMATEX* pwfxDest); public: CWaveFile(); ~CWaveFile(); HRESULT Open(LPWSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags); HRESULT OpenFromMemory(BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags); HRESULT Close(); HRESULT Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead); HRESULT Write(UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote); DWORD GetSize(); HRESULT ResetFile(); WAVEFORMATEX* GetFormat() { return m_pwfx; }; }; #endif // DXUTWAVEFILE_H
#include "WaveFile.h" #undef min // use __min instead #undef max // use __max instead //----------------------------------------------------------------------------- // Name: CWaveFile::CWaveFile() // Desc: Constructs the class. Call Open() to open a wave file for reading. // Then call Read() as needed. Calling the destructor or Close() // will close the file. //----------------------------------------------------------------------------- CWaveFile::CWaveFile() { m_pwfx = NULL; m_hmmio = NULL; m_pResourceBuffer = NULL; m_dwSize = 0; m_bIsReadingFromMemory = FALSE; } //----------------------------------------------------------------------------- // Name: CWaveFile::~CWaveFile() // Desc: Destructs the class //----------------------------------------------------------------------------- CWaveFile::~CWaveFile() { Close(); if (!m_bIsReadingFromMemory) SAFE_DELETE_ARRAY(m_pwfx); } //----------------------------------------------------------------------------- // Name: CWaveFile::Open() // Desc: Opens a wave file for reading //----------------------------------------------------------------------------- HRESULT CWaveFile::Open(LPWSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags) { HRESULT hr; m_dwFlags = dwFlags; m_bIsReadingFromMemory = FALSE; if (m_dwFlags == WAVEFILE_READ) { if (strFileName == NULL) return E_INVALIDARG; SAFE_DELETE_ARRAY(m_pwfx); m_hmmio = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ); if (NULL == m_hmmio) { HRSRC hResInfo; HGLOBAL hResData; DWORD dwSize; VOID* pvRes; // Loading it as a file failed, so try it as a resource if (NULL == (hResInfo = FindResource(NULL, strFileName, L"WAVE"))) { if (NULL == (hResInfo = FindResource(NULL, strFileName, L"WAV"))) return DXTRACE_ERR(L"FindResource", E_FAIL); } if (NULL == (hResData = LoadResource(GetModuleHandle(NULL), hResInfo))) return DXTRACE_ERR(L"LoadResource", E_FAIL); if (0 == (dwSize = SizeofResource(GetModuleHandle(NULL), hResInfo))) return DXTRACE_ERR(L"SizeofResource", E_FAIL); if (NULL == (pvRes = LockResource(hResData))) return DXTRACE_ERR(L"LockResource", E_FAIL); m_pResourceBuffer = new CHAR[dwSize]; if (m_pResourceBuffer == NULL) return DXTRACE_ERR(L"new", E_OUTOFMEMORY); memcpy(m_pResourceBuffer, pvRes, dwSize); MMIOINFO mmioInfo; ZeroMemory(&mmioInfo, sizeof(mmioInfo)); mmioInfo.fccIOProc = FOURCC_MEM; mmioInfo.cchBuffer = dwSize; mmioInfo.pchBuffer = (CHAR*)m_pResourceBuffer; m_hmmio = mmioOpen(NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ); } if (FAILED(hr = ReadMMIO())) { // ReadMMIO will fail if its an not a wave file mmioClose(m_hmmio, 0); return DXTRACE_ERR(L"ReadMMIO", hr); } if (FAILED(hr = ResetFile())) return DXTRACE_ERR(L"ResetFile", hr); // After the reset, the size of the wav file is m_ck.cksize so store it now m_dwSize = m_ck.cksize; } else { m_hmmio = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE); if (NULL == m_hmmio) return DXTRACE_ERR(L"mmioOpen", E_FAIL); if (FAILED(hr = WriteMMIO(pwfx))) { mmioClose(m_hmmio, 0); return DXTRACE_ERR(L"WriteMMIO", hr); } if (FAILED(hr = ResetFile())) return DXTRACE_ERR(L"ResetFile", hr); } return hr; } //----------------------------------------------------------------------------- // Name: CWaveFile::OpenFromMemory() // Desc: copy data to CWaveFile member variable from memory //----------------------------------------------------------------------------- HRESULT CWaveFile::OpenFromMemory(BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags) { m_pwfx = pwfx; m_ulDataSize = ulDataSize; m_pbData = pbData; m_pbDataCur = m_pbData; m_bIsReadingFromMemory = TRUE; if (dwFlags != WAVEFILE_READ) return E_NOTIMPL; return S_OK; } //----------------------------------------------------------------------------- // Name: CWaveFile::ReadMMIO() // Desc: Support function for reading from a multimedia I/O stream. // m_hmmio must be valid before calling. This function uses it to // update m_ckRiff, and m_pwfx. //----------------------------------------------------------------------------- HRESULT CWaveFile::ReadMMIO() { MMCKINFO ckIn; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. memset(&ckIn, 0, sizeof(ckIn)); m_pwfx = NULL; if ((0 != mmioDescend(m_hmmio, &m_ckRiff, NULL, 0))) return DXTRACE_ERR(L"mmioDescend", E_FAIL); // Check to make sure this is a valid wave file if ((m_ckRiff.ckid != FOURCC_RIFF) || (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) return DXTRACE_ERR(L"mmioFOURCC", E_FAIL); // Search the input file for for the 'fmt ' chunk. ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); if (0 != mmioDescend(m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK)) return DXTRACE_ERR(L"mmioDescend", E_FAIL); // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; // if there are extra parameters at the end, we'll ignore them if (ckIn.cksize < (LONG)sizeof(PCMWAVEFORMAT)) return DXTRACE_ERR(L"sizeof(PCMWAVEFORMAT)", E_FAIL); // Read the 'fmt ' chunk into <pcmWaveFormat>. if (mmioRead(m_hmmio, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat)) return DXTRACE_ERR(L"mmioRead", E_FAIL); // Allocate the waveformatex, but if its not pcm format, read the next // word, and thats how many extra bytes to allocate. if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) { m_pwfx = (WAVEFORMATEX*)new CHAR[sizeof(WAVEFORMATEX)]; if (NULL == m_pwfx) return DXTRACE_ERR(L"m_pwfx", E_FAIL); // Copy the bytes from the pcm structure to the waveformatex structure memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat)); m_pwfx->cbSize = 0; } else { // Read in length of extra bytes. WORD cbExtraBytes = 0L; if (mmioRead(m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD)) return DXTRACE_ERR(L"mmioRead", E_FAIL); m_pwfx = (WAVEFORMATEX*)new CHAR[sizeof(WAVEFORMATEX) + cbExtraBytes]; if (NULL == m_pwfx) return DXTRACE_ERR(L"new", E_FAIL); // Copy the bytes from the pcm structure to the waveformatex structure memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat)); m_pwfx->cbSize = cbExtraBytes; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. if (mmioRead(m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize)) + sizeof(WORD)), cbExtraBytes) != cbExtraBytes) { SAFE_DELETE(m_pwfx); return DXTRACE_ERR(L"mmioRead", E_FAIL); } } // Ascend the input file out of the 'fmt ' chunk. if (0 != mmioAscend(m_hmmio, &ckIn, 0)) { SAFE_DELETE(m_pwfx); return DXTRACE_ERR(L"mmioAscend", E_FAIL); } return S_OK; } //----------------------------------------------------------------------------- // Name: CWaveFile::GetSize() // Desc: Retuns the size of the read access wave file //----------------------------------------------------------------------------- DWORD CWaveFile::GetSize() { return m_dwSize; } //----------------------------------------------------------------------------- // Name: CWaveFile::ResetFile() // Desc: Resets the internal m_ck pointer so reading starts from the // beginning of the file again //----------------------------------------------------------------------------- HRESULT CWaveFile::ResetFile() { if (m_bIsReadingFromMemory) { m_pbDataCur = m_pbData; } else { if (m_hmmio == NULL) return CO_E_NOTINITIALIZED; if (m_dwFlags == WAVEFILE_READ) { // Seek to the data if (-1 == mmioSeek(m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET)) return DXTRACE_ERR(L"mmioSeek", E_FAIL); // Search the input file for the 'data' chunk. m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (0 != mmioDescend(m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK)) return DXTRACE_ERR(L"mmioDescend", E_FAIL); } else { // Create the 'data' chunk that holds the waveform samples. m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); m_ck.cksize = 0; if (0 != mmioCreateChunk(m_hmmio, &m_ck, 0)) return DXTRACE_ERR(L"mmioCreateChunk", E_FAIL); if (0 != mmioGetInfo(m_hmmio, &m_mmioinfoOut, 0)) return DXTRACE_ERR(L"mmioGetInfo", E_FAIL); } } return S_OK; } //----------------------------------------------------------------------------- // Name: CWaveFile::Read() // Desc: Reads section of data from a wave file into pBuffer and returns // how much read in pdwSizeRead, reading not more than dwSizeToRead. // This uses m_ck to determine where to start reading from. So // subsequent calls will be continue where the last left off unless // Reset() is called. //----------------------------------------------------------------------------- HRESULT CWaveFile::Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead) { if (m_bIsReadingFromMemory) { if (m_pbDataCur == NULL) return CO_E_NOTINITIALIZED; if (pdwSizeRead != NULL) *pdwSizeRead = 0; if ((BYTE*)(m_pbDataCur + dwSizeToRead) > (BYTE*)(m_pbData + m_ulDataSize)) { dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData); } #pragma warning( disable: 4616 ) // disable warning about warning number '22104' being out of range #pragma warning( disable: 22104 ) // disable PREfast warning during static code analysis CopyMemory(pBuffer, m_pbDataCur, dwSizeToRead); #pragma warning( default: 22104 ) #pragma warning( default: 4616 ) if (pdwSizeRead != NULL) *pdwSizeRead = dwSizeToRead; return S_OK; } else { MMIOINFO mmioinfoIn; // current status of m_hmmio if (m_hmmio == NULL) return CO_E_NOTINITIALIZED; if (pBuffer == NULL || pdwSizeRead == NULL) return E_INVALIDARG; *pdwSizeRead = 0; if (0 != mmioGetInfo(m_hmmio, &mmioinfoIn, 0)) return DXTRACE_ERR(L"mmioGetInfo", E_FAIL); UINT cbDataIn = dwSizeToRead; if (cbDataIn > m_ck.cksize) cbDataIn = m_ck.cksize; m_ck.cksize -= cbDataIn; for (DWORD cT = 0; cT < cbDataIn; cT++) { // Copy the bytes from the io to the buffer. if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) { if (0 != mmioAdvance(m_hmmio, &mmioinfoIn, MMIO_READ)) return DXTRACE_ERR(L"mmioAdvance", E_FAIL); if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) return DXTRACE_ERR(L"mmioinfoIn.pchNext", E_FAIL); } // Actual copy. *((BYTE*)pBuffer + cT) = *((BYTE*)mmioinfoIn.pchNext); mmioinfoIn.pchNext++; } if (0 != mmioSetInfo(m_hmmio, &mmioinfoIn, 0)) return DXTRACE_ERR(L"mmioSetInfo", E_FAIL); *pdwSizeRead = cbDataIn; return S_OK; } } //----------------------------------------------------------------------------- // Name: CWaveFile::Close() // Desc: Closes the wave file //----------------------------------------------------------------------------- HRESULT CWaveFile::Close() { if (m_dwFlags == WAVEFILE_READ) { if (m_hmmio != NULL) { mmioClose(m_hmmio, 0); m_hmmio = NULL; } SAFE_DELETE_ARRAY(m_pResourceBuffer); } else { m_mmioinfoOut.dwFlags |= MMIO_DIRTY; if (m_hmmio == NULL) return CO_E_NOTINITIALIZED; if (0 != mmioSetInfo(m_hmmio, &m_mmioinfoOut, 0)) return DXTRACE_ERR(L"mmioSetInfo", E_FAIL); // Ascend the output file out of the 'data' chunk -- this will cause // the chunk size of the 'data' chunk to be written. if (0 != mmioAscend(m_hmmio, &m_ck, 0)) return DXTRACE_ERR(L"mmioAscend", E_FAIL); // Do this here instead... if (0 != mmioAscend(m_hmmio, &m_ckRiff, 0)) return DXTRACE_ERR(L"mmioAscend", E_FAIL); mmioSeek(m_hmmio, 0, SEEK_SET); if (0 != (INT)mmioDescend(m_hmmio, &m_ckRiff, NULL, 0)) return DXTRACE_ERR(L"mmioDescend", E_FAIL); m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't'); if (0 == mmioDescend(m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK)) { DWORD dwSamples = 0; mmioWrite(m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD)); mmioAscend(m_hmmio, &m_ck, 0); } // Ascend the output file out of the 'RIFF' chunk -- this will cause // the chunk size of the 'RIFF' chunk to be written. if (0 != mmioAscend(m_hmmio, &m_ckRiff, 0)) return DXTRACE_ERR(L"mmioAscend", E_FAIL); mmioClose(m_hmmio, 0); m_hmmio = NULL; } return S_OK; } //----------------------------------------------------------------------------- // Name: CWaveFile::WriteMMIO() // Desc: Support function for reading from a multimedia I/O stream // pwfxDest is the WAVEFORMATEX for this new wave file. // m_hmmio must be valid before calling. This function uses it to // update m_ckRiff, and m_ck. //----------------------------------------------------------------------------- HRESULT CWaveFile::WriteMMIO(WAVEFORMATEX* pwfxDest) { DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile. MMCKINFO ckOut1; memset(&ckOut1, 0, sizeof(ckOut1)); dwFactChunk = (DWORD)-1; // Create the output file RIFF chunk of form type 'WAVE'. m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E'); m_ckRiff.cksize = 0; if (0 != mmioCreateChunk(m_hmmio, &m_ckRiff, MMIO_CREATERIFF)) return DXTRACE_ERR(L"mmioCreateChunk", E_FAIL); // We are now descended into the 'RIFF' chunk we just created. // Now create the 'fmt ' chunk. Since we know the size of this chunk, // specify it in the MMCKINFO structure so MMIO doesn't have to seek // back and set the chunk size after ascending from the chunk. m_ck.ckid = mmioFOURCC('f', 'm', 't', ' '); m_ck.cksize = sizeof(PCMWAVEFORMAT); if (0 != mmioCreateChunk(m_hmmio, &m_ck, 0)) return DXTRACE_ERR(L"mmioCreateChunk", E_FAIL); // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type. if (pwfxDest->wFormatTag == WAVE_FORMAT_PCM) { if (mmioWrite(m_hmmio, (HPSTR)pwfxDest, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT)) return DXTRACE_ERR(L"mmioWrite", E_FAIL); } else { // Write the variable length size. if ((UINT)mmioWrite(m_hmmio, (HPSTR)pwfxDest, sizeof(*pwfxDest) + pwfxDest->cbSize) != (sizeof(*pwfxDest) + pwfxDest->cbSize)) return DXTRACE_ERR(L"mmioWrite", E_FAIL); } // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk. if (0 != mmioAscend(m_hmmio, &m_ck, 0)) return DXTRACE_ERR(L"mmioAscend", E_FAIL); // Now create the fact chunk, not required for PCM but nice to have. This is filled // in when the close routine is called. ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't'); ckOut1.cksize = 0; if (0 != mmioCreateChunk(m_hmmio, &ckOut1, 0)) return DXTRACE_ERR(L"mmioCreateChunk", E_FAIL); if (mmioWrite(m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) != sizeof(dwFactChunk)) return DXTRACE_ERR(L"mmioWrite", E_FAIL); // Now ascend out of the fact chunk... if (0 != mmioAscend(m_hmmio, &ckOut1, 0)) return DXTRACE_ERR(L"mmioAscend", E_FAIL); return S_OK; } //----------------------------------------------------------------------------- // Name: CWaveFile::Write() // Desc: Writes data to the open wave file //----------------------------------------------------------------------------- HRESULT CWaveFile::Write(UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote) { UINT cT; if (m_bIsReadingFromMemory) return E_NOTIMPL; if (m_hmmio == NULL) return CO_E_NOTINITIALIZED; if (pnSizeWrote == NULL || pbSrcData == NULL) return E_INVALIDARG; *pnSizeWrote = 0; for (cT = 0; cT < nSizeToWrite; cT++) { if (m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite) { m_mmioinfoOut.dwFlags |= MMIO_DIRTY; if (0 != mmioAdvance(m_hmmio, &m_mmioinfoOut, MMIO_WRITE)) return DXTRACE_ERR(L"mmioAdvance", E_FAIL); } *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData + cT); (BYTE*)m_mmioinfoOut.pchNext++; (*pnSizeWrote)++; } return S_OK; }
备注:请尊重版权,转载请联系作者QQ:1245178753。
交流请加:
群名称:XAudio2 交流群
群 号:233537460
本文链接:http://blog.csdn.net/u011417605/article/details/50766317
另:微软自带的CWaveFile:http://download.csdn.net/detail/u011417605/9452340