windows-nt/Source/XPSP1/NT/multimedia/directx/dsound/dsdmo/sverbdmo.cpp

391 lines
11 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <windows.h>
#include "sverb.h"
#include "sverbp.h"
#include "clone.h"
STD_CREATE(WavesReverb)
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::NDQueryInterface
//
// Subclass can override if it wants to implement more interfaces.
//
STDMETHODIMP CDirectSoundWavesReverbDMO::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_IDirectSoundFXWavesReverb)
{
return GetInterface((IDirectSoundFXWavesReverb*)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);
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::Clone
//
STDMETHODIMP CDirectSoundWavesReverbDMO::Clone(IMediaObjectInPlace **pp)
{
return StandardDMOClone<CDirectSoundWavesReverbDMO, DSFXWavesReverb>(this, pp);
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::CDirectSoundWavesReverbDMO
//
CDirectSoundWavesReverbDMO::CDirectSoundWavesReverbDMO( IUnknown *pUnk, HRESULT *phr )
: CComBase( pUnk, phr ),
m_fDirty(TRUE),
m_pbCoeffs(NULL),
m_plStates(NULL),
m_fInitCPCMDMO(false),
m_pfnSVerbProcess(NULL),
m_fGain(DSFX_WAVESREVERB_INGAIN_DEFAULT),
m_fMix(DSFX_WAVESREVERB_REVERBMIX_DEFAULT),
m_fTime(DSFX_WAVESREVERB_REVERBTIME_DEFAULT),
m_fRatio(DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT)
{
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::~CDirectSoundWavesReverbDMO
//
CDirectSoundWavesReverbDMO::~CDirectSoundWavesReverbDMO()
{
delete[] m_pbCoeffs;
delete[] m_plStates;
}
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
SVP_Gain, MPT_FLOAT, g_capsAll, DSFX_WAVESREVERB_INGAIN_MIN, DSFX_WAVESREVERB_INGAIN_MAX, DSFX_WAVESREVERB_INGAIN_DEFAULT, L"dB", L"InGain", L"",
SVP_Mix, MPT_FLOAT, g_capsAll, DSFX_WAVESREVERB_REVERBMIX_MIN, DSFX_WAVESREVERB_REVERBMIX_MAX, DSFX_WAVESREVERB_REVERBMIX_DEFAULT, L"dB", L"ReverbMix", L"",
SVP_ReverbTime, MPT_FLOAT, g_capsAll, DSFX_WAVESREVERB_REVERBTIME_MIN, DSFX_WAVESREVERB_REVERBTIME_MAX, DSFX_WAVESREVERB_REVERBTIME_DEFAULT, L"ms", L"ReverbTime", L"",
SVP_Ratio, MPT_FLOAT, g_capsAll, DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN, DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX, DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT, L"", L"HighFreqRTRatio", L"",
};
HRESULT CDirectSoundWavesReverbDMO::InitOnCreation()
{
HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
return hr;
}
HRESULT CDirectSoundWavesReverbDMO::Init()
{
HRESULT hr = S_OK;
DMO_MEDIA_TYPE *pmt = InputType();
if (pmt->majortype != MEDIATYPE_Audio ||
pmt->subtype != MEDIASUBTYPE_PCM ||
pmt->formattype != FORMAT_WaveFormatEx)
{
hr = E_INVALIDARG;
TraceI(1,"ERROR: Invalid Format specified during SetInputType()\n");
}
WAVEFORMATEX *pwfex = (WAVEFORMATEX*)pmt->pbFormat;
if (SUCCEEDED(hr))
{
if (pwfex->wFormatTag != WAVE_FORMAT_PCM ||
pwfex->wBitsPerSample != 16)
{
hr = E_INVALIDARG;
TraceI(1,"ERROR: Invalid Format specified during SetInputType()\n");
}
}
if (SUCCEEDED(hr))
{
switch (pwfex->nChannels)
{
case 1:
m_pfnSVerbProcess = SVerbMonoToMonoShort;
break;
case 2:
m_pfnSVerbProcess = SVerbStereoToStereoShort;
break;
default:
hr = E_FAIL;
TraceI(1,"ERROR: Waves Reverb only supports mono or stereo\n");
}
}
// Formats have been set. Initialize the reverb.
//
m_pbCoeffs = new BYTE[GetCoefsSize()];
m_plStates = new long[(GetStatesSize() + sizeof(long) - 1)/ sizeof(long)];
if (m_pbCoeffs == NULL || m_plStates == NULL)
{
hr = E_OUTOFMEMORY;
TraceI(1,"ERROR: Out of memory\n");
}
if (SUCCEEDED(hr))
{
memset(m_plStates, 0, GetStatesSize());
InitSVerb((float)m_ulSamplingRate, m_pbCoeffs);
InitSVerbStates(m_plStates);
m_fInitCPCMDMO = true;
}
Discontinuity();
return hr;
}
HRESULT CDirectSoundWavesReverbDMO::Discontinuity()
{
HRESULT hr;
DSFXWavesReverb wavesreverb;
if (m_pbCoeffs && m_plStates)
{
memset(m_plStates, 0, GetStatesSize());
InitSVerb((float)m_ulSamplingRate, m_pbCoeffs);
InitSVerbStates(m_plStates);
}
hr = GetAllParameters(&wavesreverb);
if (SUCCEEDED(hr))
{
hr = SetAllParameters(&wavesreverb);
}
if (SUCCEEDED(hr))
{
UpdateCoefficients();
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::FBRProcess
//
HRESULT CDirectSoundWavesReverbDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut)
{
assert(m_pfnSVerbProcess);
(*m_pfnSVerbProcess)(
cSamples,
(short*)pIn,
(short*)pOut,
m_pbCoeffs,
m_plStates);
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::ProcessInPlace
//
HRESULT CDirectSoundWavesReverbDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags)
{
// Update parameter values from any curves that may be in effect.
if (this->GetActiveParamBits())
{
this->UpdateActiveParams(rtStart, *this);
this->UpdateCoefficients();
}
return FBRProcess(ulQuanta, pcbData, pcbData);
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::SetParam
//
STDMETHODIMP CDirectSoundWavesReverbDMO::SetParam(DWORD dwParamIndex,MP_DATA value)
{
HRESULT hr = SetParamInternal(dwParamIndex, value, false);
if (SUCCEEDED(hr))
this->UpdateCoefficients();
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::SetParamInternal
//
HRESULT CDirectSoundWavesReverbDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
{
switch (dwParamIndex)
{
case SVP_Gain:
CHECK_PARAM(DSFX_WAVESREVERB_INGAIN_MIN, DSFX_WAVESREVERB_INGAIN_MAX);
m_fGain = value;
break;
case SVP_Mix:
CHECK_PARAM(DSFX_WAVESREVERB_REVERBMIX_MIN,DSFX_WAVESREVERB_REVERBMIX_MAX);
m_fMix = value;
break;
case SVP_ReverbTime:
CHECK_PARAM(DSFX_WAVESREVERB_REVERBTIME_MIN,DSFX_WAVESREVERB_REVERBTIME_MAX);
m_fTime = value;
break;
case SVP_Ratio:
CHECK_PARAM(DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN,DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX);
m_fRatio = value;
break;
default:
return E_FAIL;
}
// Let base class set this so it can handle all the rest of the param calls
//
HRESULT hr = fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
return hr;
}
void CDirectSoundWavesReverbDMO::UpdateCoefficients()
{
// Waves Reverb has a single SetSVerb call that updates all parameters simultaneously instead of internal
// state variables that are updated incrementally by changes to individual parameters as the other DMOs do.
if (m_fInitCPCMDMO)
{
SetSVerb(
m_fGain,
m_fMix,
m_fTime,
m_fRatio,
m_pbCoeffs);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::SetAllParameters
//
STDMETHODIMP CDirectSoundWavesReverbDMO::SetAllParameters(THIS_ LPCDSFXWavesReverb pwr)
{
HRESULT hr = S_OK;
// Check that the pointer is not NULL
if (pwr == NULL)
{
TraceI(1,"ERROR: pwr is NULL\n");
hr = E_POINTER;
}
// Set the parameters
if (SUCCEEDED(hr)) hr = SetParamInternal(SVP_Gain, pwr->fInGain, false);
if (SUCCEEDED(hr)) hr = SetParamInternal(SVP_Mix, pwr->fReverbMix, false);
if (SUCCEEDED(hr)) hr = SetParamInternal(SVP_ReverbTime, pwr->fReverbTime, false);
if (SUCCEEDED(hr)) hr = SetParamInternal(SVP_Ratio, pwr->fHighFreqRTRatio, false);
this->UpdateCoefficients();
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//
// CDirectSoundWavesReverbDMO::GetAllParameters
//
HRESULT CDirectSoundWavesReverbDMO::GetAllParameters(THIS_ LPDSFXWavesReverb pwr)
{
HRESULT hr = S_OK;
MP_DATA mpd;
if (pwr == NULL) return E_POINTER;
#define GET_PARAM(x,y) \
if (SUCCEEDED(hr)) { \
hr = GetParam(x, &mpd); \
if (SUCCEEDED(hr)) pwr->y = mpd; \
}
#define GET_PARAM_LONG(x,y) \
if (SUCCEEDED(hr)) { \
hr = GetParam(x, &mpd); \
if (SUCCEEDED(hr)) pwr->y = (long)mpd; \
}
GET_PARAM(SVP_Gain, fInGain);
GET_PARAM(SVP_Mix, fReverbMix);
GET_PARAM(SVP_ReverbTime, fReverbTime);
GET_PARAM(SVP_Ratio, fHighFreqRTRatio);
return S_OK;
}
HRESULT CDirectSoundWavesReverbDMO::CheckInputType(const DMO_MEDIA_TYPE *pmt)
{
if (NULL == pmt) {
return E_POINTER;
}
// Verify that this is PCM with a WAVEFORMATEX format specifier
if ((pmt->majortype != MEDIATYPE_Audio) ||
(pmt->subtype != MEDIASUBTYPE_PCM) ||
(pmt->formattype != FORMAT_WaveFormatEx) ||
(pmt->cbFormat < sizeof(WAVEFORMATEX)) ||
(pmt->pbFormat == NULL))
return DMO_E_TYPE_NOT_ACCEPTED;
// Verify the wave format
WAVEFORMATEX *pWave = (WAVEFORMATEX*)pmt->pbFormat;
if (pWave->wFormatTag != WAVE_FORMAT_PCM ||
pWave->wBitsPerSample != 16 ||
pWave->nChannels != 1 && pWave->nChannels != 2)
{
return DMO_E_TYPE_NOT_ACCEPTED;
}
return NOERROR;
}
// 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 CDirectSoundWavesReverbDMO::GetClassID(CLSID *pClsid)
{
if (pClsid==NULL) {
return E_POINTER;
}
*pClsid = GUID_DSFX_WAVES_REVERB;
return NOERROR;
} // GetClassID