261 lines
5.9 KiB
C++
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();
|
||
|
}
|
||
|
|