2025-04-27 07:49:33 -04:00

116 lines
3.8 KiB
C++

#include <dmocom.h>
#define DMO_NOATL // the base class needs this to work w/o ATL
#include <dmobase.h>
#include "initguid.h"
DEFINE_GUID(CLSID_FIRtest, 0xfb74ee25,0x4329,0x43d9,0xba,0xbe,0x48,0xe0,0xb7,0x5d,0xf8,0x56);
class CFIRtest : public CComBase,
public CPCMDMO
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NDQueryInterface(REFIID riid, void **ppv);
static CComBase *CreateInstance(IUnknown *pUnk, HRESULT *phr);
CFIRtest(IUnknown *pUnk, HRESULT *phr);
// All of these methods are called by the base class
HRESULT FBRProcess(DWORD cQuanta, BYTE *pIn, BYTE *pOut);
void GetWindowParams(DWORD *pdwMaxLookahead, DWORD *pdwMaxLookbehind);
BOOL CheckPCMParams(BOOL b8bit, DWORD cChannels, DWORD dwSamplesPerSec);
};
CFIRtest::CFIRtest(IUnknown *pUnk, HRESULT *phr)
: CComBase(pUnk, phr)
{
}
// Really all we need is lookbehind of 21 and out lookahead is zero.
// To test the base class, we arbitrarily split it between the two.
// That means output will be shifted relative to input by 4 samples.
#define LOOKAHEAD 4
#define LOOKBEHIND 17
void CFIRtest::GetWindowParams(DWORD *pdwMaxLookahead, DWORD *pdwMaxLookbehind) {
*pdwMaxLookahead = LOOKAHEAD;
*pdwMaxLookbehind = LOOKBEHIND;
}
BOOL CFIRtest::CheckPCMParams(BOOL b8bit, DWORD cChannels, DWORD dwSamplesPerSec) {
if (dwSamplesPerSec != 44100)
return FALSE; // my FIR coefficients assume 44100, sorry
if (b8bit)
return FALSE; // I don't want to deal with 8 bit values
return TRUE;
}
// This is a 4dB 1/2 octave peak at 12.5k and a 8dB 1/2 octave trough at 15k.
signed short coefficients[LOOKBEHIND + 1 + LOOKAHEAD] = {
-1,0,3,0,-7,-1,20,6,-58,1,157,-74,-353,368,601,-1097,-565,
2369,
-444,-3122,2640,15967
};
// Point to the logically zeroth coefficient
signed short *c = &(coefficients[LOOKBEHIND]);
//
// We specified a lookahead of 4 and a lookbehind of 17. That means we are
// allowed to dereference samples in the input buffer up to 4 positions ahead
// of the current sample and up to 17 positions back from the current sample,
// even when at the boundary of the input buffer. The base class made sure
// that the data there is valid for us.
//
HRESULT CFIRtest::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut) {
DWORD cSample, cChannel;
signed short* in = (signed short*)pIn;
signed short* out = (signed short*)pOut;
for (cSample = 0; cSample < cSamples; cSample++) {
for (cChannel = 0; cChannel < m_cChannels; cChannel++) {
double Accum = 0.0;
for (int i = -LOOKBEHIND; i <= +LOOKAHEAD; i++) {
double val = in[(cSample + i) * m_cChannels + cChannel];
double coeff = ((double) c[i]) / 16384.0;
Accum += val * coeff;
}
out[cSample * m_cChannels + cChannel] = (signed short) Accum;
}
}
return NOERROR;
}
//
// COM stuff
//
CComBase* CFIRtest::CreateInstance(IUnknown *pUnk, HRESULT *phr) {
return new CFIRtest(pUnk, phr);
}
HRESULT CFIRtest::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_FIRtest,
CFIRtest::CreateInstance
}
};
int g_cComClassTemplates = 1;
STDAPI DllRegisterServer(void) {
HRESULT hr;
// Register as a COM class
hr = CreateCLSIDRegKey(CLSID_FIRtest, "FIRtest media object");
if (FAILED(hr))
return hr;
// Now register as a DMO
return DMORegister(L"audio FIR filter", CLSID_FIRtest, DMOCATEGORY_AUDIO_EFFECT, 0, 0, NULL, 0, NULL);
}
STDAPI DllUnregisterServer(void) {
// BUGBUG - implement !
return S_OK;
}