windows-nt/Source/XPSP1/NT/net/tapi/skywalker/tapi3/waves.cpp
2020-09-26 16:20:57 +08:00

800 lines
18 KiB
C++

//
// Copyright (c) 1995-2000 Microsoft Corporation
//
// Waves.cpp
//
#include "stdafx.h"
BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader, BYTE ** ppbWaveData, DWORD *pdwWaveSize);
static const char c_szWAV[] = "WAVE";
///////////////////////////////////////////////////////////////////////////////
//
// DSGetWaveResource
//
///////////////////////////////////////////////////////////////////////////////
BOOL DSGetWaveResource(HMODULE hModule, LPCTSTR lpName,
WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData, DWORD *pcbWaveSize)
{
HRSRC hResInfo;
HGLOBAL hResData;
void *pvRes;
if (((hResInfo = FindResource(hModule, lpName, c_szWAV)) != NULL) &&
((hResData = LoadResource(hModule, hResInfo)) != NULL) &&
((pvRes = LockResource(hResData)) != NULL) &&
DSParseWaveResource(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize))
{
return TRUE;
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader, BYTE **
ppbWaveData,DWORD *pcbWaveSize)
{
DWORD *pdw;
DWORD *pdwEnd;
DWORD dwRiff;
DWORD dwType;
DWORD dwLength;
if (ppWaveHeader)
{
*ppWaveHeader = NULL;
}
if (ppbWaveData)
{
*ppbWaveData = NULL;
}
if (pcbWaveSize)
{
*pcbWaveSize = 0;
}
pdw = (DWORD *)pvRes;
dwRiff = *pdw++;
dwLength = *pdw++;
dwType = *pdw++;
if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
goto exit; // not even RIFF
if (dwType != mmioFOURCC('W', 'A', 'V', 'E'))
goto exit; // not a WAV
pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
while (pdw < pdwEnd)
{
dwType = *pdw++;
dwLength = *pdw++;
switch (dwType)
{
case mmioFOURCC('f', 'm', 't', ' '):
if (ppWaveHeader && !*ppWaveHeader)
{
if (dwLength < sizeof(WAVEFORMAT))
{
goto exit; // not a WAV
}
*ppWaveHeader = (WAVEFORMATEX *)pdw;
if ((!ppbWaveData || *ppbWaveData) &&
(!pcbWaveSize || *pcbWaveSize))
{
return TRUE;
}
}
break;
case mmioFOURCC('d', 'a', 't', 'a'):
if ((ppbWaveData && !*ppbWaveData) ||
(pcbWaveSize && !*pcbWaveSize))
{
if (ppbWaveData)
{
*ppbWaveData = (LPBYTE)pdw;
}
if (pcbWaveSize)
{
*pcbWaveSize = dwLength;
}
if (!ppWaveHeader || *ppWaveHeader)
{
return TRUE;
}
}
break;
}
pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
}
exit:
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
CWavePlayer::CWavePlayer()
{
m_hWaveOutTone = NULL;
m_hWaveOutRing = NULL;
m_hMixer = NULL;
m_fInitialized = FALSE;
memset(m_fPlaying, 0, NUM_TONES * sizeof(BOOL));
m_lCurrentTone = -1;
}
//////////////////////////////////////////////////////////////////////////////
//
CWavePlayer::~CWavePlayer()
{
//
// We should have closed the wave device by now.
//
if ( m_fInitialized == TRUE )
{
_ASSERTE( m_hWaveOutTone == NULL );
_ASSERTE( m_hWaveOutRing == NULL );
_ASSERTE( m_hMixer == NULL );
}
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::Initialize(void)
{
int i;
//
// It's wasteful to initialize twice, but it won't break anything.
//
_ASSERTE( m_fInitialized == FALSE );
//
// Read all wave data resources.
// We ignore the size and the wave header -- since these are our own
// resources, we do not expect any surprises.
//
BOOL fResult;
//
// For each wave
//
for ( i = 0; i < NUM_WAVES; i ++ )
{
//
// Read the wave resource for this tone.
//
fResult = DSGetWaveResource(
_Module.GetModuleInstance(), // HMODULE hModule,
(LPCTSTR)IDR_WAV_DTMF0 + i, // LPCTSTR lpName,
NULL, // WAVEFORMATEX **ppWaveHeader,
&m_lpWaveform[i], // BYTE **ppbWaveData,
&m_dwWaveformSize[i] // DWORD *pcbWaveSize
);
if ( fResult == FALSE )
{
return E_FAIL;
}
}
//
// We can now go ahead with the other methods.
//
m_fInitialized = TRUE;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::StartTone(
long lTone
)
{
MMRESULT mmresult;
HRESULT hr;
if ( lTone < 0 )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( lTone > NUM_TONES )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOutTone == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
m_fPlaying[lTone] = TRUE;
hr = ChangeTone();
if ( FAILED( hr ) )
{
m_fPlaying[lTone] = FALSE;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::StopTone(
long lTone
)
{
if ( lTone < 0 )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( lTone > NUM_TONES )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOutTone == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
m_fPlaying[lTone] = FALSE;
return ChangeTone();
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::ChangeTone()
{
MMRESULT mmresult;
for (int i=0; i < NUM_TONES; i++)
{
if (m_fPlaying[i])
{
//
// If already playing it, just return
//
if (m_lCurrentTone == i)
{
return S_OK;
}
//
// Reset the wave device to flush out any pending buffers.
//
mmresult = waveOutReset( m_hWaveOutTone );
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite.
//
ZeroMemory( & m_WaveHeaderTone, sizeof( m_WaveHeaderTone ) );
m_WaveHeaderTone.lpData = (LPSTR)m_lpWaveform[i];
m_WaveHeaderTone.dwBufferLength = m_dwWaveformSize[i];
m_WaveHeaderTone.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
m_WaveHeaderTone.dwLoops = (DWORD) -1;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOutTone,
& m_WaveHeaderTone,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
m_lCurrentTone = -1;
return E_FAIL;
}
mmresult = waveOutWrite(m_hWaveOutTone,
& m_WaveHeaderTone,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
m_lCurrentTone = -1;
return E_FAIL;
}
m_lCurrentTone = i;
return S_OK;
}
}
//
// Stop the tone
//
if ( m_lCurrentTone != -1 )
{
mmresult = waveOutReset( m_hWaveOutTone );
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
m_lCurrentTone = -1;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL CWavePlayer::PlayingTone(
long lTone
)
{
if ( lTone < 0 )
{
_ASSERTE( FALSE );
return FALSE;
}
if ( lTone > NUM_TONES )
{
_ASSERTE( FALSE );
return FALSE;
}
return m_fPlaying[lTone];
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::StartRing()
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOutRing == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
//
// Reset the wave device to flush out any pending buffers.
//
mmresult = waveOutReset( m_hWaveOutRing );
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite.
//
ZeroMemory( & m_WaveHeaderRing, sizeof( m_WaveHeaderRing ) );
m_WaveHeaderRing.lpData = (LPSTR)m_lpWaveform[NUM_WAVES-1];
m_WaveHeaderRing.dwBufferLength = m_dwWaveformSize[NUM_WAVES-1];
m_WaveHeaderRing.dwFlags = 0;
m_WaveHeaderRing.dwLoops = (DWORD) 0;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOutRing,
& m_WaveHeaderRing,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
mmresult = waveOutWrite(m_hWaveOutRing,
& m_WaveHeaderRing,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::StopRing( void )
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOutRing == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
mmresult = waveOutReset( m_hWaveOutRing );
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::OpenWaveDeviceForTone(
long lWaveID
)
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
//
// We expect that the wave device will not be opened twice. This is
// dependent on the calling code.
//
_ASSERTE( m_hWaveOutTone == NULL );
//
// Open the wave device. Here we specify a hard-coded audio format.
//
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM; // linear PCM
waveFormat.nChannels = 1; // mono
waveFormat.nSamplesPerSec = 8000; // 8 KHz
waveFormat.wBitsPerSample = 16; // 16-bit samples
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0; // no extra format info
mmresult = waveOutOpen(& m_hWaveOutTone, // returned handle
lWaveID, // which device to use
&waveFormat, // wave format to use
0, // callback function pointer
0, // callback instance data
WAVE_FORMAT_DIRECT // we don't want ACM
);
if ( mmresult != MMSYSERR_NOERROR )
{
m_hWaveOutTone = NULL;
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::OpenWaveDeviceForRing(
long lWaveID
)
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
//
// We expect that the wave device will not be opened twice. This is
// dependent on the calling code.
//
_ASSERTE( m_hWaveOutRing == NULL );
//
// Open the wave device. Here we specify a hard-coded audio format.
//
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM; // linear PCM
waveFormat.nChannels = 1; // mono
waveFormat.nSamplesPerSec = 8000; // 8 KHz
waveFormat.wBitsPerSample = 16; // 16-bit samples
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0; // no extra format info
mmresult = waveOutOpen(& m_hWaveOutRing, // returned handle
lWaveID, // which device to use
&waveFormat, // wave format to use
0, // callback function pointer
0, // callback instance data
WAVE_FORMAT_DIRECT // we don't want ACM
);
if ( mmresult != MMSYSERR_NOERROR )
{
m_hWaveOutRing = NULL;
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
void CWavePlayer::CloseWaveDeviceForTone(void)
{
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
}
if ( m_hWaveOutTone != NULL )
{
waveOutReset( m_hWaveOutTone );
memset(m_fPlaying, 0, NUM_TONES * sizeof(BOOL));
m_lCurrentTone = -1;
waveOutClose( m_hWaveOutTone );
m_hWaveOutTone = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
void CWavePlayer::CloseWaveDeviceForRing(void)
{
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
}
if ( m_hWaveOutRing != NULL )
{
waveOutReset( m_hWaveOutRing );
waveOutClose( m_hWaveOutRing );
m_hWaveOutRing = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::OpenMixerDevice(
long lWaveID
)
{
MMRESULT mmresult;
MIXERLINECONTROLS mxlc;
mmresult = mixerOpen( &m_hMixer, lWaveID, 0, 0, MIXER_OBJECTF_WAVEOUT);
if ( mmresult != MMSYSERR_NOERROR )
{
m_hMixer = NULL;
return E_FAIL;
}
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = 0;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.pamxctrl = &m_mxctrl;
mxlc.cbmxctrl = sizeof(m_mxctrl);
mmresult = mixerGetLineControls( (HMIXEROBJ)m_hMixer, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE );
if ( mmresult != MMSYSERR_NOERROR )
{
//
// Close the mixer
//
mixerClose( m_hMixer );
m_hMixer = NULL;
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
void CWavePlayer::CloseMixerDevice(void)
{
if ( m_hMixer != NULL )
{
mixerClose( m_hMixer );
m_hMixer = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::SetVolume( DWORD dwVolume )
{
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hMixer == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
mxcd_u.dwValue = dwVolume;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = m_mxctrl.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(mxcd_u);
mxcd.paDetails = &mxcd_u;
mmresult = mixerSetControlDetails( (HMIXEROBJ)m_hMixer, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CWavePlayer::GetVolume( DWORD * pdwVolume )
{
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
if ( m_hMixer == NULL )
{
_ASSERTE( FALSE );
return E_UNEXPECTED;
}
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = m_mxctrl.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(mxcd_u);
mxcd.paDetails = &mxcd_u;
mmresult = mixerGetControlDetails( (HMIXEROBJ)m_hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
*pdwVolume = mxcd_u.dwValue;
return S_OK;
}