Source code of Windows XP (NT5)
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.

179 lines
5.0 KiB

  1. #include <windows.h>
  2. #include <dmocom.h>
  3. #define DMO_NOATL // DMO base class needs this to work w/o ATL
  4. #include <dmobase.h>
  5. #include "initguid.h"
  6. DEFINE_GUID(CLSID_GargleDMO, 0xdafd8210,0x5711,0x4b91,0x9f,0xe3,0xf7,0x5b,0x7a,0xe2,0x79,0xbf);
  7. class CGargle : public CComBase,
  8. public CPCMDMO
  9. {
  10. public:
  11. DECLARE_IUNKNOWN;
  12. STDMETHODIMP NDQueryInterface(REFIID riid, void **ppv);
  13. static CComBase* WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
  14. CGargle(IUnknown *pUnk, HRESULT *phr);
  15. // All of these methods are called by the base class
  16. HRESULT FBRProcess(DWORD cQuanta, BYTE *pIn, BYTE *pOut);
  17. HRESULT Init();
  18. HRESULT Discontinuity();
  19. void GetWindowParams(DWORD *pdwMaxLookahead,DWORD *pdwMaxLookbehind);
  20. private:
  21. // gargle params
  22. ULONG m_ulPeriod;
  23. ULONG m_ulShape;
  24. ULONG m_ulGargleFreqHz;
  25. // gargle state
  26. ULONG m_ulPhase;
  27. BOOL m_bInitialized;
  28. };
  29. CGargle::CGargle(IUnknown *pUnk, HRESULT *phr)
  30. : CComBase(pUnk, phr),
  31. m_ulShape(0),
  32. m_ulGargleFreqHz(20),
  33. m_bInitialized(FALSE)
  34. {
  35. }
  36. void CGargle::GetWindowParams(
  37. DWORD *pdwMaxLookahead, // in input quanta, 0 means no lookahead
  38. DWORD *pdwMaxLookbehind
  39. ) {
  40. *pdwMaxLookahead = 0;
  41. *pdwMaxLookbehind = 0;
  42. }
  43. HRESULT CGargle::Init() {
  44. // compute the period
  45. m_ulPeriod = m_ulSamplingRate / m_ulGargleFreqHz;
  46. m_bInitialized = TRUE;
  47. return NOERROR;
  48. }
  49. HRESULT CGargle::Discontinuity() {
  50. m_ulPhase = 0;
  51. return NOERROR;
  52. }
  53. HRESULT CGargle::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut) {
  54. if (!m_bInitialized)
  55. return DMO_E_TYPE_NOT_SET;
  56. // test code
  57. //memcpy(pOut, pIn, cSamples * m_cChannels * (m_b8bit ? 1 : 2));
  58. //return NOERROR;
  59. DWORD cSample, cChannel;
  60. for (cSample = 0; cSample < cSamples; cSample++) {
  61. // If m_Shape is 0 (triangle) then we multiply by a triangular waveform
  62. // that runs 0..Period/2..0..Period/2..0... else by a square one that
  63. // is either 0 or Period/2 (same maximum as the triangle) or zero.
  64. //
  65. // m_Phase is the number of samples from the start of the period.
  66. // We keep this running from one call to the next,
  67. // but if the period changes so as to make this more
  68. // than Period then we reset to 0 with a bang. This may cause
  69. // an audible click or pop (but, hey! it's only a sample!)
  70. //
  71. ++m_ulPhase;
  72. if (m_ulPhase > m_ulPeriod)
  73. m_ulPhase = 0;
  74. ULONG ulM = m_ulPhase; // m is what we modulate with
  75. if (m_ulShape == 0) { // Triangle
  76. if (ulM > m_ulPeriod / 2)
  77. ulM = m_ulPeriod - ulM; // handle downslope
  78. } else { // Square wave
  79. if (ulM <= m_ulPeriod / 2)
  80. ulM = m_ulPeriod / 2;
  81. else
  82. ulM = 0;
  83. }
  84. for (cChannel = 0; cChannel < m_cChannels; cChannel++) {
  85. if (m_b8bit) {
  86. // sound sample, zero based
  87. int i = pIn[cSample * m_cChannels + cChannel] - 128;
  88. // modulate
  89. i = (i * (signed)ulM * 2) / (signed)m_ulPeriod;
  90. // 8 bit sound uses 0..255 representing -128..127
  91. // Any overflow, even by 1, would sound very bad.
  92. // so we clip paranoically after modulating.
  93. // I think it should never clip by more than 1
  94. //
  95. if (i > 127)
  96. i = 127;
  97. if (i < -128)
  98. i = -128;
  99. // reset zero offset to 128
  100. pOut[cSample * m_cChannels + cChannel] = (unsigned char)(i + 128);
  101. } else {
  102. // 16 bit sound uses 16 bits properly (0 means 0)
  103. // We still clip paranoically
  104. //
  105. int i = ((short*)pIn)[cSample * m_cChannels + cChannel];
  106. // modulate
  107. i = (i * (signed)ulM * 2) / (signed)m_ulPeriod;
  108. // clip
  109. if (i > 32767)
  110. i = 32767;
  111. if (i < -32768)
  112. i = -32768;
  113. ((short*)pOut)[cSample * m_cChannels + cChannel] = (short)i;
  114. }
  115. }
  116. }
  117. return NOERROR;
  118. }
  119. //
  120. // COM stuff
  121. //
  122. CComBase* WINAPI CGargle::CreateInstance(IUnknown *pUnk, HRESULT *phr) {
  123. return new CGargle(pUnk, phr);
  124. }
  125. HRESULT CGargle::NDQueryInterface(REFIID riid, void **ppv) {
  126. if (riid == IID_IMediaObject)
  127. return GetInterface((IMediaObject*)this, ppv);
  128. else
  129. return CComBase::NDQueryInterface(riid, ppv);
  130. }
  131. struct CComClassTemplate g_ComClassTemplates[] = {
  132. {
  133. &CLSID_GargleDMO,
  134. CGargle::CreateInstance
  135. }
  136. };
  137. int g_cComClassTemplates = 1;
  138. STDAPI DllRegisterServer(void) {
  139. HRESULT hr;
  140. // Register as a COM class
  141. hr = CreateCLSIDRegKey(CLSID_GargleDMO, "Gargle media object");
  142. if (FAILED(hr))
  143. return hr;
  144. // Now register as a DMO
  145. DMO_PARTIAL_MEDIATYPE mt;
  146. mt.type = MEDIATYPE_Audio;
  147. mt.subtype = MEDIASUBTYPE_PCM;
  148. return DMORegister(L"gargle", CLSID_GargleDMO, DMOCATEGORY_AUDIO_EFFECT, 0, 1, &mt, 1, &mt);
  149. }
  150. STDAPI DllUnregisterServer(void) {
  151. // BUGBUG - implement !
  152. return S_OK;
  153. }