windows-nt/Source/XPSP1/NT/multimedia/directx/dxvb/dx8vb/wave.cpp

863 lines
23 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: wave.cpp
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include "Direct.h"
#include "dSound.h"
#include "dms.h"
#include <mmreg.h>
#include <msacm.h>
// FOURCC codes
#undef FOURCC_RIFF
#define FOURCC_RIFF 'FFIR'
#undef FOURCC_MEM
#define FOURCC_MEM ' MEM'
#undef FOURCC_WAVE
#define FOURCC_WAVE 'EVAW'
#undef FOURCC_FORMAT
#define FOURCC_FORMAT ' tmf'
#undef FOURCC_DATA
#define FOURCC_DATA 'atad'
#define RPF(level,str,err) \
{ char outBuf[MAX_PATH]; \
wsprintf(outBuf,str,err); \
OutputDebugString(outBuf); \
}
#define DPFLVL_ERROR 1
/***************************************************************************
*
* FillWfx
*
* Description:
* Fills a WAVEFORMATEX structure, given only the necessary values.
*
* Arguments:
* LPWAVEFORMATEX [out]: structure to fill.
* WORD [in]: number of channels.
* DWORD [in]: samples per second.
* WORD [in]: bits per sample.
*
* Returns:
* (void)
*
***************************************************************************/
#undef DPF_FNAME
void FillWfx(LPWAVEFORMATEX pwfx, WORD wChannels, DWORD dwSamplesPerSec, WORD wBitsPerSample)
{
pwfx->wFormatTag = WAVE_FORMAT_PCM;
pwfx->nChannels = min(2, max(1, wChannels));
pwfx->nSamplesPerSec = min(DSBFREQUENCY_MAX, max(DSBFREQUENCY_MIN, dwSamplesPerSec));
if(wBitsPerSample < 12)
{
pwfx->wBitsPerSample = 8;
}
else
{
pwfx->wBitsPerSample = 16;
}
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
pwfx->cbSize = 0;
}
#if 0
HRESULT InternalCreateSoundBuffer(LPDSBUFFERDESC pDsbDesc, byte *pbWaveData,DWORD cbWaveData,LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER *lplpDirectSoundBuffer)
{
HRESULT hr = DS_OK;
HACMSTREAM has = NULL;
BOOL fPrep = FALSE;
ACMSTREAMHEADER ash;
DWORD dwBufferBytes;
LPVOID pvWrite;
DWORD cbWrite;
HMMIO hmm = NULL;
MMRESULT mmr;
MMIOINFO mmioinfo;
MMCKINFO ckiRiff;
MMCKINFO cki;
LPWAVEFORMATEX pwfxSrcFormat = NULL;
LPWAVEFORMATEX pwfxDestFormat = NULL;
BOOL bNULLFORMAT = FALSE;
ZeroMemory(&mmioinfo, sizeof(mmioinfo));
if(SUCCEEDED(hr)){
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pchBuffer = (HPSTR)pbWaveData;
mmioinfo.cchBuffer = cbWaveData;
hmm = mmioOpen(NULL, &mmioinfo, MMIO_READ);
if(!hmm)
{
DPF1(1, "Unable to open file via MMIO. Error %lu", mmioinfo.wErrorRet);
hr = E_FAIL;
}
}
// Decend into the RIFF chunk
if(SUCCEEDED(hr))
{
ckiRiff.ckid = FOURCC_RIFF;
mmr = mmioDescend(hmm, &ckiRiff, NULL, MMIO_FINDCHUNK);
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "Unable to descend into RIFF chunk. Error %lu", mmr);
hr = E_FAIL;
}
}
// Verify that this is a wave file
if(SUCCEEDED(hr) && FOURCC_WAVE != ckiRiff.fccType)
{
DPF1(1, "File is not type WAVE %d",GetLastError());
hr = DSERR_BADFORMAT;
}
// Decend into the format chunk
if(SUCCEEDED(hr))
{
cki.ckid = FOURCC_FORMAT;
mmr = mmioDescend(hmm, &cki, &ckiRiff, MMIO_FINDCHUNK);
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "Unable to descend into format chunk. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
if(SUCCEEDED(hr))
{
pwfxSrcFormat = (LPWAVEFORMATEX)(pbWaveData + cki.dwDataOffset);
}
}
// Ascend out of the format chunk
if(SUCCEEDED(hr))
{
mmr = mmioAscend(hmm, &cki, 0);
if(MMSYSERR_NOERROR != mmr)
{
DPF(1, "Unable to ascend out of format chunk. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
}
// Descend into the data chunk
if(SUCCEEDED(hr))
{
cki.ckid = FOURCC_DATA;
mmr = mmioDescend(hmm, &cki, &ckiRiff, MMIO_FINDCHUNK);
if(MMSYSERR_NOERROR != mmr)
{
RPF(DPFLVL_ERROR, "Unable to descend into data chunk. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
}
// Prepare PCM conversion
if(SUCCEEDED(hr))
{
if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
{
// Populate the buffer description
dwBufferBytes = cki.cksize;
pwfxDestFormat = pwfxSrcFormat;
}
else
{
// Open an ACM conversion stream
mmr = acmStreamOpen(&has, NULL, (LPWAVEFORMATEX)pwfxSrcFormat, pwfxDestFormat, NULL, 0, 0, 0);
if(MMSYSERR_NOERROR != mmr)
{
RPF(DPFLVL_ERROR, "Unable to open an ACM stream. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
// Get the size of the PCM data
if(SUCCEEDED(hr))
{
mmr = acmStreamSize(has, cki.cksize, &dwBufferBytes, ACM_STREAMSIZEF_SOURCE);
if(MMSYSERR_NOERROR != mmr)
{
RPF(DPFLVL_ERROR, "Unable to determine converted data size. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
}
// Create the destination format
if(SUCCEEDED(hr))
{
pwfxDestFormat = (WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));
if (pwfxDestFormat==NULL) hr=E_OUTOFMEMORY;
}
if(SUCCEEDED(hr))
{
FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
}
}
}
LPDIRECTSOUNDBUFFER lpDirectSoundBuffer=NULL;
if(SUCCEEDED(hr))
{
//hr = InitializeEmpty(pDsbDesc->dwFlags, dwBufferBytes, pwfxDestFormat, NULL);
pDsbDesc->dwBufferBytes=dwBufferBytes;
if (pDsbDesc->lpwfxFormat){
memcpy(pDsbDesc->lpwfxFormat,pwfxDestFormat,sizeof(WAVEFORMATEX));
}
else {
pDsbDesc->lpwfxFormat=pwfxDestFormat;
}
hr=lpDirectSound->CreateSoundBuffer(pDsbDesc,lplpDirectSoundBuffer,NULL);
if (*lplpDirectSoundBuffer==NULL) hr= E_FAIL;
lpDirectSoundBuffer=*lplpDirectSoundBuffer;
}
// Lock the buffer in order to write the PCM data to it
if(SUCCEEDED(hr))
{
hr = lpDirectSoundBuffer->Lock(0, dwBufferBytes, &pvWrite, &cbWrite, NULL, NULL,0);
}
// Convert to PCM
if(SUCCEEDED(hr))
{
if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
{
CopyMemory(pvWrite, pbWaveData + cki.dwDataOffset, cbWrite);
}
else
{
// Prepare the conversion header
ZeroMemory(&ash, sizeof(ash));
ash.cbStruct = sizeof(ash);
ash.pbSrc = pbWaveData + cki.dwDataOffset;
ash.cbSrcLength = cki.cksize;
ash.pbDst = (LPBYTE)pvWrite;
ash.cbDstLength = cbWrite;
mmr = acmStreamPrepareHeader(has, &ash, 0);
if(MMSYSERR_NOERROR != mmr)
{
RPF(DPFLVL_ERROR, "Unable to prepare ACM stream header. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
fPrep = SUCCEEDED(hr);
// Convert the buffer
if(SUCCEEDED(hr))
{
mmr = acmStreamConvert(has, &ash, 0);
if(MMSYSERR_NOERROR != mmr)
{
RPF(DPFLVL_ERROR, "Unable to convert wave data. Error %lu", mmr);
hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
}
}
}
}
// Unlock the buffer
if(SUCCEEDED(hr))
{
hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
}
// Clean up
if(fPrep)
{
acmStreamUnprepareHeader(has, &ash, 0);
}
if(has)
{
acmStreamClose(has, 0);
}
if(hmm)
{
mmioClose(hmm, 0);
}
if(pwfxDestFormat != pwfxSrcFormat)
{
free(pwfxDestFormat);
}
return hr;
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT InternalCreateSoundBuffer(LPDSBUFFERDESC pDsbDesc, byte *pbWaveData, DWORD cbWaveData,LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
{
HRESULT hr = DS_OK;
HACMSTREAM has = NULL;
BOOL fPrep = FALSE;
DWORD dwBufferBytes = 0;
LPVOID pvWrite = NULL;
DWORD cbWrite = 0;
LPWAVEFORMATEX pwfxFormat = NULL;
LPWAVEFORMATEX pwfxSrcFormat = NULL;
LPWAVEFORMATEX pwfxDestFormat = NULL;
MMRESULT mmr = 0;
DWORD dwDataLength = 0;
DWORD dwOffset = 0;
char *pChunk = NULL;
LPDIRECTSOUNDBUFFER lpDirectSoundBuffer = NULL;
ACMSTREAMHEADER ash;
BOOL bNULLFORMAT =FALSE;
BOOL bDirty =FALSE;
struct tag_FileHeader
{
DWORD dwRiff;
DWORD dwFileSize;
DWORD dwWave;
DWORD dwFormat;
DWORD dwFormatLength;
} FileHeader;
ZeroMemory(&FileHeader,sizeof(struct tag_FileHeader));
// If our file is big enough to have a header copy it over
// other wise error out
if (cbWaveData>sizeof(struct tag_FileHeader))
{
memcpy(&FileHeader,pbWaveData,sizeof(struct tag_FileHeader));
}
else
{
hr= E_INVALIDARG;
}
// File must be a riff file ( 52 R, 49 I, 46 F, 46 F)
if (FileHeader.dwRiff != 0x46464952)
{
DPF(1, "DXVB: not a RIFF file\n");
return E_INVALIDARG;
}
// must be a WAVE format ( 57 W, 41 A, 56 V, 45 E )
if (FileHeader.dwWave != 0x45564157)
{
DPF(1, "DXVB: not a WAVE file\n");
return E_INVALIDARG;
}
// check for odd stuff
// note 18bytes is a typical WAVEFORMATEX
if (FileHeader.dwFormatLength <= 14) return E_INVALIDARG;
if (FileHeader.dwFormatLength > 1000) return E_INVALIDARG;
//allocate the waveformat
pwfxFormat=(WAVEFORMATEX*)alloca(FileHeader.dwFormatLength);
if (!pwfxFormat) return E_OUTOFMEMORY;
//copy it to our own data structure
pChunk=(char*)(pbWaveData+sizeof (struct tag_FileHeader));
memcpy(pwfxFormat,pChunk,FileHeader.dwFormatLength);
// Now look for the next chunk after the WaveFormat
pChunk=(char*)(pChunk+FileHeader.dwFormatLength);
// Look for option FACT chunk and skip it
// (66 F, 61 A, 63 C, 74 T)
// this chunk is required for compressed wave files
// but is optional for PCM
//
if ( ((DWORD*)pChunk)[0]==0x74636166)
{
dwOffset=((DWORD*)pChunk)[1];
dwBufferBytes=((DWORD*)pChunk)[2]; //number of bytes of PCM data
pChunk =(char*)(pChunk+ dwOffset+8);
}
//Look for required data chunk
// (64 D, 61 A, 74 T, 61 A)
if (((DWORD*)pChunk)[0]!=0x61746164)
{
DPF(1, "DXVB: no DATA chunk in wave file\n");
return E_INVALIDARG;
}
dwDataLength=((DWORD*)pChunk)[1];
pChunk=(char*)(pChunk+8);
//IF we assume PCM
//pcm files are not required to have their fact chunk
//so be ware they may missreport the data length
dwBufferBytes=dwDataLength;
pwfxDestFormat=pwfxSrcFormat=pwfxFormat;
// if we are not PCM then we need to do some things first
if (pwfxFormat->wFormatTag!=WAVE_FORMAT_PCM)
{
// source format is from the file
pwfxSrcFormat=pwfxFormat; //from file
pwfxDestFormat=pDsbDesc->lpwfxFormat ; //from user
//pick the format of the file passed in
FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
// Open an ACM conversion stream
mmr = acmStreamOpen(&has, NULL, (LPWAVEFORMATEX)pwfxSrcFormat, pwfxDestFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME );
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "Unable to open an ACM stream. Error %lu\n", mmr);
return E_FAIL;
}
// Get the size of the PCM data
mmr = acmStreamSize(has, dwDataLength, &dwBufferBytes, ACM_STREAMSIZEF_SOURCE);
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "Unable to determine converted data size. Error %lu\n", mmr);
return E_FAIL; //MMRESULTtoHRESULT(mmr);
}
// Allocate a DestFormat struct
//pwfxDestFormat = (WAVEFORMATEX*)alloca(sizeof(WAVEFORMATEX));
//if (!pwfxDestFormat) return E_OUTOFMEMORY;
// Fill the format with information from the source but
// FillWfx sets the format to PCM
//FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
}
// fill the buffer desc the user passed in with the buffer bytes
// this is the number of PCM bytes
pDsbDesc->dwBufferBytes=dwBufferBytes;
// if they provide us a pointer to a waveformatex
// copy over the format to the input desc and use it
// otherwise have it point to our data format temprarily
if (pDsbDesc->lpwfxFormat){
memcpy(pDsbDesc->lpwfxFormat,pwfxDestFormat,sizeof(WAVEFORMATEX));
}
else {
pDsbDesc->lpwfxFormat=pwfxDestFormat;
//make sure we null out the format before passing it back to the user
//NOTE: consider the problems in a multithreaded enviroment
//where the users data structures are being accesed by multiple
//threads... on the other hand if thats going on..
//then the user would need to syncronize things on his or her own
//for everything else including calling into apis that fill structures..
bNULLFORMAT=TRUE;
}
LPDIRECTSOUNDBUFFER dsbTemp = NULL;
// Create the buffer
if (FAILED(hr=lpDirectSound->CreateSoundBuffer(pDsbDesc,&dsbTemp,NULL) ) )
return hr;
hr = dsbTemp->QueryInterface(IID_IDirectSoundBuffer8, (void**) lplpDirectSoundBuffer);
dsbTemp->Release();
if (FAILED(hr)) return hr;
if (*lplpDirectSoundBuffer==NULL) return E_FAIL; //todo ASSERT this instead..
// for more convenient referencing...
lpDirectSoundBuffer=*lplpDirectSoundBuffer;
// Lock the buffer in order to write the PCM data to it
// cbWrite will contain the number of locked bytes
hr = lpDirectSoundBuffer->Lock(0, dwBufferBytes, &pvWrite, &cbWrite, NULL, NULL,0);
if FAILED(hr) return hr;
// If the sorce format was pcm then copy from the file to the buffer
if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
{
CopyMemory(pvWrite, pChunk, cbWrite);
// Unlock the buffer
hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
if (FAILED(hr))
{
DPF(1, "DXVB: lpDirectSoundBuffer->Unlock failed.. \n");
return hr;
}
}
// if the source format is compressed then convert first then copy
else
{
// Prepare the conversion header
ZeroMemory(&ash, sizeof(ash));
ash.cbStruct = sizeof(ash);
ash.pbSrc = (unsigned char*)pChunk; //start of compressed data
ash.cbSrcLength = dwDataLength; //number of bytes of compressed data
ash.pbDst = (LPBYTE)pvWrite; //where to put the decompressed data
ash.cbDstLength = cbWrite; //how big is that buffer
mmr = acmStreamPrepareHeader(has, &ash, 0);
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "DXVB: Unable to prepare ACM stream header. Error %lu \n", mmr);
return E_FAIL;
}
mmr = acmStreamConvert(has, &ash, 0);
if(MMSYSERR_NOERROR != mmr)
{
DPF1(1, "DXVB: Unable to convert wave data. Error %lu \n", mmr);
return hr;
}
// Unlock the buffer
hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
if (FAILED(hr))
{
DPF(1, "DXVB: lpDirectSoundBuffer->Unlock failed.. \n");
return hr;
}
acmStreamUnprepareHeader(has, &ash, 0);
acmStreamClose(has, 0);
}
if (bNULLFORMAT){
pDsbDesc->lpwfxFormat=NULL;
}
return hr;
}
HRESULT InternalCreateSoundBufferFromFile(LPDIRECTSOUND8 lpDirectSound,LPDSBUFFERDESC pDesc,WCHAR *file,LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
{
HRESULT hr=S_OK;
HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
DWORD cbWaveData;
LPBYTE pbWaveData = NULL;
#pragma message("CreateFileW should be used for localization why wont it work")
//hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
USES_CONVERSION;
LPSTR pStrA=W2T(file);
hFile = CreateFileA(pStrA, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
hFile = NULL;
}
if(!hFile)
{
RPF(DPFLVL_ERROR, "Unable to open file. Error %lu", GetLastError());
hr=STG_E_FILENOTFOUND;
return hr;
}
if(hFile)
{
cbWaveData = GetFileSize(hFile, NULL);
if(-1 == cbWaveData)
{
RPF(DPFLVL_ERROR, "Unable to get file size. Error %lu", GetLastError());
hr = E_FAIL; //DSERR_FILEREADFAULT;
}
}
if(SUCCEEDED(hr))
{
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbWaveData, NULL);
if(INVALID_HANDLE_VALUE == hFileMapping)
{
hFileMapping = NULL;
}
if(!hFileMapping)
{
RPF(DPFLVL_ERROR, "Unable to create file mapping. Error %lu", GetLastError());
hr = E_FAIL; //DSERR_FILEREADFAULT;
}
}
if(SUCCEEDED(hr))
{
pbWaveData = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, cbWaveData);
if(!pbWaveData)
{
RPF(DPFLVL_ERROR, "Unable to map view of file. Error %lu", GetLastError());
hr = E_FAIL; //DSERR_FILEREADFAULT;
}
}
if(SUCCEEDED(hr)) {
hr=InternalCreateSoundBuffer(pDesc, pbWaveData, cbWaveData,lpDirectSound, lplpDirectSoundBuffer);
}
if(pbWaveData)
{
UnmapViewOfFile(pbWaveData);
}
if(hFileMapping)
{
CloseHandle(hFileMapping);
}
if(hFile)
{
CloseHandle(hFile);
}
return hr;
}
HRESULT InternalCreateSoundBufferFromResource(LPDIRECTSOUND8 lpDirectSound,LPDSBUFFERDESC pDesc,HANDLE resHandle,WCHAR *resName,LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
{
const LPCSTR apszResourceTypeA[] = { "WAVE", "WAV" };
const LPCWSTR apszResourceTypeW[] = { L"WAVE", L"WAV" };
UINT cResourceType = 2;
HRSRC hRsrc = NULL;
DWORD cbWaveData;
LPBYTE pbWaveData = NULL;
HRESULT hr=S_OK;
LPCDSBUFFERDESC pDsbDesc=pDesc;
while(!hRsrc && cResourceType--)
{
hRsrc = FindResourceW((HINSTANCE)resHandle, resName, apszResourceTypeW[cResourceType]);
}
if(!hRsrc)
{
RPF(DPFLVL_ERROR,"Unable to find resource. Error %lu", GetLastError());
hr = STG_E_FILENOTFOUND;
}
if(SUCCEEDED(hr))
{
cbWaveData = SizeofResource((HINSTANCE)resHandle, hRsrc);
if(!cbWaveData)
{
RPF(DPFLVL_ERROR, "Unable to get resource size. Error %lu", GetLastError());
hr = E_FAIL;
}
}
if(SUCCEEDED(hr))
{
pbWaveData = (LPBYTE)LoadResource((HINSTANCE)resHandle, hRsrc);
if(!pbWaveData)
{
RPF(DPFLVL_ERROR, "Unable to load resource. Error %lu", GetLastError());
hr = E_FAIL;
}
}
if(SUCCEEDED(hr)) {
hr=InternalCreateSoundBuffer(pDesc, pbWaveData, cbWaveData,lpDirectSound, lplpDirectSoundBuffer);
}
//loadResource
return hr;
}
HRESULT InternalSaveToFile(IDirectSoundBuffer *pBuff,BSTR file)
{
WAVEFORMATEX waveFormat;
DWORD dwWritten=0;
DWORD dwBytes=0;
LPBYTE lpByte=NULL;
HRESULT hr;
HANDLE hFile=NULL;
if (!pBuff) return E_FAIL;
if (!file) return E_INVALIDARG;
pBuff->GetFormat(&waveFormat,sizeof(WAVEFORMATEX),NULL);
USES_CONVERSION;
LPSTR pStrA=W2T(file);
hFile = CreateFile
(
pStrA,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE != hFile)
{
struct tag_FileHeader
{
DWORD dwRiff;
DWORD dwFileSize;
DWORD dwWave;
DWORD dwFormat;
DWORD dwFormatLength;
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
DWORD dwData;
DWORD dwDataLength;
} FileHeader;
hr=pBuff->Lock(0,0,(void**)&lpByte,&dwBytes,NULL,NULL,DSBLOCK_ENTIREBUFFER);
if FAILED(hr) {
CloseHandle(hFile);
return hr;
}
FileHeader.dwRiff = 0x46464952; // RIFF
FileHeader.dwWave = 0x45564157; // WAVE
FileHeader.dwFormat = 0x20746D66; // fmt_chnk
FileHeader.dwFormatLength = 16;
FileHeader.wFormatTag = WAVE_FORMAT_PCM;
FileHeader.nChannels = waveFormat.nChannels ;
FileHeader.nSamplesPerSec = waveFormat.nSamplesPerSec ;
FileHeader.wBitsPerSample = waveFormat.wBitsPerSample ;
FileHeader.nBlockAlign = FileHeader.wBitsPerSample / 8 * FileHeader.nChannels;
FileHeader.nAvgBytesPerSec = FileHeader.nSamplesPerSec * FileHeader.nBlockAlign;
FileHeader.dwData = 0x61746164; // data_chnk
FileHeader.dwDataLength = dwBytes;
FileHeader.dwFileSize = dwBytes + sizeof(FileHeader);
WriteFile(hFile, &FileHeader, sizeof(FileHeader), &dwWritten, NULL);
WriteFile(hFile, lpByte, dwBytes, &dwWritten, NULL);
hr=pBuff->Unlock(lpByte,0,NULL,0);
CloseHandle(hFile);
}
else{
return E_FAIL;
}
return S_OK;
}