|
|
#include <windows.h>
#include "parameqp.h"
#include "clone.h"
STD_CREATE(ParamEq)
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::QueryInterface
//
// Subclass can override if it wants to implement more interfaces.
//
STDMETHODIMP CDirectSoundParamEqDMO::NDQueryInterface(THIS_ REFIID riid, LPVOID *ppv) { IMP_DSDMO_QI(riid,ppv);
if (riid == IID_IPersist) { return GetInterface((IPersist*)this, ppv); } else if (riid == IID_IMediaObject) { return GetInterface((IMediaObject*)this, ppv); } else if (riid == IID_IDirectSoundFXParamEq) { return GetInterface((IDirectSoundFXParamEq*)this, ppv); } else if (riid == IID_ISpecifyPropertyPages) { return GetInterface((ISpecifyPropertyPages*)this, ppv); } else if (riid == IID_IMediaParams) { return GetInterface((IMediaParams*)this, ppv); } else if (riid == IID_IMediaParamInfo) { return GetInterface((IMediaParamInfo*)this, ppv); } else return CComBase::NDQueryInterface(riid, ppv); }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::CDirectSoundParamEqDMO
//
CDirectSoundParamEqDMO::CDirectSoundParamEqDMO( IUnknown * pUnk, HRESULT *phr ) : CComBase( pUnk, phr ), m_fDirty(TRUE) // { EAX: put init data here if any (otherwise use Discontinuity).
// } EAX
{ m_EaxSamplesPerSec = 48000; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::Init()
//
HRESULT CDirectSoundParamEqDMO::Init() { DSFXParamEq param;
// Force recalc of all internal parameters
//
GetAllParameters(¶m); SetAllParameters(¶m);
return Discontinuity(); }
const MP_CAPS g_capsAll = MP_CAPS_CURVE_JUMP | MP_CAPS_CURVE_LINEAR | MP_CAPS_CURVE_SQUARE | MP_CAPS_CURVE_INVSQUARE | MP_CAPS_CURVE_SINE; static ParamInfo g_params[] = { // index type caps min, max, neutral, unit text, label, pwchText
PFP_Center, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_CENTER_MIN, DSFXPARAMEQ_CENTER_MAX, 8000, L"", L"Center", L"", PFP_Bandwidth, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_BANDWIDTH_MIN, DSFXPARAMEQ_BANDWIDTH_MAX, 12, L"", L"Bandwidth", L"", PFP_Gain, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_GAIN_MIN, DSFXPARAMEQ_GAIN_MAX, 0, L"", L"Gain", L"", };
HRESULT CDirectSoundParamEqDMO::InitOnCreation() { HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params); return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::~CDirectSoundParamEqDMO
//
CDirectSoundParamEqDMO::~CDirectSoundParamEqDMO() { }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::Clone
//
STDMETHODIMP CDirectSoundParamEqDMO::Clone(IMediaObjectInPlace **pp) { return StandardDMOClone<CDirectSoundParamEqDMO, DSFXParamEq>(this, pp); } //
// Bump - bump the delay pointers.
//
void CDirectSoundParamEqDMO::Bump(void) { // EAX {
// }
}
HRESULT CDirectSoundParamEqDMO::Discontinuity() { // { EAX
m_delayL1 = m_delayL2 = m_delayR1 = m_delayR2 = 0;
// } EAX
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
__forceinline void CDirectSoundParamEqDMO::DoOneSampleMono(int *l) { float inPortL = (float)*l; float outPortL, temp1, temp2, temp3;
temp1 = inPortL / 4;
// 2nd Order Ladder All Pass: Zeros first version
temp3 = m_delayL2 + temp1 * m_EaxApA; temp2 = temp1 - temp3 * m_EaxApA; m_delayL2 = m_delayL1 + temp2 * m_EaxApB; m_delayL1 = temp2 - m_delayL2 * m_EaxApB;
// Regalia Mitra Structure
temp3 = temp3 * m_EaxGainCoefA; temp3 = temp3 + temp1 * m_EaxGainCoefB; outPortL = m_EaxScale * temp3;
*l = Saturate(outPortL);
// Bump();
}
//////////////////////////////////////////////////////////////////////////////
__forceinline void CDirectSoundParamEqDMO::DoOneSample(int *l, int *r) { float inPortL = (float)*l; float inPortR = (float)*r; float outPortL, outPortR, temp1, temp2, temp3;
temp1 = inPortL / 4;
// 2nd Order Ladder All Pass: Zeros first version
temp3 = m_delayL2 + temp1 * m_EaxApA; temp2 = temp1 - temp3 * m_EaxApA; m_delayL2 = m_delayL1 + temp2 * m_EaxApB; m_delayL1 = temp2 - m_delayL2 * m_EaxApB;
// Regalia Mitra Structure
temp3 = temp3 * m_EaxGainCoefA; temp3 = temp3 + temp1 * m_EaxGainCoefB; outPortL = m_EaxScale * temp3;
*l = Saturate(outPortL);
temp1 = inPortR / 4;
// 2nd Order Ladder All Pass: Zeros first version
temp3 = m_delayR2 + temp1 * m_EaxApA; temp2 = temp1 - temp3 * m_EaxApA; m_delayR2 = m_delayR1 + temp2 * m_EaxApB; m_delayR1 = temp2 - m_delayR2 * m_EaxApB;
// Regalia Mitra Structure
temp3 = temp3 * m_EaxGainCoefA; temp3 = temp3 + temp1 * m_EaxGainCoefB; outPortR = m_EaxScale * temp3;
*r = Saturate(outPortR);
// Bump();
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::FBRProcess
//
HRESULT CDirectSoundParamEqDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut) { // { EAX
#define cb cSamples
#define pin pIn
#define pout pOut
if (m_cChannels == 1) { if (m_b8bit) { for (;cb > 0; --cb) { int i, j;
i = *(pin+0)-128; i *=256; // j = i;
DoOneSampleMono(&i); // i += j;
// i /= 2;
i /= 256;
*(pout+0) = (unsigned char)(i + 128); pin += sizeof(unsigned char); pout += sizeof(unsigned char); } } else if (!m_b8bit) { for (;cb > 0; --cb) { // for (;cb > 0; cb -= sizeof(short)) {
short int *psi = (short int *)pin; short int *pso = (short int *)pout; int i, j;
i = *psi; // j = i;
DoOneSampleMono(&i); // i += j;
// i /= 2;
*pso = (short)i; pin += sizeof(short); pout += sizeof(short); } } } else if (m_cChannels == 2) { if (m_b8bit) { for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(unsigned char)) {
int i, j;
i = *(pin+0)-128; j = *(pin+1)-128;
i *=256; j *=256;
DoOneSample(&i, &j); i /= 256; j /= 256; *(pout+0) = (unsigned char)(i + 128); *(pout+1) = (unsigned char)(j + 128); pin += 2 * sizeof(unsigned char); pout += 2 * sizeof(unsigned char); } } else if (!m_b8bit) { for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(short)) {
short int *psi = (short int *)pin; short int *pso = (short int *)pout; int i, j;
i = *(psi+0); j = *(psi+1);
DoOneSample(&i, &j); *(pso+0) = (short)i; *(pso+1) = (short)j; pin += 2 * sizeof(short); pout += 2 * sizeof(short); } } } // } EAX
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::ProcessInPlace
//
HRESULT CDirectSoundParamEqDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags) { HRESULT hr=S_OK; // Update parameter values from any curves that may be in effect.
this->UpdateActiveParams(rtStart, *this);
hr = FBRProcess(ulQuanta, pcbData, pcbData); return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::SetParam
//
// { EAX
// }
void CDirectSoundParamEqDMO::UpdateCoefficients(void) { float _gain, _omega, _lambda, _sinX;
//Calculate linear gain coefficient
_gain = (float)pow(10, m_EaxGain/20);
if (!_gain) _gain = (float).00001;
m_EaxGainCoefA = (1 - _gain)/2; m_EaxGainCoefB = (1 + _gain)/2; //Calculate scaling coefficient
m_EaxScale = (float)((fabs(m_EaxGainCoefA) > fabs(m_EaxGainCoefB)) ? fabs(m_EaxGainCoefA) : fabs(m_EaxGainCoefB)); m_EaxScale = (float)(m_EaxScale > 1 ? ceil(m_EaxScale) : 1);
m_EaxGainCoefA /= m_EaxScale; m_EaxGainCoefB /= m_EaxScale;
m_EaxScale = m_EaxScale * 4;
//Calculate allpass coefficients
_omega = (float)(2*PI*m_EaxCenter/m_EaxSamplesPerSec);
_sinX = (float)sin(_omega);
// if (!_sinX) _sinX = (float).000001;
_lambda = (float)(sinh(.5 * log(2) * m_EaxBandwidth/12 * _omega/_sinX) * sin(_omega)); m_EaxApA = (float)((1 - (_lambda/sqrt(_gain))) / (1 + (_lambda/sqrt(_gain)))); m_EaxApB = (float)(-cos(_omega)); }
HRESULT CDirectSoundParamEqDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager) { HRESULT hr = S_OK; HRESULT hr2 = S_OK;
switch (dwParamIndex) { // { EAX
case PFP_Center : CHECK_PARAM(DSFXPARAMEQ_CENTER_MIN, DSFXPARAMEQ_CENTER_MAX);
//if we are greater than 1/3rd the samplig rate then we need to S_FALSE;
if (value > (m_EaxSamplesPerSec/3)) { hr = S_FALSE; value = static_cast<MP_DATA>(m_EaxSamplesPerSec/3); }
PUT_EAX_VALUE(Center, value); UpdateCoefficients(); break; case PFP_Bandwidth : CHECK_PARAM(DSFXPARAMEQ_BANDWIDTH_MIN, DSFXPARAMEQ_BANDWIDTH_MAX);
PUT_EAX_VALUE(Bandwidth, value);
UpdateCoefficients(); break;
case PFP_Gain : { CHECK_PARAM(DSFXPARAMEQ_GAIN_MIN, DSFXPARAMEQ_GAIN_MAX);
PUT_EAX_VALUE(Gain, value);
UpdateCoefficients(); break; } // } EAX
default: return E_FAIL; }
// Let base class set this so it can handle all the rest of the param calls.
// Skip the base class if fSkipPasssingToParamManager. This indicates that we're calling the function
// internally using valuds that came from the base class -- thus there's no need to tell it values it
// already knows.
hr2 = fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
if(FAILED(hr2)) { hr = hr2; } return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::SetAllParameters
//
STDMETHODIMP CDirectSoundParamEqDMO::SetAllParameters(LPCDSFXParamEq peq) { HRESULT hr = S_OK; HRESULT hr2[3];
ZeroMemory(hr2,sizeof(hr2)); // Check that the pointer is not NULL
if (peq == NULL) { Trace(1,"ERROR: peq is NULL\n"); hr = E_POINTER; }
// Set the parameters
if (SUCCEEDED(hr)) hr = hr2[0] = SetParam(PFP_Center, peq->fCenter); if (SUCCEEDED(hr)) hr = hr2[1] = SetParam(PFP_Bandwidth, peq->fBandwidth); if (SUCCEEDED(hr)) hr = hr2[2] = SetParam(PFP_Gain, peq->fGain);
// if we have any alternate success codes, grab the first one and return it.
if(SUCCEEDED(hr)) { for (int i = 0;i < 3; i++) { if (hr2[i] != S_OK) { hr = hr2[i]; break; } } }
m_fDirty = true; return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundParamEqDMO::GetAllParameters
//
STDMETHODIMP CDirectSoundParamEqDMO::GetAllParameters(LPDSFXParamEq peq) { HRESULT hr = S_OK; MP_DATA mpd;
if (peq ==NULL) return E_POINTER;
#define GET_PARAM(x,y) \
if (SUCCEEDED(hr)) { \ hr = GetParam(x, &mpd); \ if (SUCCEEDED(hr)) peq->y = mpd; \ }
GET_PARAM(PFP_Center, fCenter); GET_PARAM(PFP_Bandwidth, fBandwidth); GET_PARAM(PFP_Gain, fGain);
return hr; }
// GetClassID
//
// Part of the persistent file support. We must supply our class id
// which can be saved in a graph file and used on loading a graph with
// this fx in it to instantiate this filter via CoCreateInstance.
//
HRESULT CDirectSoundParamEqDMO::GetClassID(CLSID *pClsid) { if (pClsid==NULL) { return E_POINTER; } *pClsid = GUID_DSFX_STANDARD_PARAMEQ; return NOERROR;
} // GetClassID
|