|
|
#include "precomp.h"
#include "WaveDev.h"
#include "WaveIo.h"
// utility function for both waveIndev and waveOutdev
// builds a PCM WaveFormatEx structure for a given sampling rate and size
static MMRESULT MakeWaveFormat(WAVEFORMATEX *pWF, int hertz, int bps) { WAVEFORMATEX waveFormat;
if ((bps != 8) && (bps != 16)) { return WAVERR_BADFORMAT; }
waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = 1; waveFormat.nSamplesPerSec = hertz; waveFormat.nAvgBytesPerSec = hertz * bps/8; waveFormat.nBlockAlign = bps/8; waveFormat.wBitsPerSample = (WORD)bps; waveFormat.cbSize = 0;
*pWF = waveFormat;
return MMSYSERR_NOERROR; }
waveInDev::waveInDev(UINT uDevId, HANDLE hEvent) : m_devID(uDevId), m_hwi(NULL), m_bOpen(FALSE), m_fAllowMapper(TRUE), m_hEvent(hEvent) { ZeroMemory(&m_waveFormat, sizeof(m_waveFormat)); return; }
waveInDev::~waveInDev() { Close(); }
MMRESULT waveInDev::Open(int hertz, int bps) { MMRESULT mmr; WAVEFORMATEX waveFormat; DWORD dwCallbackType = (m_hEvent ? CALLBACK_EVENT : CALLBACK_NULL );
if (m_bOpen == TRUE) return MMSYSERR_NOERROR;
mmr = MakeWaveFormat(&waveFormat, hertz, bps); if (mmr != MMSYSERR_NOERROR) { return mmr; }
mmr = waveInOpen(&m_hwi, m_devID, &waveFormat, (DWORD_PTR)m_hEvent, 0, dwCallbackType);
// begin hack, try to open wave_mapper
// this may end up opening a different device!
if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper)) { mmr = waveInOpen(&m_hwi, WAVE_MAPPER, &waveFormat, (DWORD_PTR)m_hEvent, 0, dwCallbackType); }
if (mmr == MMSYSERR_NOERROR) m_bOpen = TRUE;
waveInStart(m_hwi);
m_waveFormat = waveFormat;
return mmr; }
MMRESULT waveInDev::PrepareHeader(WAVEHDR *pWaveHdr) { MMRESULT mmr;
if (m_bOpen == FALSE) return MMSYSERR_INVALHANDLE;
mmr = waveInPrepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveInDev::UnPrepareHeader(WAVEHDR *pWaveHdr) { MMRESULT mmr;
if (m_bOpen == FALSE) return MMSYSERR_INVALHANDLE;
mmr = waveInUnprepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveInDev::Reset() { MMRESULT mmr; if (m_bOpen == FALSE) return MMSYSERR_NOERROR;
mmr = waveInReset(m_hwi);
return mmr; }
MMRESULT waveInDev::Close() { MMRESULT mmr; if (m_bOpen == FALSE) return MMSYSERR_NOERROR;
waveInReset(m_hwi); mmr = waveInClose(m_hwi);
if (mmr == MMSYSERR_NOERROR) m_bOpen = FALSE;
return mmr; }
MMRESULT waveInDev::Record(WAVEHDR *pHdr) { MMRESULT mmr;
if (m_bOpen == FALSE) { return MMSYSERR_INVALHANDLE; }
mmr = waveInAddBuffer(m_hwi, pHdr, sizeof(WAVEHDR));
return mmr;
}
void waveInDev::AllowMapper(BOOL fAllowMapper) { m_fAllowMapper = fAllowMapper; }
waveOutDev::waveOutDev(UINT uDevID, HWND hwnd) : m_devID(uDevID), m_hwo(NULL), m_bOpen(FALSE), m_hWnd(hwnd), m_pfBuffer(NULL), m_nBufferSize(0), m_fFileBufferValid(FALSE), m_fAllowMapper(TRUE) { ZeroMemory(&m_waveFormat, sizeof(m_waveFormat)); ZeroMemory(m_szPlayFile, sizeof(m_szPlayFile)); ZeroMemory(&m_waveHdr, sizeof(m_waveHdr));
if (hwnd == NULL) { m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hEvent == NULL) { ERROR_OUT(("waveOutDev::waveOutDev - Unable to create event")); } } else m_hEvent = NULL;
}
waveOutDev::~waveOutDev() { Close(); if (m_hEvent) CloseHandle(m_hEvent);
if (m_pfBuffer) LocalFree(m_pfBuffer); }
MMRESULT waveOutDev::Open(int hertz, int bps) { MMRESULT mmr; WAVEFORMATEX waveFormat;
mmr = MakeWaveFormat(&waveFormat, hertz, bps); if (mmr != MMSYSERR_NOERROR) { return mmr; }
return Open(&waveFormat);
}
MMRESULT waveOutDev::Open(WAVEFORMATEX *pWaveFormat) { MMRESULT mmr;
m_waveFormat = *pWaveFormat;
if (m_bOpen == TRUE) return MMSYSERR_NOERROR;
if (m_hWnd == NULL) { mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hEvent, 0, CALLBACK_EVENT); } else { mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hWnd, 0, CALLBACK_WINDOW); }
// begin hack, try to open wave_mapper
// this may end up opening a different device!
if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper)) { if (m_hWnd == NULL) { mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat, (DWORD_PTR)m_hEvent, 0, CALLBACK_EVENT); } else { mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat, (DWORD_PTR)m_hWnd, 0, CALLBACK_WINDOW); } }
if (mmr == MMSYSERR_NOERROR) m_bOpen = TRUE;
return mmr;
}
MMRESULT waveOutDev::Close() { MMRESULT mmr; if (m_bOpen == FALSE) return MMSYSERR_NOERROR;
waveOutReset(m_hwo);
if (m_waveHdr.dwFlags & WHDR_PREPARED) { waveOutUnprepareHeader(m_hwo, &m_waveHdr, sizeof(m_waveHdr)); m_waveHdr.dwFlags = 0; }
mmr = waveOutClose(m_hwo);
if (mmr == MMSYSERR_NOERROR) m_bOpen = FALSE; else ERROR_OUT(("ATW:Close failed"));
return mmr; }
MMRESULT waveOutDev::PrepareHeader(WAVEHDR *pWhdr, SHORT *shBuffer, int numSamples) { MMRESULT mmr;
if (m_bOpen == FALSE) return MMSYSERR_INVALHANDLE;
// if shBuffer is not NULL, we assume the caller wants us to fill in the
// WAVEHDR struct
if (shBuffer) { ZeroMemory(pWhdr, sizeof(WAVEHDR)); pWhdr->lpData = (LPSTR)shBuffer; pWhdr->dwBufferLength = numSamples * m_waveFormat.nBlockAlign; }
mmr = waveOutPrepareHeader(m_hwo, pWhdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveOutDev::UnprepareHeader(WAVEHDR *pWaveHdr) { MMRESULT mmr;
if (m_bOpen == FALSE) return MMSYSERR_INVALHANDLE;
mmr = waveOutUnprepareHeader(m_hwo, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveOutDev::Play(WAVEHDR *pWaveHdr) { MMRESULT mmr; DWORD dwTimeOut; DWORD dwRet; int numSamples;
if (m_bOpen == FALSE) return MMSYSERR_INVALHANDLE;
if (m_hEvent) ResetEvent(m_hEvent);
mmr = waveOutWrite(m_hwo, pWaveHdr, sizeof(WAVEHDR));
if (mmr != MMSYSERR_NOERROR) return mmr;
if (m_hEvent) { numSamples = pWaveHdr->dwBufferLength / m_waveFormat.nBlockAlign;
dwTimeOut = 5 * ((1000 * numSamples) / m_waveFormat.nSamplesPerSec); dwRet = WaitForSingleObject(m_hEvent, dwTimeOut);
if ((dwRet != WAIT_ABANDONED) && (dwRet != WAIT_OBJECT_0)) { ERROR_OUT(("waveOutDev::Play() - WaitForSingleObject Failed")); return WAVERR_LASTERROR + 1; } }
return MMSYSERR_NOERROR; }
// File io errors or anything unexpected results in -1 being returned
// Otherwise, returns the MMRESULT of the last waveOut call made
MMRESULT waveOutDev::PlayFile(LPCTSTR szFileName) { MMRESULT mmr; WAVEIOCB waveiocb; WIOERR werr; DWORD dwSize; PCHAR pBuffer;
// quick optimization
// if the same file is being played twice in a row
// the just replay the buffer
if ((m_fFileBufferValid) && (0 == lstrcmp(szFileName, m_szPlayFile))) { Close(); mmr = Open(&m_PlayFileWf);
if (mmr == MMSYSERR_NOERROR) { mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer, m_nBufferSize / m_PlayFileWf.nBlockAlign); if (mmr == MMSYSERR_NOERROR) { mmr = Play(&m_waveHdr); } }
m_fFileBufferValid = (mmr == MMSYSERR_NOERROR); return mmr; }
ZeroMemory(&waveiocb, sizeof(waveiocb)); werr = wioFileOpen(&waveiocb, szFileName, 0);
if (werr == WIOERR_NOERROR) { // prepare to read the samples!
// quick hack, if the file to play was the same as the last,
// then use the same buffer
m_fFileBufferValid = FALSE;
if (m_pfBuffer == NULL) { m_pfBuffer = (char *)LocalAlloc(LPTR, waveiocb.dwDataBytes); } else { pBuffer = (char*)LocalReAlloc(m_pfBuffer, waveiocb.dwDataBytes, LMEM_MOVEABLE |LMEM_ZEROINIT); if(NULL != pBuffer) { m_pfBuffer = pBuffer; } else { // Failed to reallocate buffer, make sure to clean up
LocalFree(m_pfBuffer); m_pfBuffer = NULL; } }
if (m_pfBuffer == NULL) { wioFileClose(&waveiocb, 0); return -1; }
// read
mmioSeek(waveiocb.hmmio, waveiocb.dwDataOffset, SEEK_SET); dwSize = mmioRead(waveiocb.hmmio, m_pfBuffer, waveiocb.dwDataBytes);
if (dwSize == 0) return -1;
Close(); mmr = Open(waveiocb.pwfx); if (mmr != MMSYSERR_NOERROR) { wioFileClose(&waveiocb, 0); return mmr; }
// mmr = Play((short *)m_pfBuffer, dwSize / (waveiocb.pwfx)->nBlockAlign);
mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer, dwSize / (waveiocb.pwfx)->nBlockAlign); if (mmr == MMSYSERR_NOERROR) { mmr = Play(&m_waveHdr); }
m_fFileBufferValid = (mmr == MMSYSERR_NOERROR); if (m_fFileBufferValid) { m_PlayFileWf = *(waveiocb.pwfx); lstrcpy(m_szPlayFile, szFileName); m_nBufferSize = dwSize; }
wioFileClose(&waveiocb, 0);
return mmr; }
return -1;
}
void waveOutDev::AllowMapper(BOOL fAllowMapper) { m_fAllowMapper = fAllowMapper; }
|