|
|
#include <windows.h>
#include "distortp.h"
#include "debug.h"
#include "clone.h"
STD_CREATE(Distortion)
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortDMO::NDQueryInterface
//
// Subclass can override if it wants to implement more interfaces.
//
STDMETHODIMP CDirectSoundDistortionDMO::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_IDirectSoundFXDistortion) { return GetInterface((IDirectSoundFXDistortion*)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); }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::CDirectSoundDistortionDMO
//
CDirectSoundDistortionDMO::CDirectSoundDistortionDMO( IUnknown *pUnk, HRESULT *phr ) : CComBase( pUnk, phr ), m_fDirty(false) // { EAX: put init data here if any (otherwise use Discontinuity).
// } EAX
{ m_EaxSamplesPerSec = 44010; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::Init()
//
HRESULT CDirectSoundDistortionDMO::Init() { DSFXDistortion distort;
// Force recalc of all internal parameters
//
GetAllParameters(&distort); SetAllParameters(&distort);
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
DFP_Gain, MPT_FLOAT, g_capsAll, DSFXDISTORTION_GAIN_MIN, DSFXDISTORTION_GAIN_MAX, -18, L"", L"Gain", L"", DFP_Edge, MPT_FLOAT, g_capsAll, DSFXDISTORTION_EDGE_MIN, DSFXDISTORTION_EDGE_MAX, 15, L"", L"Edge", L"", DFP_LpCutoff, MPT_FLOAT, g_capsAll, DSFXDISTORTION_PRELOWPASSCUTOFF_MIN, DSFXDISTORTION_PRELOWPASSCUTOFF_MAX, 8000, L"", L"PreLowpassCutoff", L"", DFP_EqCenter, MPT_FLOAT, g_capsAll, DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN, DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX, 2400, L"", L"PostEQCenterFrequency", L"", DFP_EqWidth, MPT_FLOAT, g_capsAll, DSFXDISTORTION_POSTEQBANDWIDTH_MIN, DSFXDISTORTION_POSTEQBANDWIDTH_MAX, 2400, L"", L"PostEQBandwidth", L"", };
HRESULT CDirectSoundDistortionDMO::InitOnCreation() { HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params); return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::~CDirectSoundDistortionDMO
//
CDirectSoundDistortionDMO::~CDirectSoundDistortionDMO() { }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::Clone
//
STDMETHODIMP CDirectSoundDistortionDMO::Clone(IMediaObjectInPlace **pp) { return StandardDMOClone<CDirectSoundDistortionDMO, DSFXDistortion>(this, pp); }
//
// Bump - bump the delay pointers.
//
void CDirectSoundDistortionDMO::Bump(void) { // EAX {
// }
}
HRESULT CDirectSoundDistortionDMO::Discontinuity() { // { EAX
m_delayL1 = m_delayL2 = m_delayR1 = m_delayR2 = 0; m_ls0 = m_rs0 = 0.0;
// } EAX
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
__forceinline void CDirectSoundDistortionDMO::DoOneSampleMono(int *l) { float inPortL = (float)*l; float outPortL, tempvar;
// One-pole lowpass filter
outPortL = inPortL * m_EaxLpff; m_ls0 = outPortL + m_ls0 * m_EaxLpfb; ////////////////////////////////////////
////////////////////////////////////////
// Non-linear gain
#define LOG(x,y) mylog(x,y)
outPortL = (float)LOG(m_ls0 * 0x8000, m_EaxExp_range);
outPortL /= 0x8000;
////////////////////////////////////////
////////////////////////////////////////
// Bandpass
outPortL = outPortL * m_EaxInScale; tempvar = outPortL - m_delayL1 * m_EaxK2; tempvar = tempvar - m_delayL2 * m_EaxK1; m_delayL1 = m_delayL2 + tempvar * m_EaxK1; m_delayL2 = tempvar; outPortL = tempvar;
////////////////////////////////////////
#ifdef GOOD_CODE_GEN
*l = Saturate(outPortL); #else
int i;
#ifdef i386
_asm { fld outPortL fistp i } #else
i = (int)outPortL; #endif
if (i > 32767) i = 32767; else if ( i < -32768) i = -32768;
*l = i; #endif
// Bump();
}
//////////////////////////////////////////////////////////////////////////////
__forceinline void CDirectSoundDistortionDMO::DoOneSample(int *l, int *r) { float inPortL = (float)*l; float inPortR = (float)*r; float outPortL, outPortR, tempvar;
// One-pole lowpass filter
outPortL = inPortL * m_EaxLpff; outPortR = inPortR * m_EaxLpff; m_ls0 = outPortL + m_ls0 * m_EaxLpfb; m_rs0 = outPortR + m_rs0 * m_EaxLpfb; ////////////////////////////////////////
////////////////////////////////////////
// Non-linear gain
#define LOG(x,y) mylog(x,y)
outPortL = (float)LOG(m_ls0 * 0x8000, m_EaxExp_range); outPortR = (float)LOG(m_rs0 * 0x8000, m_EaxExp_range);
outPortL /= 0x8000; outPortR /= 0x8000;
////////////////////////////////////////
////////////////////////////////////////
// Bandpass
outPortL = outPortL * m_EaxInScale; tempvar = outPortL - m_delayL1 * m_EaxK2; tempvar = tempvar - m_delayL2 * m_EaxK1; m_delayL1 = m_delayL2 + tempvar * m_EaxK1; m_delayL2 = tempvar; outPortL = tempvar;
outPortR = outPortR * m_EaxInScale; tempvar = outPortR - m_delayR1 * m_EaxK2; tempvar = tempvar - m_delayR2 * m_EaxK1; m_delayR1 = m_delayR2 + tempvar * m_EaxK1; m_delayR2 = tempvar; outPortR = tempvar; ////////////////////////////////////////
*l = Saturate(outPortL); *r = Saturate(outPortR);
// Bump();
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::FBRProcess
//
HRESULT CDirectSoundDistortionDMO::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; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::ProcessInPlace
//
HRESULT CDirectSoundDistortionDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags) { // Update parameter values from any curves that may be in effect.
this->UpdateActiveParams(rtStart, *this);
return FBRProcess(ulQuanta, pcbData, pcbData); }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::SetParam
//
// { EAX
// }
HRESULT CDirectSoundDistortionDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager) { HRESULT hr = S_OK; HRESULT hr2 = S_OK;
//if (!m_EaxSamplesPerSec) return DMO_E_TYPE_NOT_ACCEPTED; // NO TYPE!
switch (dwParamIndex) { // { EAX
case DFP_Gain : { CHECK_PARAM(DSFXDISTORTION_GAIN_MIN, DSFXDISTORTION_GAIN_MAX);
PUT_EAX_VALUE(Gain, value);
m_EaxGain = (float)pow(10, m_EaxGain/20);
INTERPOLATE(InScale, TOFRACTION(m_EaxScale*m_EaxGain)); break;
case DFP_Edge: CHECK_PARAM(DSFXDISTORTION_EDGE_MIN, DSFXDISTORTION_EDGE_MAX);
PUT_EAX_VALUE(Edge, value);
m_EaxEdge = (m_EaxEdge/100 * 29) + 2;
PUT_EAX_VALUE(Exp_range, (DWORD) m_EaxEdge);
SetParamInternal(DFP_EqCenter, m_EaxCenter, true); SetParamInternal(DFP_EqWidth, m_EaxBandwidth, true); break;
case DFP_LpCutoff: CHECK_PARAM(DSFXDISTORTION_PRELOWPASSCUTOFF_MIN, DSFXDISTORTION_PRELOWPASSCUTOFF_MAX);
//Clamp at Fs/3;
if (value > (MP_DATA)(m_EaxSamplesPerSec / 3)) { value = (MP_DATA)(m_EaxSamplesPerSec / 3); hr = S_FALSE; }
m_EaxLpfb = (float)sqrt((2*cos(2*PI*value/m_EaxSamplesPerSec)+3)/5); m_EaxLpff = (float)sqrt(1-m_EaxLpfb*m_EaxLpfb); break;
case DFP_EqCenter: { CHECK_PARAM(DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN, DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX);
//Clamp at Fs/3;
if (value > (MP_DATA)(m_EaxSamplesPerSec / 3)) { value = (MP_DATA)(m_EaxSamplesPerSec / 3); hr = S_FALSE; }
PUT_EAX_VALUE(Center, value);
double _k1, _k2, _omega;
_omega = 2*PI*m_EaxBandwidth/m_EaxSamplesPerSec; _k1 = -cos(2*PI*value/m_EaxSamplesPerSec); _k2 = (1 - tan(_omega/2)) / (1 + tan(_omega/2));
m_EaxScale = (float)(sqrt(1 - _k1*_k1) * sqrt(1 - _k2*_k2)); m_EaxScale = (float)(m_EaxScale * LogNorm[(int)m_EaxEdge]);
INTERPOLATE(K1, TOFRACTION(_k1)); INTERPOLATE(InScale, TOFRACTION(m_EaxScale*m_EaxGain)); break; } case DFP_EqWidth: { CHECK_PARAM(DSFXDISTORTION_POSTEQBANDWIDTH_MIN, DSFXDISTORTION_POSTEQBANDWIDTH_MAX);
//Clamp at Fs/3;
if (value > (MP_DATA)(m_EaxSamplesPerSec / 3)) { value = (MP_DATA)(m_EaxSamplesPerSec / 3); hr = S_FALSE; }
PUT_EAX_VALUE(Bandwidth, value);
double _k1, _k2, _omega;
_omega = 2*PI*value/m_EaxSamplesPerSec; _k1 = (float)(-cos(2*PI*m_EaxCenter/m_EaxSamplesPerSec)); _k2 = (float)((1 - tan(_omega/2)) / (1 + tan(_omega/2)));
m_EaxScale = (float)(sqrt(1 - _k1*_k1) * sqrt(1 - _k2*_k2)); m_EaxScale = (float)(m_EaxScale * LogNorm[(int)m_EaxEdge]);
INTERPOLATE(K2, TOFRACTION(_k2)); INTERPOLATE(InScale, TOFRACTION(m_EaxScale*m_EaxGain)); 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);
//Preserve the S_FALSE if there is one
if (FAILED(hr2)) hr = hr2;
return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::SetAllParameters
//
STDMETHODIMP CDirectSoundDistortionDMO::SetAllParameters(LPCDSFXDistortion pDistort) { HRESULT hr = S_OK; HRESULT hr2[5];
ZeroMemory(hr2,sizeof(hr2)); // Check that the pointer is not NULL
if (pDistort == NULL) { Trace(1,"ERROR: pDistort is NULL\n"); hr = E_POINTER; }
// Set the parameters
if (SUCCEEDED(hr)) hr = hr2[0] = SetParam(DFP_Gain, pDistort->fGain); if (SUCCEEDED(hr)) hr = hr2[1] = SetParam(DFP_Edge, pDistort->fEdge); if (SUCCEEDED(hr)) hr = hr2[2] = SetParam(DFP_LpCutoff, pDistort->fPreLowpassCutoff); if (SUCCEEDED(hr)) hr = hr2[3] = SetParam(DFP_EqCenter, pDistort->fPostEQCenterFrequency); if (SUCCEEDED(hr)) hr = hr2[4] = SetParam(DFP_EqWidth, pDistort->fPostEQBandwidth);
m_fDirty = true;
// if we have any alternate success codes, grab the first one and return it.
if(SUCCEEDED(hr)) { for (int i = 0;i < 5; i++) { if (hr2[i] != S_OK) { hr = hr2[i]; break; } } } return hr; }
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundDistortionDMO::GetAllParameters
//
STDMETHODIMP CDirectSoundDistortionDMO::GetAllParameters(LPDSFXDistortion pDistort) { HRESULT hr = S_OK; MP_DATA mpd;
if (pDistort == NULL) { return E_POINTER; } #define GET_PARAM(x,y) \
if (SUCCEEDED(hr)) { \ hr = GetParam(x, &mpd); \ if (SUCCEEDED(hr)) pDistort->y = mpd; \ }
GET_PARAM(DFP_Edge, fEdge); GET_PARAM(DFP_Gain, fGain); GET_PARAM(DFP_LpCutoff, fPreLowpassCutoff); GET_PARAM(DFP_EqCenter, fPostEQCenterFrequency); GET_PARAM(DFP_EqWidth, fPostEQBandwidth);
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 CDirectSoundDistortionDMO::GetClassID(CLSID *pClsid) { if (pClsid==NULL) { return E_POINTER; } *pClsid = GUID_DSFX_STANDARD_DISTORTION; return NOERROR;
} // GetClassID
|