windows-nt/Source/XPSP1/NT/multimedia/dshow/dmo/gargle/gargle.cpp
2020-09-26 16:20:57 +08:00

180 lines
5 KiB
C++

#include <windows.h>
#include <dmocom.h>
#define DMO_NOATL // DMO base class needs this to work w/o ATL
#include <dmobase.h>
#include "initguid.h"
DEFINE_GUID(CLSID_GargleDMO, 0xdafd8210,0x5711,0x4b91,0x9f,0xe3,0xf7,0x5b,0x7a,0xe2,0x79,0xbf);
class CGargle : public CComBase,
public CPCMDMO
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NDQueryInterface(REFIID riid, void **ppv);
static CComBase* WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
CGargle(IUnknown *pUnk, HRESULT *phr);
// All of these methods are called by the base class
HRESULT FBRProcess(DWORD cQuanta, BYTE *pIn, BYTE *pOut);
HRESULT Init();
HRESULT Discontinuity();
void GetWindowParams(DWORD *pdwMaxLookahead,DWORD *pdwMaxLookbehind);
private:
// gargle params
ULONG m_ulPeriod;
ULONG m_ulShape;
ULONG m_ulGargleFreqHz;
// gargle state
ULONG m_ulPhase;
BOOL m_bInitialized;
};
CGargle::CGargle(IUnknown *pUnk, HRESULT *phr)
: CComBase(pUnk, phr),
m_ulShape(0),
m_ulGargleFreqHz(20),
m_bInitialized(FALSE)
{
}
void CGargle::GetWindowParams(
DWORD *pdwMaxLookahead, // in input quanta, 0 means no lookahead
DWORD *pdwMaxLookbehind
) {
*pdwMaxLookahead = 0;
*pdwMaxLookbehind = 0;
}
HRESULT CGargle::Init() {
// compute the period
m_ulPeriod = m_ulSamplingRate / m_ulGargleFreqHz;
m_bInitialized = TRUE;
return NOERROR;
}
HRESULT CGargle::Discontinuity() {
m_ulPhase = 0;
return NOERROR;
}
HRESULT CGargle::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut) {
if (!m_bInitialized)
return DMO_E_TYPE_NOT_SET;
// test code
//memcpy(pOut, pIn, cSamples * m_cChannels * (m_b8bit ? 1 : 2));
//return NOERROR;
DWORD cSample, cChannel;
for (cSample = 0; cSample < cSamples; cSample++) {
// If m_Shape is 0 (triangle) then we multiply by a triangular waveform
// that runs 0..Period/2..0..Period/2..0... else by a square one that
// is either 0 or Period/2 (same maximum as the triangle) or zero.
//
// m_Phase is the number of samples from the start of the period.
// We keep this running from one call to the next,
// but if the period changes so as to make this more
// than Period then we reset to 0 with a bang. This may cause
// an audible click or pop (but, hey! it's only a sample!)
//
++m_ulPhase;
if (m_ulPhase > m_ulPeriod)
m_ulPhase = 0;
ULONG ulM = m_ulPhase; // m is what we modulate with
if (m_ulShape == 0) { // Triangle
if (ulM > m_ulPeriod / 2)
ulM = m_ulPeriod - ulM; // handle downslope
} else { // Square wave
if (ulM <= m_ulPeriod / 2)
ulM = m_ulPeriod / 2;
else
ulM = 0;
}
for (cChannel = 0; cChannel < m_cChannels; cChannel++) {
if (m_b8bit) {
// sound sample, zero based
int i = pIn[cSample * m_cChannels + cChannel] - 128;
// modulate
i = (i * (signed)ulM * 2) / (signed)m_ulPeriod;
// 8 bit sound uses 0..255 representing -128..127
// Any overflow, even by 1, would sound very bad.
// so we clip paranoically after modulating.
// I think it should never clip by more than 1
//
if (i > 127)
i = 127;
if (i < -128)
i = -128;
// reset zero offset to 128
pOut[cSample * m_cChannels + cChannel] = (unsigned char)(i + 128);
} else {
// 16 bit sound uses 16 bits properly (0 means 0)
// We still clip paranoically
//
int i = ((short*)pIn)[cSample * m_cChannels + cChannel];
// modulate
i = (i * (signed)ulM * 2) / (signed)m_ulPeriod;
// clip
if (i > 32767)
i = 32767;
if (i < -32768)
i = -32768;
((short*)pOut)[cSample * m_cChannels + cChannel] = (short)i;
}
}
}
return NOERROR;
}
//
// COM stuff
//
CComBase* WINAPI CGargle::CreateInstance(IUnknown *pUnk, HRESULT *phr) {
return new CGargle(pUnk, phr);
}
HRESULT CGargle::NDQueryInterface(REFIID riid, void **ppv) {
if (riid == IID_IMediaObject)
return GetInterface((IMediaObject*)this, ppv);
else
return CComBase::NDQueryInterface(riid, ppv);
}
struct CComClassTemplate g_ComClassTemplates[] = {
{
&CLSID_GargleDMO,
CGargle::CreateInstance
}
};
int g_cComClassTemplates = 1;
STDAPI DllRegisterServer(void) {
HRESULT hr;
// Register as a COM class
hr = CreateCLSIDRegKey(CLSID_GargleDMO, "Gargle media object");
if (FAILED(hr))
return hr;
// Now register as a DMO
DMO_PARTIAL_MEDIATYPE mt;
mt.type = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
return DMORegister(L"gargle", CLSID_GargleDMO, DMOCATEGORY_AUDIO_EFFECT, 0, 1, &mt, 1, &mt);
}
STDAPI DllUnregisterServer(void) {
// BUGBUG - implement !
return S_OK;
}