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