mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 09:49:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
//========= 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user