You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
3.6 KiB
205 lines
3.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include <windows.h> |
|
#include <assert.h> |
|
#include <mmsystem.h> |
|
#include "waveout.h" |
|
#include "ivoicecodec.h" |
|
|
|
|
|
class CWaveOutHdr |
|
{ |
|
public: |
|
WAVEHDR m_Hdr; |
|
CWaveOutHdr *m_pNext; |
|
char m_Data[1]; |
|
}; |
|
|
|
|
|
class CWaveOut : public IWaveOut |
|
{ |
|
// IWaveOut overrides. |
|
public: |
|
CWaveOut(); |
|
virtual ~CWaveOut(); |
|
virtual void Release(); |
|
virtual bool PutSamples(short *pSamples, int nSamples); |
|
virtual void Idle(); |
|
virtual int GetNumBufferedSamples(); |
|
|
|
|
|
public: |
|
bool Init(int sampleRate); |
|
void Term(); |
|
|
|
|
|
private: |
|
void KillOldHeaders(); |
|
|
|
|
|
private: |
|
HWAVEOUT m_hWaveOut; |
|
CWaveOutHdr m_Headers; // Head of a linked list of WAVEHDRs. |
|
int m_nBufferedSamples; |
|
}; |
|
|
|
|
|
CWaveOut::CWaveOut() |
|
{ |
|
m_hWaveOut = NULL; |
|
m_Headers.m_pNext = NULL; |
|
m_nBufferedSamples = 0; |
|
} |
|
|
|
CWaveOut::~CWaveOut() |
|
{ |
|
Term(); |
|
} |
|
|
|
void CWaveOut::Release() |
|
{ |
|
delete this; |
|
} |
|
|
|
bool CWaveOut::PutSamples(short *pInSamples, int nInSamples) |
|
{ |
|
int granularity = 2048; |
|
while( nInSamples ) |
|
{ |
|
int nSamples = (nInSamples > granularity) ? granularity : nInSamples; |
|
short *pSamples = pInSamples; |
|
nInSamples -= nSamples; |
|
pInSamples += nSamples; |
|
|
|
if(!m_hWaveOut) |
|
return false; |
|
|
|
// Kill any old headers.. |
|
KillOldHeaders(); |
|
|
|
// Allocate a header.. |
|
CWaveOutHdr *pHdr; |
|
if(!(pHdr = (CWaveOutHdr*)malloc(sizeof(CWaveOutHdr) - 1 + nSamples*2))) |
|
return false; |
|
|
|
// Make a new one. |
|
memset(&pHdr->m_Hdr, 0, sizeof(pHdr->m_Hdr)); |
|
pHdr->m_Hdr.lpData = pHdr->m_Data; |
|
pHdr->m_Hdr.dwBufferLength = nSamples * 2; |
|
memcpy(pHdr->m_Data, pSamples, nSamples*2); |
|
|
|
MMRESULT mmr = waveOutPrepareHeader(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr)); |
|
if(mmr != MMSYSERR_NOERROR) |
|
return false; |
|
|
|
mmr = waveOutWrite(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr)); |
|
if(mmr != MMSYSERR_NOERROR) |
|
{ |
|
delete pHdr; |
|
waveOutUnprepareHeader(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr)); |
|
return false; |
|
} |
|
|
|
m_nBufferedSamples += nSamples; |
|
|
|
// Queue up this header until waveOut is done with it. |
|
pHdr->m_pNext = m_Headers.m_pNext; |
|
m_Headers.m_pNext = pHdr; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CWaveOut::Idle() |
|
{ |
|
KillOldHeaders(); |
|
} |
|
|
|
int CWaveOut::GetNumBufferedSamples() |
|
{ |
|
return m_nBufferedSamples; |
|
} |
|
|
|
bool CWaveOut::Init(int sampleRate) |
|
{ |
|
Term(); |
|
|
|
|
|
WAVEFORMATEX format = |
|
{ |
|
WAVE_FORMAT_PCM, // wFormatTag |
|
1, // nChannels |
|
sampleRate, // nSamplesPerSec |
|
sampleRate*BYTES_PER_SAMPLE,// nAvgBytesPerSec |
|
BYTES_PER_SAMPLE, // nBlockAlign |
|
BYTES_PER_SAMPLE * 8, // wBitsPerSample |
|
sizeof(WAVEFORMATEX) |
|
}; |
|
|
|
MMRESULT mmr = waveOutOpen( |
|
&m_hWaveOut, |
|
0, |
|
&format, |
|
0, |
|
0, |
|
CALLBACK_NULL); |
|
|
|
return mmr == MMSYSERR_NOERROR; |
|
} |
|
|
|
void CWaveOut::Term() |
|
{ |
|
if(m_hWaveOut) |
|
{ |
|
waveOutClose(m_hWaveOut); |
|
m_hWaveOut = NULL; |
|
} |
|
} |
|
|
|
void CWaveOut::KillOldHeaders() |
|
{ |
|
// Look for any headers windows is done with. |
|
CWaveOutHdr *pNext; |
|
CWaveOutHdr **ppPrev = &m_Headers.m_pNext; |
|
for(CWaveOutHdr *pCur=m_Headers.m_pNext; pCur; pCur=pNext) |
|
{ |
|
pNext = pCur->m_pNext; |
|
|
|
if(pCur->m_Hdr.dwFlags & WHDR_DONE) |
|
{ |
|
m_nBufferedSamples -= (int)(pCur->m_Hdr.dwBufferLength / 2); |
|
assert(m_nBufferedSamples >= 0); |
|
waveOutUnprepareHeader(m_hWaveOut, &pCur->m_Hdr, sizeof(pCur->m_Hdr)); |
|
*ppPrev = pCur->m_pNext; |
|
free(pCur); |
|
} |
|
else |
|
{ |
|
ppPrev = &pCur->m_pNext; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
IWaveOut* CreateWaveOut(int sampleRate) |
|
{ |
|
CWaveOut *pRet = new CWaveOut; |
|
if(pRet && pRet->Init(sampleRate)) |
|
{ |
|
return pRet; |
|
} |
|
else |
|
{ |
|
delete pRet; |
|
return NULL; |
|
} |
|
} |
|
|
|
|
|
|