Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

489 lines
12 KiB

  1. #include <windows.h>
  2. #include "parameqp.h"
  3. #include "clone.h"
  4. STD_CREATE(ParamEq)
  5. //////////////////////////////////////////////////////////////////////////////
  6. //
  7. // CDirectSoundParamEqDMO::QueryInterface
  8. //
  9. // Subclass can override if it wants to implement more interfaces.
  10. //
  11. STDMETHODIMP CDirectSoundParamEqDMO::NDQueryInterface(THIS_ REFIID riid, LPVOID *ppv)
  12. {
  13. IMP_DSDMO_QI(riid,ppv);
  14. if (riid == IID_IPersist)
  15. {
  16. return GetInterface((IPersist*)this, ppv);
  17. }
  18. else if (riid == IID_IMediaObject)
  19. {
  20. return GetInterface((IMediaObject*)this, ppv);
  21. }
  22. else if (riid == IID_IDirectSoundFXParamEq)
  23. {
  24. return GetInterface((IDirectSoundFXParamEq*)this, ppv);
  25. }
  26. else if (riid == IID_ISpecifyPropertyPages)
  27. {
  28. return GetInterface((ISpecifyPropertyPages*)this, ppv);
  29. }
  30. else if (riid == IID_IMediaParams)
  31. {
  32. return GetInterface((IMediaParams*)this, ppv);
  33. }
  34. else if (riid == IID_IMediaParamInfo)
  35. {
  36. return GetInterface((IMediaParamInfo*)this, ppv);
  37. }
  38. else
  39. return CComBase::NDQueryInterface(riid, ppv);
  40. }
  41. //////////////////////////////////////////////////////////////////////////////
  42. //
  43. // CDirectSoundParamEqDMO::CDirectSoundParamEqDMO
  44. //
  45. CDirectSoundParamEqDMO::CDirectSoundParamEqDMO( IUnknown * pUnk, HRESULT *phr )
  46. : CComBase( pUnk, phr ),
  47. m_fDirty(TRUE)
  48. // { EAX: put init data here if any (otherwise use Discontinuity).
  49. // } EAX
  50. {
  51. m_EaxSamplesPerSec = 48000;
  52. }
  53. //////////////////////////////////////////////////////////////////////////////
  54. //
  55. // CDirectSoundParamEqDMO::Init()
  56. //
  57. HRESULT CDirectSoundParamEqDMO::Init()
  58. {
  59. DSFXParamEq param;
  60. // Force recalc of all internal parameters
  61. //
  62. GetAllParameters(&param);
  63. SetAllParameters(&param);
  64. return Discontinuity();
  65. }
  66. 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;
  67. static ParamInfo g_params[] =
  68. {
  69. // index type caps min, max, neutral, unit text, label, pwchText
  70. PFP_Center, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_CENTER_MIN, DSFXPARAMEQ_CENTER_MAX, 8000, L"", L"Center", L"",
  71. PFP_Bandwidth, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_BANDWIDTH_MIN, DSFXPARAMEQ_BANDWIDTH_MAX, 12, L"", L"Bandwidth", L"",
  72. PFP_Gain, MPT_FLOAT, g_capsAll, DSFXPARAMEQ_GAIN_MIN, DSFXPARAMEQ_GAIN_MAX, 0, L"", L"Gain", L"",
  73. };
  74. HRESULT CDirectSoundParamEqDMO::InitOnCreation()
  75. {
  76. HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
  77. return hr;
  78. }
  79. //////////////////////////////////////////////////////////////////////////////
  80. //
  81. // CDirectSoundParamEqDMO::~CDirectSoundParamEqDMO
  82. //
  83. CDirectSoundParamEqDMO::~CDirectSoundParamEqDMO()
  84. {
  85. }
  86. //////////////////////////////////////////////////////////////////////////////
  87. //
  88. // CDirectSoundParamEqDMO::Clone
  89. //
  90. STDMETHODIMP CDirectSoundParamEqDMO::Clone(IMediaObjectInPlace **pp)
  91. {
  92. return StandardDMOClone<CDirectSoundParamEqDMO, DSFXParamEq>(this, pp);
  93. }
  94. //
  95. // Bump - bump the delay pointers.
  96. //
  97. void CDirectSoundParamEqDMO::Bump(void)
  98. {
  99. // EAX {
  100. // }
  101. }
  102. HRESULT CDirectSoundParamEqDMO::Discontinuity()
  103. {
  104. // { EAX
  105. m_delayL1 = m_delayL2 = m_delayR1 = m_delayR2 = 0;
  106. // } EAX
  107. return S_OK;
  108. }
  109. //////////////////////////////////////////////////////////////////////////////
  110. __forceinline void CDirectSoundParamEqDMO::DoOneSampleMono(int *l)
  111. {
  112. float inPortL = (float)*l;
  113. float outPortL, temp1, temp2, temp3;
  114. temp1 = inPortL / 4;
  115. // 2nd Order Ladder All Pass: Zeros first version
  116. temp3 = m_delayL2 + temp1 * m_EaxApA;
  117. temp2 = temp1 - temp3 * m_EaxApA;
  118. m_delayL2 = m_delayL1 + temp2 * m_EaxApB;
  119. m_delayL1 = temp2 - m_delayL2 * m_EaxApB;
  120. // Regalia Mitra Structure
  121. temp3 = temp3 * m_EaxGainCoefA;
  122. temp3 = temp3 + temp1 * m_EaxGainCoefB;
  123. outPortL = m_EaxScale * temp3;
  124. *l = Saturate(outPortL);
  125. // Bump();
  126. }
  127. //////////////////////////////////////////////////////////////////////////////
  128. __forceinline void CDirectSoundParamEqDMO::DoOneSample(int *l, int *r)
  129. {
  130. float inPortL = (float)*l;
  131. float inPortR = (float)*r;
  132. float outPortL, outPortR, temp1, temp2, temp3;
  133. temp1 = inPortL / 4;
  134. // 2nd Order Ladder All Pass: Zeros first version
  135. temp3 = m_delayL2 + temp1 * m_EaxApA;
  136. temp2 = temp1 - temp3 * m_EaxApA;
  137. m_delayL2 = m_delayL1 + temp2 * m_EaxApB;
  138. m_delayL1 = temp2 - m_delayL2 * m_EaxApB;
  139. // Regalia Mitra Structure
  140. temp3 = temp3 * m_EaxGainCoefA;
  141. temp3 = temp3 + temp1 * m_EaxGainCoefB;
  142. outPortL = m_EaxScale * temp3;
  143. *l = Saturate(outPortL);
  144. temp1 = inPortR / 4;
  145. // 2nd Order Ladder All Pass: Zeros first version
  146. temp3 = m_delayR2 + temp1 * m_EaxApA;
  147. temp2 = temp1 - temp3 * m_EaxApA;
  148. m_delayR2 = m_delayR1 + temp2 * m_EaxApB;
  149. m_delayR1 = temp2 - m_delayR2 * m_EaxApB;
  150. // Regalia Mitra Structure
  151. temp3 = temp3 * m_EaxGainCoefA;
  152. temp3 = temp3 + temp1 * m_EaxGainCoefB;
  153. outPortR = m_EaxScale * temp3;
  154. *r = Saturate(outPortR);
  155. // Bump();
  156. }
  157. //////////////////////////////////////////////////////////////////////////////
  158. //
  159. // CDirectSoundParamEqDMO::FBRProcess
  160. //
  161. HRESULT CDirectSoundParamEqDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut)
  162. {
  163. // { EAX
  164. #define cb cSamples
  165. #define pin pIn
  166. #define pout pOut
  167. if (m_cChannels == 1) {
  168. if (m_b8bit) {
  169. for (;cb > 0; --cb) {
  170. int i, j;
  171. i = *(pin+0)-128;
  172. i *=256;
  173. // j = i;
  174. DoOneSampleMono(&i);
  175. // i += j;
  176. // i /= 2;
  177. i /= 256;
  178. *(pout+0) = (unsigned char)(i + 128);
  179. pin += sizeof(unsigned char);
  180. pout += sizeof(unsigned char);
  181. }
  182. }
  183. else if (!m_b8bit) {
  184. for (;cb > 0; --cb) { // for (;cb > 0; cb -= sizeof(short)) {
  185. short int *psi = (short int *)pin;
  186. short int *pso = (short int *)pout;
  187. int i, j;
  188. i = *psi;
  189. // j = i;
  190. DoOneSampleMono(&i);
  191. // i += j;
  192. // i /= 2;
  193. *pso = (short)i;
  194. pin += sizeof(short);
  195. pout += sizeof(short);
  196. }
  197. }
  198. }
  199. else if (m_cChannels == 2) {
  200. if (m_b8bit) {
  201. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(unsigned char)) {
  202. int i, j;
  203. i = *(pin+0)-128;
  204. j = *(pin+1)-128;
  205. i *=256; j *=256;
  206. DoOneSample(&i, &j);
  207. i /= 256; j /= 256;
  208. *(pout+0) = (unsigned char)(i + 128);
  209. *(pout+1) = (unsigned char)(j + 128);
  210. pin += 2 * sizeof(unsigned char);
  211. pout += 2 * sizeof(unsigned char);
  212. }
  213. }
  214. else if (!m_b8bit) {
  215. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(short)) {
  216. short int *psi = (short int *)pin;
  217. short int *pso = (short int *)pout;
  218. int i, j;
  219. i = *(psi+0);
  220. j = *(psi+1);
  221. DoOneSample(&i, &j);
  222. *(pso+0) = (short)i;
  223. *(pso+1) = (short)j;
  224. pin += 2 * sizeof(short);
  225. pout += 2 * sizeof(short);
  226. }
  227. }
  228. }
  229. // } EAX
  230. return S_OK;
  231. }
  232. //////////////////////////////////////////////////////////////////////////////
  233. //
  234. // CDirectSoundParamEqDMO::ProcessInPlace
  235. //
  236. HRESULT CDirectSoundParamEqDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags)
  237. {
  238. HRESULT hr=S_OK;
  239. // Update parameter values from any curves that may be in effect.
  240. this->UpdateActiveParams(rtStart, *this);
  241. hr = FBRProcess(ulQuanta, pcbData, pcbData);
  242. return hr;
  243. }
  244. //////////////////////////////////////////////////////////////////////////////
  245. //
  246. // CDirectSoundParamEqDMO::SetParam
  247. //
  248. // { EAX
  249. // }
  250. void CDirectSoundParamEqDMO::UpdateCoefficients(void)
  251. {
  252. float _gain, _omega, _lambda, _sinX;
  253. //Calculate linear gain coefficient
  254. _gain = (float)pow(10, m_EaxGain/20);
  255. if (!_gain) _gain = (float).00001;
  256. m_EaxGainCoefA = (1 - _gain)/2;
  257. m_EaxGainCoefB = (1 + _gain)/2;
  258. //Calculate scaling coefficient
  259. m_EaxScale = (float)((fabs(m_EaxGainCoefA) > fabs(m_EaxGainCoefB)) ? fabs(m_EaxGainCoefA) : fabs(m_EaxGainCoefB));
  260. m_EaxScale = (float)(m_EaxScale > 1 ? ceil(m_EaxScale) : 1);
  261. m_EaxGainCoefA /= m_EaxScale;
  262. m_EaxGainCoefB /= m_EaxScale;
  263. m_EaxScale = m_EaxScale * 4;
  264. //Calculate allpass coefficients
  265. _omega = (float)(2*PI*m_EaxCenter/m_EaxSamplesPerSec);
  266. _sinX = (float)sin(_omega);
  267. // if (!_sinX) _sinX = (float).000001;
  268. _lambda = (float)(sinh(.5 * log(2) * m_EaxBandwidth/12 * _omega/_sinX) * sin(_omega));
  269. m_EaxApA = (float)((1 - (_lambda/sqrt(_gain))) / (1 + (_lambda/sqrt(_gain))));
  270. m_EaxApB = (float)(-cos(_omega));
  271. }
  272. HRESULT CDirectSoundParamEqDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
  273. {
  274. HRESULT hr = S_OK;
  275. HRESULT hr2 = S_OK;
  276. switch (dwParamIndex)
  277. {
  278. // { EAX
  279. case PFP_Center :
  280. CHECK_PARAM(DSFXPARAMEQ_CENTER_MIN, DSFXPARAMEQ_CENTER_MAX);
  281. //if we are greater than 1/3rd the samplig rate then we need to S_FALSE;
  282. if (value > (m_EaxSamplesPerSec/3))
  283. {
  284. hr = S_FALSE;
  285. value = static_cast<MP_DATA>(m_EaxSamplesPerSec/3);
  286. }
  287. PUT_EAX_VALUE(Center, value);
  288. UpdateCoefficients();
  289. break;
  290. case PFP_Bandwidth :
  291. CHECK_PARAM(DSFXPARAMEQ_BANDWIDTH_MIN, DSFXPARAMEQ_BANDWIDTH_MAX);
  292. PUT_EAX_VALUE(Bandwidth, value);
  293. UpdateCoefficients();
  294. break;
  295. case PFP_Gain : {
  296. CHECK_PARAM(DSFXPARAMEQ_GAIN_MIN, DSFXPARAMEQ_GAIN_MAX);
  297. PUT_EAX_VALUE(Gain, value);
  298. UpdateCoefficients();
  299. break;
  300. }
  301. // } EAX
  302. default:
  303. return E_FAIL;
  304. }
  305. // Let base class set this so it can handle all the rest of the param calls.
  306. // Skip the base class if fSkipPasssingToParamManager. This indicates that we're calling the function
  307. // internally using valuds that came from the base class -- thus there's no need to tell it values it
  308. // already knows.
  309. hr2 = fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
  310. if(FAILED(hr2))
  311. {
  312. hr = hr2;
  313. }
  314. return hr;
  315. }
  316. //////////////////////////////////////////////////////////////////////////////
  317. //
  318. // CDirectSoundParamEqDMO::SetAllParameters
  319. //
  320. STDMETHODIMP CDirectSoundParamEqDMO::SetAllParameters(LPCDSFXParamEq peq)
  321. {
  322. HRESULT hr = S_OK;
  323. HRESULT hr2[3];
  324. ZeroMemory(hr2,sizeof(hr2));
  325. // Check that the pointer is not NULL
  326. if (peq == NULL)
  327. {
  328. Trace(1,"ERROR: peq is NULL\n");
  329. hr = E_POINTER;
  330. }
  331. // Set the parameters
  332. if (SUCCEEDED(hr)) hr = hr2[0] = SetParam(PFP_Center, peq->fCenter);
  333. if (SUCCEEDED(hr)) hr = hr2[1] = SetParam(PFP_Bandwidth, peq->fBandwidth);
  334. if (SUCCEEDED(hr)) hr = hr2[2] = SetParam(PFP_Gain, peq->fGain);
  335. // if we have any alternate success codes, grab the first one and return it.
  336. if(SUCCEEDED(hr))
  337. {
  338. for (int i = 0;i < 3; i++)
  339. {
  340. if (hr2[i] != S_OK)
  341. {
  342. hr = hr2[i];
  343. break;
  344. }
  345. }
  346. }
  347. m_fDirty = true;
  348. return hr;
  349. }
  350. //////////////////////////////////////////////////////////////////////////////
  351. //
  352. // CDirectSoundParamEqDMO::GetAllParameters
  353. //
  354. STDMETHODIMP CDirectSoundParamEqDMO::GetAllParameters(LPDSFXParamEq peq)
  355. {
  356. HRESULT hr = S_OK;
  357. MP_DATA mpd;
  358. if (peq ==NULL) return E_POINTER;
  359. #define GET_PARAM(x,y) \
  360. if (SUCCEEDED(hr)) { \
  361. hr = GetParam(x, &mpd); \
  362. if (SUCCEEDED(hr)) peq->y = mpd; \
  363. }
  364. GET_PARAM(PFP_Center, fCenter);
  365. GET_PARAM(PFP_Bandwidth, fBandwidth);
  366. GET_PARAM(PFP_Gain, fGain);
  367. return hr;
  368. }
  369. // GetClassID
  370. //
  371. // Part of the persistent file support. We must supply our class id
  372. // which can be saved in a graph file and used on loading a graph with
  373. // this fx in it to instantiate this filter via CoCreateInstance.
  374. //
  375. HRESULT CDirectSoundParamEqDMO::GetClassID(CLSID *pClsid)
  376. {
  377. if (pClsid==NULL) {
  378. return E_POINTER;
  379. }
  380. *pClsid = GUID_DSFX_STANDARD_PARAMEQ;
  381. return NOERROR;
  382. } // GetClassID