windows-nt/Source/XPSP1/NT/windows/feime/cht/cblocks/waveodev.cpp
2020-09-26 16:20:57 +08:00

261 lines
5.9 KiB
C++

/*************************************************
* waveodev.cpp *
* *
* Copyright (C) 1995-1999 Microsoft Inc. *
* *
*************************************************/
// waveodev.cpp : implementation file
//
#include "stdafx.h"
#include "wave.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
// global items
CWaveOutDevice theDefaultWaveOutDevice;
/////////////////////////////////////////////////////////////////////////////
// CWaveOutDevice
CWaveOutDevice::CWaveOutDevice()
{
m_hOutDev = NULL;
m_iBlockCount = 0;
}
CWaveOutDevice::~CWaveOutDevice()
{
}
BEGIN_MESSAGE_MAP(CWaveOutDevice, CWnd)
//{{AFX_MSG_MAP(CWaveOutDevice)
ON_MESSAGE(MM_WOM_DONE, OnWomDone)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CWaveOutDevice::Create()
{
if (!CreateEx(0,
AfxRegisterWndClass(0),
"Wave Wnd",
WS_POPUP,
0,
0,
0,
0,
NULL,
NULL)) {
TRACE("Failed to create wave notification window");
return FALSE;
}
return TRUE;
}
#ifndef _DEBUG
#define MMERR(n) 0
#else
void MMERR(MMRESULT mmr)
{
switch (mmr) {
case WAVERR_BADFORMAT:
TRACE("No wave device supports format");
break;
case MMSYSERR_NOMEM:
TRACE("Out of memory");
break;
case MMSYSERR_ALLOCATED:
TRACE("Resource is already allocated");
break;
case MMSYSERR_BADDEVICEID:
TRACE("Bad device id");
break;
case MMSYSERR_INVALHANDLE:
TRACE("Invalid device handle");
break;
case MMSYSERR_HANDLEBUSY:
TRACE("Device in use by another thread");
break;
case WAVERR_UNPREPARED:
TRACE("Header not prepared");
break;
default:
TRACE("Unknown error");
break;
}
}
#endif // _DEBUG
/////////////////////////////////////////////////////////////////////////////
// CWaveOutDevice message handlers
LRESULT CWaveOutDevice::OnWomDone(WPARAM w, LPARAM l)
{
ASSERT(l);
WAVEHDR* phdr = (WAVEHDR*) l;
CWave* pWave = (CWave*)(phdr->dwUser);
ASSERT(pWave->IsKindOf(RUNTIME_CLASS(CWave)));
CWaveOutDevice* pOutDev = pWave->GetOutDevice();
ASSERT(pOutDev);
pOutDev->WaveOutDone(pWave, phdr);
UNREFERENCED_PARAMETER(w);
return 0;
}
BOOL CWaveOutDevice::IsOpen()
{
return m_hOutDev ? TRUE : FALSE;
}
BOOL CWaveOutDevice::Open(WAVEFORMATEX *pFormat)
{
MMRESULT mmr;
// Make sure we have a callback window.
if (!m_hWnd) {
Create(); // Create the window.
ASSERT(m_hWnd);
}
// See whether it's already open for this format.
if (IsOpen()) {
// See whether it can handle this format.
if (CanDoFormat(pFormat)) {
return TRUE;
} else {
TRACE("Open for different format");
return FALSE;
}
}
// See whether we can open for this format.
mmr = waveOutOpen(&m_hOutDev,
WAVE_MAPPER,
pFormat,
(DWORD_PTR)(GetSafeHwnd()),
0,
CALLBACK_WINDOW);
if (mmr != 0) {
MMERR(mmr);
return FALSE;
}
return TRUE;
}
BOOL CWaveOutDevice::CanDoFormat(WAVEFORMATEX* pFormat)
{
MMRESULT mmr;
if (!IsOpen()) {
TRACE("Not open");
return FALSE;
}
HWAVEOUT hDev = NULL;
mmr = waveOutOpen(&hDev,
WAVE_MAPPER,
pFormat,
NULL,
0,
WAVE_FORMAT_QUERY);
if (mmr != 0) {
MMERR(mmr);
return FALSE;
}
return TRUE;
}
BOOL CWaveOutDevice::Close()
{
if (m_hOutDev) {
// Close the device.
waveOutReset(m_hOutDev);
MMRESULT mmr = waveOutClose(m_hOutDev);
if (mmr != 0) {
MMERR(mmr);
}
m_hOutDev = NULL;
}
// Destroy the window.
DestroyWindow();
ASSERT(m_hWnd == NULL);
return TRUE;
}
BOOL CWaveOutDevice::Play(CWave* pWave)
{
if (!Open(pWave->GetFormat())) {
return FALSE;
}
// Allocate a header.
WAVEHDR* phdr = (WAVEHDR*)malloc(sizeof(WAVEHDR));
ASSERT(phdr);
// Fill out the wave header.
memset(phdr, 0, sizeof(WAVEHDR));
//#if 1 // BUGFIX for VC++ 2.0
// phdr->lpData = (BYTE*) pWave->GetSamples();
//#else
phdr->lpData = (char*) pWave->GetSamples();
//#endif
phdr->dwBufferLength = pWave->GetSize();
phdr->dwUser = (DWORD_PTR)(void*)pWave; // So we can find the object
// Prepare the header
MMRESULT mmr = waveOutPrepareHeader(m_hOutDev,
phdr,
sizeof(WAVEHDR));
if (mmr) {
MMERR(mmr);
return FALSE;
}
// Mark the wave as busy.
pWave->SetBusy(TRUE);
// Start it playing.
mmr = waveOutWrite(m_hOutDev,
phdr,
sizeof(WAVEHDR));
if (mmr) {
MMERR(mmr);
return FALSE;
}
// Add one to the block count.
m_iBlockCount++;
return TRUE;
}
void CWaveOutDevice::WaveOutDone(CWave *pWave, WAVEHDR *pHdr)
{
// Unprepare the header.
MMRESULT mmr = waveOutUnprepareHeader(m_hOutDev,
pHdr,
sizeof(WAVEHDR));
if (mmr) {
MMERR(mmr);
}
// Free the header.
free(pHdr);
// Decrement the block count.
ASSERT(m_iBlockCount > 0);
m_iBlockCount--;
if (m_iBlockCount == 0) {
// Close the device.
Close();
}
// Notify the object that it is done.
pWave->SetBusy(FALSE);
pWave->OnWaveOutDone();
}