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.

645 lines
18 KiB

  1. #include <windows.h>
  2. #include "flangerp.h"
  3. #include "clone.h"
  4. STD_CREATE(Flanger)
  5. //////////////////////////////////////////////////////////////////////////////
  6. //
  7. // CDirectSoundFlangerDMO::NDQueryInterface
  8. //
  9. // Subclass can override if it wants to implement more interfaces.
  10. //
  11. STDMETHODIMP CDirectSoundFlangerDMO::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_IDirectSoundFXFlanger)
  23. {
  24. return GetInterface((IDirectSoundFXFlanger*)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. // CDirectSoundFlangerDMO::CDirectSoundFlangerDMO
  44. //
  45. CDirectSoundFlangerDMO::CDirectSoundFlangerDMO( IUnknown *pUnk, HRESULT *phr )
  46. : CComBase( pUnk, phr ),
  47. m_fDirty(false)
  48. // { EAX: put init data here if any (otherwise use Discontinuity).
  49. // } EAX
  50. {
  51. m_EaxSamplesPerSec = 22050;
  52. m_DelayL .Init(0);
  53. m_DelayR .Init(0);
  54. m_DryDelayL.Init(0);
  55. m_DryDelayR.Init(0);
  56. }
  57. //////////////////////////////////////////////////////////////////////////////
  58. //
  59. // CDirectSoundFlangerDMO::Init()
  60. //
  61. HRESULT CDirectSoundFlangerDMO::Init()
  62. {
  63. DSFXFlanger flanger;
  64. HRESULT hr;
  65. // Force recalc of all internal parameters
  66. //
  67. hr = GetAllParameters(&flanger);
  68. if (SUCCEEDED(hr)) hr = SetAllParameters(&flanger);
  69. if (SUCCEEDED(hr)) hr = m_DelayL .Init(m_EaxSamplesPerSec);
  70. if (SUCCEEDED(hr)) hr = m_DelayR .Init(m_EaxSamplesPerSec);
  71. if (SUCCEEDED(hr)) hr = m_DryDelayL.Init(m_EaxSamplesPerSec);
  72. if (SUCCEEDED(hr)) hr = m_DryDelayR.Init(m_EaxSamplesPerSec);
  73. if (SUCCEEDED(hr)) hr = Discontinuity();
  74. return hr;
  75. }
  76. // �� bugbug on dsdmo.h: FilterParams should be FlangerFilterParams and need DSFXFLANGER_WAVE_TRIANGLE/DSFXFLANGER_WAVE_SIN
  77. 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;
  78. static ParamInfo g_params[] =
  79. {
  80. // index type caps min, max, neutral, unit text, label, pwchText
  81. FFP_Wetdrymix, MPT_FLOAT, g_capsAll, DSFXFLANGER_WETDRYMIX_MIN, DSFXFLANGER_WETDRYMIX_MAX, 50, L"%", L"WetDryMix", L"",
  82. FFP_Depth, MPT_FLOAT, g_capsAll, DSFXFLANGER_DEPTH_MIN, DSFXFLANGER_DEPTH_MAX, 100, L"", L"Depth", L"",
  83. FFP_Frequency, MPT_FLOAT, g_capsAll, DSFXFLANGER_FREQUENCY_MIN, DSFXFLANGER_FREQUENCY_MAX, (float).25, L"Hz", L"Frequency", L"",
  84. FFP_Waveform, MPT_ENUM, g_capsAll, DSFXCHORUS_WAVE_TRIANGLE, DSFXCHORUS_WAVE_SIN, DSFXCHORUS_WAVE_SIN, L"", L"WaveShape", L"Triangle,Sine",
  85. FFP_Phase, MPT_INT, g_capsAll, DSFXFLANGER_PHASE_MIN, DSFXFLANGER_PHASE_MAX, 2, L"", L"Phase", L"",
  86. FFP_Feedback, MPT_FLOAT, g_capsAll, DSFXFLANGER_FEEDBACK_MIN, DSFXFLANGER_FEEDBACK_MAX, -50, L"", L"Feedback", L"",
  87. FFP_Delay, MPT_FLOAT, g_capsAll, DSFXFLANGER_DELAY_MIN, DSFXFLANGER_DELAY_MAX, 2, L"", L"Delay", L"",
  88. };
  89. HRESULT CDirectSoundFlangerDMO::InitOnCreation()
  90. {
  91. HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
  92. m_ModdelayL = m_ModdelayR = 0;
  93. m_ModdelayL1 = m_ModdelayR1 = 0x800;
  94. return hr;
  95. }
  96. //////////////////////////////////////////////////////////////////////////////
  97. //
  98. // CDirectSoundFlangerDMO::~CDirectSoundFlangerDMO
  99. //
  100. CDirectSoundFlangerDMO::~CDirectSoundFlangerDMO()
  101. {
  102. m_DelayL .Init(-1);
  103. m_DelayR .Init(-1);
  104. m_DryDelayL.Init(-1);
  105. m_DryDelayR.Init(-1);
  106. }
  107. //////////////////////////////////////////////////////////////////////////////
  108. //
  109. // CDirectSoundFlangerDMO::Clone
  110. //
  111. STDMETHODIMP CDirectSoundFlangerDMO::Clone(IMediaObjectInPlace **pp)
  112. {
  113. return StandardDMOClone<CDirectSoundFlangerDMO, DSFXFlanger>(this, pp);
  114. }
  115. //
  116. // Bump - bump the delay pointers.
  117. //
  118. void CDirectSoundFlangerDMO::Bump(void)
  119. {
  120. // EAX {
  121. m_DelayL.Bump();
  122. m_DelayR.Bump();
  123. m_DryDelayL.Bump();
  124. m_DryDelayR.Bump();
  125. // }
  126. }
  127. HRESULT CDirectSoundFlangerDMO::Discontinuity()
  128. {
  129. // { EAX
  130. m_DelayL .ZeroBuffer();
  131. m_DelayR .ZeroBuffer();
  132. m_DryDelayL.ZeroBuffer();
  133. m_DryDelayR.ZeroBuffer();
  134. // These values have defined initial values.
  135. // m_FixedptrL = m_DelayL.LastPos(0) * FractMultiplier;
  136. m_DelayptrL = m_ModdelayL1 = m_ModdelayL = (int)m_EaxFixedptrL;
  137. // m_FixedptrR = m_DelayR.LastPos(0) * FractMultiplier;
  138. m_DelayptrR = m_ModdelayR1 = m_ModdelayR = (int)m_EaxFixedptrR;
  139. if (!m_EaxWaveform) {
  140. m_LfoState[0] = (float)0.0;
  141. m_LfoState[1] = (float)0.5;
  142. }
  143. else {
  144. m_LfoState[0] = (float)0.0;
  145. m_LfoState[1] = (float)0.99999999999;
  146. }
  147. // } EAX
  148. return S_OK;
  149. }
  150. //////////////////////////////////////////////////////////////////////////////
  151. static int LMul [5] = { 1, 1, 1, 1, -1};
  152. static int RMul [5] = { -1, -1, 1, 1, 1};
  153. static int RPhase[5] = { 0, 1, 0, 1, 0};
  154. __forceinline void CDirectSoundFlangerDMO::DoOneSample(int *l, int *r)
  155. {
  156. float inPortL = (float)*l;
  157. float inPortR = (float)*r;
  158. float XWave[2];
  159. #define sinwave XWave[0]
  160. #define coswave XWave[1]
  161. int Pos0, PosX, tempvar;
  162. float val;
  163. // dryDelayL[] = inPortL;
  164. Pos0 = m_DryDelayL.Pos(0);
  165. m_DryDelayL[Pos0] = inPortL;
  166. // delayL[] = ACC + delayL[fixedptrL] * fbcoef;
  167. Pos0 = m_DelayL.Pos(0);
  168. PosX = m_DelayL.Pos(m_EaxFixedptrL);
  169. m_DelayL[Pos0] = inPortL + m_DelayL[PosX] * m_EaxFbCoef;
  170. // dryDelayR[] = inPortR;
  171. Pos0 = m_DryDelayR.Pos(0);
  172. m_DryDelayR[Pos0] = inPortR;
  173. // delayR[] = ACC + delayR[fixedptrR] * fbcoef;
  174. Pos0 = m_DelayR.Pos(0);
  175. PosX = m_DelayR.Pos(m_EaxFixedptrR);
  176. m_DelayR[Pos0] = inPortR + m_DelayR[PosX] * m_EaxFbCoef;
  177. // Sinusoid : lfocoef = 2*sin(PI*f/FS) // ??? Update this when form changes.
  178. if (!m_EaxWaveform) {
  179. m_LfoState[0] = m_LfoState[0] + m_EaxLfoCoef;
  180. if (m_LfoState[0] > 1) m_LfoState[0] -= 2;
  181. m_LfoState[1] = m_LfoState[1] + m_EaxLfoCoef;
  182. if (m_LfoState[1] > 1) m_LfoState[1] -= 2;
  183. sinwave = (float)fabs(m_LfoState[0]);
  184. coswave = (float)fabs(m_LfoState[1]);
  185. sinwave = -1 + 2 * sinwave;
  186. coswave = -1 + 2 * coswave;
  187. }
  188. else {
  189. m_LfoState[0] = m_LfoState[0] + m_EaxLfoCoef * m_LfoState[1];
  190. m_LfoState[1] = m_LfoState[1] - m_EaxLfoCoef * m_LfoState[0];
  191. sinwave = m_LfoState[0];
  192. coswave = m_LfoState[1];
  193. }
  194. // Left Out
  195. // tempvar ^= delayptrL << 20;
  196. tempvar = m_DelayptrL & FractMask;
  197. // tempvar = tempvar : delayL[moddelayL] < delayL[moddelayL1];
  198. Pos0 = m_DelayL.Pos(m_ModdelayL);
  199. PosX = m_DelayL.Pos(m_ModdelayL1);
  200. val = ((float)tempvar) / FractMultiplier;
  201. val = Interpolate(m_DelayL[Pos0], m_DelayL[PosX], val);
  202. // outPortL = wetlevel : dryDelayL[2] < tempvar;
  203. Pos0 = m_DryDelayL.FractPos(2);
  204. val = Interpolate(m_DryDelayL[Pos0], val, m_EaxWetlevel);
  205. *l = Saturate(val);
  206. // Right Out
  207. // tempvar ^= delayptrR << 20;
  208. tempvar = m_DelayptrR & FractMask;
  209. // tempvar = tempvar : delayR[moddelayR] < delayR[moddelayR1];
  210. Pos0 = m_DelayR.Pos(m_ModdelayR);
  211. PosX = m_DelayR.Pos(m_ModdelayR1);
  212. val = ((float)tempvar) / FractMultiplier;
  213. val = Interpolate(m_DelayR[Pos0], m_DelayR[PosX], val);
  214. // outPortR = wetlevel : dryDelayR[2] < tempvar;
  215. Pos0 = m_DryDelayR.FractPos(2);
  216. val = Interpolate(m_DryDelayR[Pos0], val, m_EaxWetlevel);
  217. *r = Saturate(val);
  218. // Left Delay Address Calculation
  219. // Same as efx...
  220. // m_DelayptrL = (int)(m_EaxFixedptrL + (sinwave * m_EaxDepthCoef));
  221. #if 0
  222. switch (m_EaxPhase) {
  223. case 0:
  224. case 1:
  225. case 2:
  226. case 3: m_DelayptrL = (int)(sinwave * m_EaxDepthCoef); break;
  227. case 4: m_DelayptrL = - (int)(sinwave * m_EaxDepthCoef); break;
  228. }
  229. #else
  230. #ifdef DONTUSEi386
  231. {
  232. int x;
  233. float f = (sinwave * m_EaxDepthCoef);
  234. _asm {
  235. fld f
  236. fistp x
  237. }
  238. m_DelayptrL = LMul[m_EaxPhase] * x;
  239. }
  240. #else
  241. m_DelayptrL = LMul[m_EaxPhase] * (int)(sinwave * m_EaxDepthCoef);
  242. #endif
  243. #endif
  244. m_DelayptrL += m_EaxFixedptrL;
  245. m_ModdelayL = m_DelayptrL;
  246. m_ModdelayL1 = m_DelayptrL + FractMultiplier;
  247. // Right Delay Address Calculation
  248. // m_DelayptrR = (int)(m_EaxFixedptrR + (coswave * m_EaxDepthCoef));
  249. #if 0
  250. switch (m_EaxPhase) {
  251. case 0: m_DelayptrR = - (int)(sinwave * m_EaxDepthCoef); break;
  252. case 1: m_DelayptrR = - (int)(coswave * m_EaxDepthCoef); break;
  253. case 3: m_DelayptrR = (int)(coswave * m_EaxDepthCoef); break;
  254. case 2:
  255. case 4: m_DelayptrR = (int)(sinwave * m_EaxDepthCoef); break;
  256. }
  257. #else
  258. Pos0 = RPhase[m_EaxPhase];
  259. #ifdef DONTUSEi386
  260. {
  261. int x;
  262. float f = (XWave[Pos0] * m_EaxDepthCoef);
  263. _asm {
  264. fld f
  265. fistp x
  266. }
  267. m_DelayptrR = RMul [m_EaxPhase] * x;
  268. }
  269. #else
  270. m_DelayptrR = RMul [m_EaxPhase] * (int)(XWave[Pos0] * m_EaxDepthCoef);
  271. #endif
  272. #endif
  273. m_DelayptrR += m_EaxFixedptrR;
  274. m_ModdelayR = m_DelayptrR;
  275. m_ModdelayR1 = m_DelayptrR + FractMultiplier;
  276. Bump();
  277. }
  278. //////////////////////////////////////////////////////////////////////////////
  279. //
  280. // CDirectSoundFlangerDMO::FBRProcess
  281. //
  282. HRESULT CDirectSoundFlangerDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut)
  283. {
  284. // { EAX
  285. #define cb cSamples
  286. #define pin pIn
  287. #define pout pOut
  288. if (m_cChannels == 1) {
  289. if (m_b8bit) {
  290. for (;cb > 0; --cb) {
  291. int i, j;
  292. i = *(pin+0)-128;
  293. i *=256;
  294. j = i;
  295. DoOneSample(&i, &j);
  296. i += j;
  297. i /= 2;
  298. i /= 256;
  299. *(pout+0) = (unsigned char)(i + 128);
  300. pin += sizeof(unsigned char);
  301. pout += sizeof(unsigned char);
  302. }
  303. }
  304. else if (!m_b8bit) {
  305. for (;cb > 0; --cb) { // for (;cb > 0; cb -= sizeof(short)) {
  306. short int *psi = (short int *)pin;
  307. short int *pso = (short int *)pout;
  308. int i, j;
  309. i = *psi;
  310. j = i;
  311. DoOneSample(&i, &j);
  312. i += j;
  313. i /= 2;
  314. *pso = (short)i;
  315. pin += sizeof(short);
  316. pout += sizeof(short);
  317. }
  318. }
  319. }
  320. else if (m_cChannels == 2) {
  321. if (m_b8bit) {
  322. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(unsigned char)) {
  323. int i, j;
  324. i = *(pin+0)-128;
  325. j = *(pin+1)-128;
  326. i *=256; j *=256;
  327. DoOneSample(&i, &j);
  328. i /= 256; j /= 256;
  329. *(pout+0) = (unsigned char)(i + 128);
  330. *(pout+1) = (unsigned char)(j + 128);
  331. pin += 2 * sizeof(unsigned char);
  332. pout += 2 * sizeof(unsigned char);
  333. }
  334. }
  335. else if (!m_b8bit) {
  336. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(short)) {
  337. short int *psi = (short int *)pin;
  338. short int *pso = (short int *)pout;
  339. int i, j;
  340. i = *(psi+0);
  341. j = *(psi+1);
  342. DoOneSample(&i, &j);
  343. *(pso+0) = (short)i;
  344. *(pso+1) = (short)j;
  345. pin += 2 * sizeof(short);
  346. pout += 2 * sizeof(short);
  347. }
  348. }
  349. }
  350. // } EAX
  351. return S_OK;
  352. }
  353. //////////////////////////////////////////////////////////////////////////////
  354. //
  355. // CDirectSoundFlangerDMO::ProcessInPlace
  356. //
  357. HRESULT CDirectSoundFlangerDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags)
  358. {
  359. // Update parameter values from any curves that may be in effect.
  360. this->UpdateActiveParams(rtStart, *this);
  361. return FBRProcess(ulQuanta, pcbData, pcbData);
  362. }
  363. //////////////////////////////////////////////////////////////////////////////
  364. //
  365. // CDirectSoundFlangerDMO::SetParam
  366. //
  367. // { EAX
  368. // }
  369. HRESULT CDirectSoundFlangerDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
  370. {
  371. long l;
  372. if (!m_EaxSamplesPerSec) return DMO_E_TYPE_NOT_ACCEPTED; // NO TYPE!
  373. switch (dwParamIndex)
  374. {
  375. case FFP_Wetdrymix :
  376. CHECK_PARAM(DSFXFLANGER_WETDRYMIX_MIN, DSFXFLANGER_WETDRYMIX_MAX);
  377. PUT_EAX_VALUE(Wetlevel, value / 100);
  378. break;
  379. case FFP_Waveform :
  380. CHECK_PARAM(DSFXFLANGER_WAVE_TRIANGLE, DSFXFLANGER_WAVE_SIN);
  381. l = m_EaxWaveform;
  382. PUT_EAX_VALUE(Waveform, (long)value);
  383. if (l != m_EaxWaveform) {
  384. if (!m_EaxWaveform) {
  385. m_LfoState[0] = (float)0.0;
  386. m_LfoState[1] = (float)0.5;
  387. }
  388. else {
  389. m_LfoState[0] = (float)0.0;
  390. m_LfoState[1] = (float)0.99999999999;
  391. }
  392. }
  393. goto x;
  394. // break;
  395. case FFP_Frequency :
  396. CHECK_PARAM(DSFXFLANGER_FREQUENCY_MIN, DSFXFLANGER_FREQUENCY_MAX);
  397. PUT_EAX_VALUE(Frequency, value);
  398. x:
  399. if (!m_EaxWaveform) { // Triangle.
  400. INTERPOLATE
  401. (
  402. LfoCoef,
  403. TOFRACTION(2.0 * (m_EaxFrequency/m_EaxSamplesPerSec) * 1.0)
  404. );
  405. }
  406. else // Sine/Cosine.
  407. {
  408. INTERPOLATE
  409. (
  410. LfoCoef,
  411. TOFRACTION(2.0*sin(PI*m_EaxFrequency/m_EaxSamplesPerSec))
  412. );
  413. }
  414. break;
  415. case FFP_Depth : {
  416. CHECK_PARAM(DSFXFLANGER_DEPTH_MIN, DSFXFLANGER_DEPTH_MAX);
  417. PUT_EAX_VALUE(Depth, value / 100);
  418. double midpoint = m_EaxDelay * m_EaxSamplesPerSec/1000;
  419. INTERPOLATE(DepthCoef, ((m_EaxDepth * midpoint) / 2) * FractMultiplier);
  420. break;
  421. }
  422. case FFP_Phase :
  423. CHECK_PARAM(DSFXFLANGER_PHASE_MIN, DSFXFLANGER_PHASE_MAX);
  424. PUT_EAX_VALUE(Phase, (long)value);
  425. break;
  426. case FFP_Feedback :
  427. CHECK_PARAM(DSFXFLANGER_FEEDBACK_MIN, DSFXFLANGER_FEEDBACK_MAX);
  428. PUT_EAX_FVAL(FbCoef, TOFRACTION(value/100));
  429. break;
  430. case FFP_Delay : {
  431. CHECK_PARAM(DSFXFLANGER_DELAY_MIN, DSFXFLANGER_DELAY_MAX);
  432. PUT_EAX_VALUE(Delay, value);
  433. double midpoint = m_EaxDelay * m_EaxSamplesPerSec/1000;
  434. PUT_EAX_FVAL(DepthCoef, ((m_EaxDepth * midpoint) / 2) * FractMultiplier);
  435. PUT_EAX_LVAL(FixedptrL, (midpoint + 2) * FractMultiplier);
  436. PUT_EAX_LVAL(FixedptrR, (midpoint + 2) * FractMultiplier);
  437. break;
  438. }
  439. // } EAX
  440. default:
  441. return E_FAIL;
  442. }
  443. // Let base class set this so it can handle all the rest of the param calls.
  444. // Skip the base class if fSkipPasssingToParamManager. This indicates that we're calling the function
  445. // internally using valuds that came from the base class -- thus there's no need to tell it values it
  446. // already knows.
  447. return fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
  448. }
  449. //////////////////////////////////////////////////////////////////////////////
  450. //
  451. // CDirectSoundFlangerDMO::SetAllParameters
  452. //
  453. STDMETHODIMP CDirectSoundFlangerDMO::SetAllParameters(LPCDSFXFlanger pFlanger)
  454. {
  455. HRESULT hr = S_OK;
  456. // Check that the pointer is not NULL
  457. if (pFlanger == NULL)
  458. {
  459. Trace(1,"ERROR: pFlanger is NULL\n");
  460. hr = E_POINTER;
  461. }
  462. // Set the parameters
  463. if (SUCCEEDED(hr)) hr = SetParam(FFP_Wetdrymix, pFlanger->fWetDryMix);
  464. if (SUCCEEDED(hr)) hr = SetParam(FFP_Waveform, (float)pFlanger->lWaveform);
  465. if (SUCCEEDED(hr)) hr = SetParam(FFP_Frequency, pFlanger->fFrequency);
  466. if (SUCCEEDED(hr)) hr = SetParam(FFP_Depth, pFlanger->fDepth);
  467. if (SUCCEEDED(hr)) hr = SetParam(FFP_Phase, (float)pFlanger->lPhase);
  468. if (SUCCEEDED(hr)) hr = SetParam(FFP_Feedback, pFlanger->fFeedback);
  469. if (SUCCEEDED(hr)) hr = SetParam(FFP_Delay, pFlanger->fDelay);
  470. m_fDirty = true;
  471. return hr;
  472. }
  473. //////////////////////////////////////////////////////////////////////////////
  474. //
  475. // CDirectSoundFlangerDMO::GetAllParameters
  476. //
  477. STDMETHODIMP CDirectSoundFlangerDMO::GetAllParameters(LPDSFXFlanger pFlanger)
  478. {
  479. HRESULT hr = S_OK;
  480. MP_DATA mpd;
  481. if (pFlanger == NULL) return E_POINTER;
  482. #define GET_PARAM(x,y) \
  483. if (SUCCEEDED(hr)) { \
  484. hr = GetParam(x, &mpd); \
  485. if (SUCCEEDED(hr)) pFlanger->y = mpd; \
  486. }
  487. #define GET_PARAM_LONG(x,y) \
  488. if (SUCCEEDED(hr)) { \
  489. hr = GetParam(x, &mpd); \
  490. if (SUCCEEDED(hr)) pFlanger->y = (long)mpd; \
  491. }
  492. GET_PARAM(FFP_Wetdrymix, fWetDryMix);
  493. GET_PARAM(FFP_Delay, fDelay);
  494. GET_PARAM(FFP_Depth, fDepth);
  495. GET_PARAM(FFP_Frequency, fFrequency);
  496. GET_PARAM_LONG(FFP_Waveform, lWaveform);
  497. GET_PARAM_LONG(FFP_Phase, lPhase);
  498. GET_PARAM(FFP_Feedback, fFeedback);
  499. return hr;
  500. }
  501. // GetClassID
  502. //
  503. // Part of the persistent file support. We must supply our class id
  504. // which can be saved in a graph file and used on loading a graph with
  505. // this fx in it to instantiate this filter via CoCreateInstance.
  506. //
  507. HRESULT CDirectSoundFlangerDMO::GetClassID(CLSID *pClsid)
  508. {
  509. if (pClsid==NULL) {
  510. return E_POINTER;
  511. }
  512. *pClsid = GUID_DSFX_STANDARD_FLANGER;
  513. return NOERROR;
  514. } // GetClassID