Leaked source code of windows server 2003
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.

582 lines
17 KiB

  1. #include <windows.h>
  2. #include "chorusp.h"
  3. #include "Debug.h"
  4. #include "clone.h"
  5. STD_CREATE(Chorus)
  6. //////////////////////////////////////////////////////////////////////////////
  7. //
  8. // CDirectSoundChorusDMO::QueryInterface
  9. //
  10. // Subclass can override if it wants to implement more interfaces.
  11. //
  12. HRESULT CDirectSoundChorusDMO::NDQueryInterface(REFIID riid, void **ppv) {
  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_IDirectSoundFXChorus)
  23. {
  24. return GetInterface((IDirectSoundFXChorus*)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. // CDirectSoundChorusDMO::CDirectSoundChorusDMO
  44. //
  45. CDirectSoundChorusDMO::CDirectSoundChorusDMO( 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_DelayLine.Init(0);
  53. }
  54. //////////////////////////////////////////////////////////////////////////////
  55. //
  56. // CDirectSoundChorusDMO::Init()
  57. //
  58. HRESULT CDirectSoundChorusDMO::Init()
  59. {
  60. DSFXChorus chorus;
  61. HRESULT hr;
  62. // Force recalc of all internal parameters
  63. //
  64. hr = GetAllParameters(&chorus);
  65. if (SUCCEEDED(hr)) hr = SetAllParameters(&chorus);
  66. if (SUCCEEDED(hr)) hr = m_DelayLine.Init(m_EaxSamplesPerSec);
  67. if (SUCCEEDED(hr)) hr = Discontinuity();
  68. return hr;
  69. }
  70. 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;
  71. static ParamInfo g_params[] =
  72. {
  73. // index type caps min, max, neutral, unit text, label, pwchText
  74. CFP_Wetdrymix, MPT_FLOAT, g_capsAll, DSFXCHORUS_WETDRYMIX_MIN, DSFXCHORUS_WETDRYMIX_MAX, 50, L"%", L"WetDryMix", L"",
  75. CFP_Depth, MPT_FLOAT, g_capsAll, DSFXCHORUS_DEPTH_MIN, DSFXCHORUS_DEPTH_MAX, 10, L"", L"Depth", L"",
  76. CFP_Frequency, MPT_FLOAT, g_capsAll, DSFXCHORUS_FREQUENCY_MIN, DSFXCHORUS_FREQUENCY_MAX, (float)1.1, L"Hz", L"Frequency", L"",
  77. CFP_Waveform, MPT_ENUM, g_capsAll, DSFXCHORUS_WAVE_TRIANGLE, DSFXCHORUS_WAVE_SIN, DSFXCHORUS_WAVE_SIN, L"", L"WaveShape", L"Triangle,Sine",
  78. CFP_Phase, MPT_INT, g_capsAll, DSFXCHORUS_PHASE_MIN, DSFXCHORUS_PHASE_MAX, 3, L"", L"Phase", L"",
  79. CFP_Feedback, MPT_FLOAT, g_capsAll, DSFXCHORUS_FEEDBACK_MIN, DSFXCHORUS_FEEDBACK_MAX, 25, L"", L"Feedback", L"",
  80. CFP_Delay, MPT_FLOAT, g_capsAll, DSFXCHORUS_DELAY_MIN, DSFXCHORUS_DELAY_MAX, 16, L"", L"Delay", L"",
  81. };
  82. HRESULT CDirectSoundChorusDMO::InitOnCreation()
  83. {
  84. HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
  85. return hr;
  86. }
  87. //////////////////////////////////////////////////////////////////////////////
  88. //
  89. // CDirectSoundChorusDMO::~CDirectSoundChorusDMO
  90. //
  91. CDirectSoundChorusDMO::~CDirectSoundChorusDMO()
  92. {
  93. m_DelayLine.Init(-1);
  94. }
  95. //////////////////////////////////////////////////////////////////////////////
  96. //
  97. // CDirectSoundChorusDMO::Clone
  98. //
  99. STDMETHODIMP CDirectSoundChorusDMO::Clone(IMediaObjectInPlace **pp)
  100. {
  101. return StandardDMOClone<CDirectSoundChorusDMO, DSFXChorus>(this, pp);
  102. }
  103. HRESULT CDirectSoundChorusDMO::Discontinuity()
  104. {
  105. if (!m_EaxWaveform) {
  106. m_LfoState[0] = (float)0.0;
  107. m_LfoState[1] = (float)0.5;
  108. }
  109. else {
  110. m_LfoState[0] = (float)0.0;
  111. m_LfoState[1] = (float)0.99999999999;
  112. }
  113. m_DelayLine.ZeroBuffer();
  114. m_DelayFixedPtr = (int)m_EaxDelayCoef;
  115. m_DelayL = m_DelayFixedPtr;
  116. m_DelayL1 = m_DelayFixedPtr;
  117. m_DelayR = m_DelayFixedPtr;
  118. m_DelayR1 = m_DelayFixedPtr;
  119. return S_OK;
  120. }
  121. //////////////////////////////////////////////////////////////////////////////
  122. static int LMul [5] = { 1, 1, 1, 1, -1};
  123. static int RMul [5] = { -1, -1, 1, 1, 1};
  124. static int RPhase[5] = { 0, 1, 0, 1, 0};
  125. __forceinline void CDirectSoundChorusDMO::DoOneSample(int *l, int *r)
  126. {
  127. float inPortL, inPortR;
  128. float TempVar;
  129. float XWave[2];
  130. // float sinwave, coswave;
  131. #define sinwave XWave[0]
  132. #define coswave XWave[1]
  133. int Pos0, Pos1;
  134. int DelayFixedPtr = m_DelayLine.Pos(m_DelayFixedPtr);
  135. Pos0 = m_DelayLine.Pos(0);
  136. TempVar = m_DelayLine[DelayFixedPtr] * m_EaxFbCoef;
  137. inPortL = (float)*l;
  138. inPortR = (float)*r;
  139. m_DelayLine[Pos0] = TempVar + (inPortL + inPortR) / 2;
  140. if (!m_EaxWaveform) {
  141. m_LfoState[0] = m_LfoState[0] + m_EaxLfoCoef;
  142. if (m_LfoState[0] > 1) m_LfoState[0] -= 2;
  143. m_LfoState[1] = m_LfoState[1] + m_EaxLfoCoef;
  144. if (m_LfoState[1] > 1) m_LfoState[1] -= 2;
  145. sinwave = (float)fabs(m_LfoState[0]);
  146. coswave = (float)fabs(m_LfoState[1]);
  147. sinwave = -1 + 2 * sinwave;
  148. coswave = -1 + 2 * coswave;
  149. }
  150. else {
  151. m_LfoState[0] = m_LfoState[0] + m_EaxLfoCoef * m_LfoState[1];
  152. m_LfoState[1] = m_LfoState[1] - m_EaxLfoCoef * m_LfoState[0];
  153. sinwave = m_LfoState[0];
  154. coswave = m_LfoState[1];
  155. }
  156. Pos0 = m_DelayLine.Pos(m_DelayL);
  157. Pos1 = m_DelayLine.Pos(m_DelayL1);
  158. TempVar = (float)(m_DelayL & FractMask);
  159. TempVar /= (float)FractMultiplier;
  160. TempVar = Interpolate(m_DelayLine[Pos0], m_DelayLine[Pos1], TempVar);
  161. inPortL = Interpolate(inPortL, TempVar, m_EaxWetLevel);
  162. // m_DelayL = m_DelayFixedPtr + (int)(sinwave * m_EaxDepthCoef);
  163. #if 0
  164. switch (m_EaxPhase) {
  165. case 0:
  166. case 1:
  167. case 2:
  168. case 3: m_DelayL = (int)(sinwave * m_EaxDepthCoef); break;
  169. case 4: m_DelayL = - (int)(sinwave * m_EaxDepthCoef); break;
  170. }
  171. #else
  172. #ifdef DONTUSEi386
  173. {
  174. int x;
  175. float f = (sinwave * m_EaxDepthCoef);
  176. _asm {
  177. fld f
  178. fistp x
  179. }
  180. m_DelayL = LMul[m_EaxPhase] * x;
  181. }
  182. #else
  183. m_DelayL = LMul[m_EaxPhase] * (int)(sinwave * m_EaxDepthCoef);
  184. #endif
  185. #endif
  186. m_DelayL += m_DelayFixedPtr;
  187. m_DelayL1 = m_DelayL + FractMultiplier;
  188. *l = Saturate(inPortL);
  189. Pos0 = m_DelayLine.Pos(m_DelayR);
  190. Pos1 = m_DelayLine.Pos(m_DelayR1);
  191. TempVar = (float)(m_DelayR & FractMask);
  192. TempVar /= (float)FractMultiplier;
  193. TempVar = Interpolate(m_DelayLine[Pos0], m_DelayLine[Pos1], TempVar);
  194. inPortR = Interpolate(inPortR, TempVar, m_EaxWetLevel);
  195. // m_DelayR = m_DelayFixedPtr + (int)(coswave * m_EaxDepthCoef);
  196. #if 0
  197. switch (m_EaxPhase) {
  198. case 0: m_DelayR = - (int)(sinwave * m_EaxDepthCoef); break;
  199. case 1: m_DelayR = - (int)(coswave * m_EaxDepthCoef); break;
  200. case 3: m_DelayR = (int)(coswave * m_EaxDepthCoef); break;
  201. case 2:
  202. case 4: m_DelayR = (int)(sinwave * m_EaxDepthCoef); break;
  203. }
  204. #else
  205. Pos0 = RPhase[m_EaxPhase];
  206. #ifdef DONTUSEi386
  207. {
  208. int x;
  209. float f = (XWave[Pos0] * m_EaxDepthCoef);
  210. _asm {
  211. fld f
  212. fistp x
  213. }
  214. m_DelayR = RMul [m_EaxPhase] * x;
  215. }
  216. #else
  217. m_DelayR = RMul [m_EaxPhase] * (int)(XWave[Pos0] * m_EaxDepthCoef);
  218. #endif
  219. #endif
  220. m_DelayR += m_DelayFixedPtr;
  221. m_DelayR1 = m_DelayR + FractMultiplier;
  222. *r = Saturate(inPortR);
  223. m_DelayLine.Bump();
  224. }
  225. //////////////////////////////////////////////////////////////////////////////
  226. //
  227. // CDirectSoundChorusDMO::FBRProcess
  228. //
  229. HRESULT CDirectSoundChorusDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut)
  230. {
  231. #define cb cSamples
  232. #define pin pIn
  233. #define pout pOut
  234. if (m_cChannels == 1) {
  235. if (m_b8bit) {
  236. for (;cb > 0; --cb) {
  237. int i, j;
  238. i = *(pin+0)-128;
  239. i *=256;
  240. j = i;
  241. DoOneSample(&i, &j);
  242. i += j;
  243. i /= 2;
  244. i /= 256;
  245. *(pout+0) = (unsigned char)(i + 128);
  246. pin += sizeof(unsigned char);
  247. pout += sizeof(unsigned char);
  248. }
  249. }
  250. else if (!m_b8bit) {
  251. for (;cb > 0; --cb) { // for (;cb > 0; cb -= sizeof(short)) {
  252. short int *psi = (short int *)pin;
  253. short int *pso = (short int *)pout;
  254. int i, j;
  255. i = *psi;
  256. j = i;
  257. DoOneSample(&i, &j);
  258. i += j;
  259. i /= 2;
  260. *pso = (short)i;
  261. pin += sizeof(short);
  262. pout += sizeof(short);
  263. }
  264. }
  265. }
  266. else if (m_cChannels == 2) {
  267. if (m_b8bit) {
  268. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(unsigned char)) {
  269. int i, j;
  270. i = *(pin+0)-128;
  271. j = *(pin+1)-128;
  272. i *=256; j *=256;
  273. DoOneSample(&i, &j);
  274. i /= 256; j /= 256;
  275. *(pout+0) = (unsigned char)(i + 128);
  276. *(pout+1) = (unsigned char)(j + 128);
  277. pin += 2 * sizeof(unsigned char);
  278. pout += 2 * sizeof(unsigned char);
  279. }
  280. }
  281. else if (!m_b8bit) {
  282. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(short)) {
  283. short int *psi = (short int *)pin;
  284. short int *pso = (short int *)pout;
  285. int i, j;
  286. i = *(psi+0);
  287. j = *(psi+1);
  288. DoOneSample(&i, &j);
  289. *(pso+0) = (short)i;
  290. *(pso+1) = (short)j;
  291. pin += 2 * sizeof(short);
  292. pout += 2 * sizeof(short);
  293. }
  294. }
  295. }
  296. return S_OK;
  297. }
  298. //////////////////////////////////////////////////////////////////////////////
  299. //
  300. // CDirectSoundChorusDMO::ProcessInPlace
  301. //
  302. HRESULT CDirectSoundChorusDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags)
  303. {
  304. // Update parameter values from any curves that may be in effect.
  305. this->UpdateActiveParams(rtStart, *this);
  306. return FBRProcess(ulQuanta, pcbData, pcbData);
  307. }
  308. //////////////////////////////////////////////////////////////////////////////
  309. //
  310. // CDirectSoundChorusDMO::SetParamInternal
  311. //
  312. HRESULT CDirectSoundChorusDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
  313. {
  314. long l;
  315. if (!m_EaxSamplesPerSec) return DMO_E_TYPE_NOT_ACCEPTED; // NO TYPE!
  316. switch (dwParamIndex)
  317. {
  318. // { EAX
  319. case CFP_Wetdrymix :
  320. CHECK_PARAM(DSFXCHORUS_WETDRYMIX_MIN, DSFXCHORUS_WETDRYMIX_MAX);
  321. PUT_EAX_VALUE(WetLevel, value / 100);
  322. break;
  323. case CFP_Depth : {
  324. CHECK_PARAM(DSFXCHORUS_DEPTH_MIN, DSFXCHORUS_DEPTH_MAX);
  325. PUT_EAX_VALUE(Depth, value / 100);
  326. double midpoint = m_EaxDelay * m_EaxSamplesPerSec/1000;
  327. INTERPOLATE(DepthCoef, (float)((m_EaxDepth * midpoint) / 2) * FractMultiplier);
  328. break;
  329. }
  330. case CFP_Delay : {
  331. CHECK_PARAM(DSFXCHORUS_DELAY_MIN, DSFXCHORUS_DELAY_MAX);
  332. PUT_EAX_VALUE(Delay, value);
  333. double midpoint = m_EaxDelay * m_EaxSamplesPerSec/1000;
  334. m_EaxDepthCoef = (float)(((m_EaxDepth * midpoint) / 2) * FractMultiplier);
  335. m_EaxDelayCoef = (float)((midpoint + 2) * FractMultiplier);
  336. break;
  337. }
  338. case CFP_Frequency : {
  339. CHECK_PARAM(DSFXCHORUS_FREQUENCY_MIN, DSFXCHORUS_FREQUENCY_MAX);
  340. PUT_EAX_VALUE(Frequency, value);
  341. x:
  342. if (!m_EaxWaveform) {
  343. INTERPOLATE
  344. (
  345. LfoCoef,
  346. TOFRACTION(2.0 * (m_EaxFrequency/m_EaxSamplesPerSec) * 1.0)
  347. );
  348. }
  349. else
  350. {
  351. INTERPOLATE
  352. (
  353. LfoCoef,
  354. TOFRACTION(2.0*sin(PI*m_EaxFrequency/m_EaxSamplesPerSec))
  355. );
  356. }
  357. break;
  358. }
  359. case CFP_Waveform :
  360. CHECK_PARAM(DSFXCHORUS_WAVE_TRIANGLE, DSFXCHORUS_WAVE_SIN);
  361. l = m_EaxWaveform;
  362. PUT_EAX_VALUE(Waveform, (long)value);
  363. if (l != m_EaxWaveform) {
  364. if (!m_EaxWaveform) {
  365. m_LfoState[0] = (float)0.0;
  366. m_LfoState[1] = (float)0.5;
  367. }
  368. else {
  369. m_LfoState[0] = (float)0.0;
  370. m_LfoState[1] = (float)0.99999999999;
  371. }
  372. }
  373. goto x;
  374. case CFP_Phase :
  375. CHECK_PARAM(DSFXCHORUS_PHASE_MIN, DSFXCHORUS_PHASE_MAX);
  376. PUT_EAX_VALUE(Phase, (long)value);
  377. break;
  378. case CFP_Feedback :
  379. CHECK_PARAM(DSFXCHORUS_FEEDBACK_MIN, DSFXCHORUS_FEEDBACK_MAX);
  380. PUT_EAX_VALUE(FbCoef, value / 100);
  381. // m_EaxFbCoef = TOFRACTION(m_EaxFbCoef);
  382. break;
  383. // } EAX
  384. default:
  385. return E_FAIL;
  386. }
  387. // Let base class set this so it can handle all the rest of the param calls.
  388. // Skip the base class if fSkipPasssingToParamManager. This indicates that we're calling the function
  389. // internally using valuds that came from the base class -- thus there's no need to tell it values it
  390. // already knows.
  391. return fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
  392. }
  393. //////////////////////////////////////////////////////////////////////////////
  394. //
  395. // CDirectSoundChorusDMO::SetAllParameters
  396. //
  397. STDMETHODIMP CDirectSoundChorusDMO::SetAllParameters(LPCDSFXChorus pChorus)
  398. {
  399. HRESULT hr = S_OK;
  400. // Check that the pointer is not NULL
  401. if (pChorus == NULL)
  402. {
  403. Trace(1,"ERROR: pChorus is NULL\n");
  404. hr = E_POINTER;
  405. }
  406. // Set the parameters
  407. if (SUCCEEDED(hr)) hr = SetParam(CFP_Wetdrymix, pChorus->fWetDryMix);
  408. if (SUCCEEDED(hr)) hr = SetParam(CFP_Depth, pChorus->fDepth);
  409. if (SUCCEEDED(hr)) hr = SetParam(CFP_Frequency, pChorus->fFrequency);
  410. if (SUCCEEDED(hr)) hr = SetParam(CFP_Waveform, (float)pChorus->lWaveform);
  411. if (SUCCEEDED(hr)) hr = SetParam(CFP_Phase, (float)pChorus->lPhase);
  412. if (SUCCEEDED(hr)) hr = SetParam(CFP_Feedback, pChorus->fFeedback);
  413. if (SUCCEEDED(hr)) hr = SetParam(CFP_Delay, pChorus->fDelay);
  414. m_fDirty = true;
  415. return hr;
  416. }
  417. //////////////////////////////////////////////////////////////////////////////
  418. //
  419. // CDirectSoundChorusDMO::GetAllParameters
  420. //
  421. STDMETHODIMP CDirectSoundChorusDMO::GetAllParameters(LPDSFXChorus pChorus)
  422. {
  423. HRESULT hr = S_OK;
  424. MP_DATA mpd;
  425. if (pChorus == NULL)
  426. {
  427. return E_POINTER;
  428. }
  429. #define GET_PARAM(x,y) \
  430. if (SUCCEEDED(hr)) { \
  431. hr = GetParam(x, &mpd); \
  432. if (SUCCEEDED(hr)) pChorus->y = mpd; \
  433. }
  434. #define GET_PARAM_LONG(x,y) \
  435. if (SUCCEEDED(hr)) { \
  436. hr = GetParam(x, &mpd); \
  437. if (SUCCEEDED(hr)) pChorus->y = (long)mpd; \
  438. }
  439. GET_PARAM(CFP_Wetdrymix, fWetDryMix);
  440. GET_PARAM(CFP_Delay, fDelay);
  441. GET_PARAM(CFP_Depth, fDepth);
  442. GET_PARAM(CFP_Frequency, fFrequency);
  443. GET_PARAM_LONG(CFP_Waveform, lWaveform);
  444. GET_PARAM_LONG(CFP_Phase, lPhase);
  445. GET_PARAM(CFP_Feedback, fFeedback);
  446. return hr;
  447. }
  448. // GetClassID
  449. //
  450. // Part of the persistent file support. We must supply our class id
  451. // which can be saved in a graph file and used on loading a graph with
  452. // this fx in it to instantiate this filter via CoCreateInstance.
  453. //
  454. HRESULT CDirectSoundChorusDMO::GetClassID(CLSID *pClsid)
  455. {
  456. if (pClsid==NULL) {
  457. return E_POINTER;
  458. }
  459. *pClsid = GUID_DSFX_STANDARD_CHORUS;
  460. return NOERROR;
  461. } // GetClassID
  462. HRESULT CDirectSoundChorusDMO::CheckInputType(const DMO_MEDIA_TYPE *pmt)
  463. {
  464. HRESULT hr = CPCMDMO::CheckInputType(pmt);
  465. if (FAILED(hr)) return hr;
  466. WAVEFORMATEX *pWave = (WAVEFORMATEX*)pmt->pbFormat;
  467. if (pWave->wFormatTag != WAVE_FORMAT_PCM ||
  468. (pWave->wBitsPerSample != 8 && pWave->wBitsPerSample != 16) ||
  469. (pWave->nChannels != 1 && pWave->nChannels != 2)) {
  470. return DMO_E_TYPE_NOT_ACCEPTED;
  471. }
  472. return S_OK;
  473. }