Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include <windows.h>
  9. #include <assert.h>
  10. #include <mmsystem.h>
  11. #include "waveout.h"
  12. #include "ivoicecodec.h"
  13. class CWaveOutHdr
  14. {
  15. public:
  16. WAVEHDR m_Hdr;
  17. CWaveOutHdr *m_pNext;
  18. char m_Data[1];
  19. };
  20. class CWaveOut : public IWaveOut
  21. {
  22. // IWaveOut overrides.
  23. public:
  24. CWaveOut();
  25. virtual ~CWaveOut();
  26. virtual void Release();
  27. virtual bool PutSamples(short *pSamples, int nSamples);
  28. virtual void Idle();
  29. virtual int GetNumBufferedSamples();
  30. public:
  31. bool Init(int sampleRate);
  32. void Term();
  33. private:
  34. void KillOldHeaders();
  35. private:
  36. HWAVEOUT m_hWaveOut;
  37. CWaveOutHdr m_Headers; // Head of a linked list of WAVEHDRs.
  38. int m_nBufferedSamples;
  39. };
  40. CWaveOut::CWaveOut()
  41. {
  42. m_hWaveOut = NULL;
  43. m_Headers.m_pNext = NULL;
  44. m_nBufferedSamples = 0;
  45. }
  46. CWaveOut::~CWaveOut()
  47. {
  48. Term();
  49. }
  50. void CWaveOut::Release()
  51. {
  52. delete this;
  53. }
  54. bool CWaveOut::PutSamples(short *pInSamples, int nInSamples)
  55. {
  56. int granularity = 2048;
  57. while( nInSamples )
  58. {
  59. int nSamples = (nInSamples > granularity) ? granularity : nInSamples;
  60. short *pSamples = pInSamples;
  61. nInSamples -= nSamples;
  62. pInSamples += nSamples;
  63. if(!m_hWaveOut)
  64. return false;
  65. // Kill any old headers..
  66. KillOldHeaders();
  67. // Allocate a header..
  68. CWaveOutHdr *pHdr;
  69. if(!(pHdr = (CWaveOutHdr*)malloc(sizeof(CWaveOutHdr) - 1 + nSamples*2)))
  70. return false;
  71. // Make a new one.
  72. memset(&pHdr->m_Hdr, 0, sizeof(pHdr->m_Hdr));
  73. pHdr->m_Hdr.lpData = pHdr->m_Data;
  74. pHdr->m_Hdr.dwBufferLength = nSamples * 2;
  75. memcpy(pHdr->m_Data, pSamples, nSamples*2);
  76. MMRESULT mmr = waveOutPrepareHeader(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr));
  77. if(mmr != MMSYSERR_NOERROR)
  78. return false;
  79. mmr = waveOutWrite(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr));
  80. if(mmr != MMSYSERR_NOERROR)
  81. {
  82. delete pHdr;
  83. waveOutUnprepareHeader(m_hWaveOut, &pHdr->m_Hdr, sizeof(pHdr->m_Hdr));
  84. return false;
  85. }
  86. m_nBufferedSamples += nSamples;
  87. // Queue up this header until waveOut is done with it.
  88. pHdr->m_pNext = m_Headers.m_pNext;
  89. m_Headers.m_pNext = pHdr;
  90. }
  91. return true;
  92. }
  93. void CWaveOut::Idle()
  94. {
  95. KillOldHeaders();
  96. }
  97. int CWaveOut::GetNumBufferedSamples()
  98. {
  99. return m_nBufferedSamples;
  100. }
  101. bool CWaveOut::Init(int sampleRate)
  102. {
  103. Term();
  104. WAVEFORMATEX format =
  105. {
  106. WAVE_FORMAT_PCM, // wFormatTag
  107. 1, // nChannels
  108. sampleRate, // nSamplesPerSec
  109. sampleRate*BYTES_PER_SAMPLE,// nAvgBytesPerSec
  110. BYTES_PER_SAMPLE, // nBlockAlign
  111. BYTES_PER_SAMPLE * 8, // wBitsPerSample
  112. sizeof(WAVEFORMATEX)
  113. };
  114. MMRESULT mmr = waveOutOpen(
  115. &m_hWaveOut,
  116. 0,
  117. &format,
  118. 0,
  119. 0,
  120. CALLBACK_NULL);
  121. return mmr == MMSYSERR_NOERROR;
  122. }
  123. void CWaveOut::Term()
  124. {
  125. if(m_hWaveOut)
  126. {
  127. waveOutClose(m_hWaveOut);
  128. m_hWaveOut = NULL;
  129. }
  130. }
  131. void CWaveOut::KillOldHeaders()
  132. {
  133. // Look for any headers windows is done with.
  134. CWaveOutHdr *pNext;
  135. CWaveOutHdr **ppPrev = &m_Headers.m_pNext;
  136. for(CWaveOutHdr *pCur=m_Headers.m_pNext; pCur; pCur=pNext)
  137. {
  138. pNext = pCur->m_pNext;
  139. if(pCur->m_Hdr.dwFlags & WHDR_DONE)
  140. {
  141. m_nBufferedSamples -= (int)(pCur->m_Hdr.dwBufferLength / 2);
  142. assert(m_nBufferedSamples >= 0);
  143. waveOutUnprepareHeader(m_hWaveOut, &pCur->m_Hdr, sizeof(pCur->m_Hdr));
  144. *ppPrev = pCur->m_pNext;
  145. free(pCur);
  146. }
  147. else
  148. {
  149. ppPrev = &pCur->m_pNext;
  150. }
  151. }
  152. }
  153. IWaveOut* CreateWaveOut(int sampleRate)
  154. {
  155. CWaveOut *pRet = new CWaveOut;
  156. if(pRet && pRet->Init(sampleRate))
  157. {
  158. return pRet;
  159. }
  160. else
  161. {
  162. delete pRet;
  163. return NULL;
  164. }
  165. }