diff options
Diffstat (limited to 'utils/voice_tweak/waveout.cpp')
| -rw-r--r-- | utils/voice_tweak/waveout.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/utils/voice_tweak/waveout.cpp b/utils/voice_tweak/waveout.cpp new file mode 100644 index 0000000..2f58e76 --- /dev/null +++ b/utils/voice_tweak/waveout.cpp @@ -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; + } +} + + |