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.

480 lines
12 KiB

  1. #include <windows.h>
  2. #include "echop.h"
  3. #include "clone.h"
  4. STD_CREATE(Echo)
  5. //////////////////////////////////////////////////////////////////////////////
  6. //
  7. // CDirectSoundEchoDMO::NDQueryInterface
  8. //
  9. // Subclass can override if it wants to implement more interfaces.
  10. //
  11. STDMETHODIMP CDirectSoundEchoDMO::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_IDirectSoundFXEcho)
  23. {
  24. return GetInterface((IDirectSoundFXEcho*)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. // CDirectSoundEchoDMO::CDirectSoundEchoDMO
  44. //
  45. CDirectSoundEchoDMO::CDirectSoundEchoDMO( 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 = 22050;
  52. m_DelayL.Init(0);
  53. m_DelayR.Init(0);
  54. }
  55. //////////////////////////////////////////////////////////////////////////////
  56. //
  57. // CDirectSoundEchoDMO::Init()
  58. //
  59. HRESULT CDirectSoundEchoDMO::Init()
  60. {
  61. DSFXEcho echo;
  62. HRESULT hr;
  63. // Force recalc of all internal parameters
  64. hr = GetAllParameters(&echo);
  65. if (SUCCEEDED(hr)) hr = SetAllParameters(&echo);
  66. if (SUCCEEDED(hr)) hr = m_DelayL.Init(m_EaxSamplesPerSec);
  67. if (SUCCEEDED(hr)) hr = m_DelayR.Init(m_EaxSamplesPerSec);
  68. if (SUCCEEDED(hr)) hr = Discontinuity();
  69. return hr;
  70. }
  71. 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;
  72. static ParamInfo g_params[] =
  73. {
  74. // index type caps min, max, neutral, unit text, label, pwchText
  75. EFP_Wetdrymix, MPT_FLOAT, g_capsAll, DSFXECHO_WETDRYMIX_MIN, DSFXECHO_WETDRYMIX_MAX, 50, L"", L"WetDryMix", L"",
  76. EFP_Feedback, MPT_FLOAT, g_capsAll, DSFXECHO_FEEDBACK_MIN, DSFXECHO_FEEDBACK_MAX, 50, L"", L"Feedback", L"",
  77. EFP_DelayLeft, MPT_FLOAT, g_capsAll, DSFXECHO_LEFTDELAY_MIN, DSFXECHO_LEFTDELAY_MAX, 500, L"", L"LeftDelay", L"",
  78. EFP_DelayRight, MPT_FLOAT, g_capsAll, DSFXECHO_RIGHTDELAY_MIN, DSFXECHO_RIGHTDELAY_MAX, 500, L"", L"RightDelay", L"",
  79. EFP_PanDelay, MPT_BOOL, g_capsAll, DSFXECHO_PANDELAY_MIN, DSFXECHO_PANDELAY_MAX, 0, L"", L"PanDelay", L"",
  80. };
  81. HRESULT CDirectSoundEchoDMO::InitOnCreation()
  82. {
  83. HRESULT hr = InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
  84. return hr;
  85. }
  86. //////////////////////////////////////////////////////////////////////////////
  87. //
  88. // CDirectSoundEchoDMO::~CDirectSoundEchoDMO
  89. //
  90. CDirectSoundEchoDMO::~CDirectSoundEchoDMO()
  91. {
  92. m_DelayL.Init(-1);
  93. m_DelayR.Init(-1);
  94. }
  95. //////////////////////////////////////////////////////////////////////////////
  96. //
  97. // CDirectSoundEchoDMO::Clone
  98. //
  99. STDMETHODIMP CDirectSoundEchoDMO::Clone(IMediaObjectInPlace **pp)
  100. {
  101. return StandardDMOClone<CDirectSoundEchoDMO, DSFXEcho>(this, pp);
  102. }
  103. //
  104. // Bump - bump the delay pointers.
  105. //
  106. void CDirectSoundEchoDMO::Bump(void)
  107. {
  108. // EAX {
  109. m_DelayL.Bump(); // Bump delay array pointers.
  110. m_DelayR.Bump(); // Bump delay array pointers.
  111. // }
  112. }
  113. HRESULT CDirectSoundEchoDMO::Discontinuity()
  114. {
  115. // { EAX
  116. m_EaxPan = 0;
  117. m_StateL = m_StateR = 0;
  118. m_DelayL.ZeroBuffer();
  119. m_DelayR.ZeroBuffer();
  120. // These values are set to be the defaults when the property page is activated.
  121. // m_EaxDelayLRead = m_DelayL.LastPos(-16);
  122. // m_EaxDelayRRead = m_DelayR.LastPos(-16);
  123. // These values have defined initial values.
  124. // } EAX
  125. return S_OK;
  126. }
  127. //////////////////////////////////////////////////////////////////////////////
  128. __forceinline void CDirectSoundEchoDMO::DoOneSample(int *l, int *r)
  129. {
  130. float inPortL = (float)*l;
  131. float inPortR = (float)*r;
  132. float outPortL, outPortR;
  133. int pos;
  134. float tempvar, temp2;
  135. //LeftDelayRead:
  136. // tempvar = delayL[@-16] + 0 * 0;
  137. // tempvar = delayRread + 0 * 0;
  138. if (m_EaxPan) {
  139. pos = m_DelayR.Pos((int)m_EaxDelayRRead);
  140. tempvar = m_DelayR[pos];
  141. }
  142. else {
  143. pos = m_DelayL.Pos((int)m_EaxDelayLRead);
  144. tempvar = m_DelayL[pos];
  145. }
  146. temp2 = m_StateL + tempvar * m_EaxLpfb;
  147. // delayL[] = ACC + inPortL[0] * lpff;
  148. pos = m_DelayL.Pos(0);
  149. m_DelayL[pos] = temp2 + inPortL * m_EaxLpff;
  150. m_StateL = tempvar * m_EaxLpfb;
  151. // outPortL = wetlevel : inPortL[1] < tempvar;
  152. outPortL = Interpolate(inPortL, tempvar, m_EaxWetlevel);
  153. //RightDelayRead:
  154. // tempvar = delayR[@-16] + 0 * 0;
  155. // tempvar = delayRread + 0 * 0;
  156. if (m_EaxPan) {
  157. pos = m_DelayL.Pos((int)m_EaxDelayLRead);
  158. tempvar = m_DelayL[pos];
  159. }
  160. else {
  161. pos = m_DelayR.Pos((int)m_EaxDelayRRead);
  162. tempvar = m_DelayR[pos];
  163. }
  164. temp2 = m_StateR + tempvar * m_EaxLpfb;
  165. // delayR[]= ACC + inPortR[0] * lpff;
  166. pos = m_DelayR.Pos(0);
  167. m_DelayR[pos] = temp2 + inPortR * m_EaxLpff;
  168. m_StateR = tempvar * m_EaxLpfb;
  169. // outPortR = wetlevel : inPortR[1] < tempvar;
  170. outPortR = Interpolate(inPortR, tempvar, m_EaxWetlevel);
  171. *l = Saturate(outPortL);
  172. *r = Saturate(outPortR);
  173. Bump();
  174. }
  175. //////////////////////////////////////////////////////////////////////////////
  176. //
  177. // CDirectSoundEchoDMO::FBRProcess
  178. //
  179. HRESULT CDirectSoundEchoDMO::FBRProcess(DWORD cSamples, BYTE *pIn, BYTE *pOut)
  180. {
  181. // { EAX
  182. #define cb cSamples
  183. #define pin pIn
  184. #define pout pOut
  185. if (m_cChannels == 1) {
  186. if (m_b8bit) {
  187. for (;cb > 0; --cb) {
  188. int i, j;
  189. i = *(pin+0)-128;
  190. i *=256;
  191. j = i;
  192. DoOneSample(&i, &j);
  193. i += j;
  194. i /= 2;
  195. i /= 256;
  196. *(pout+0) = (unsigned char)(i + 128);
  197. pin += sizeof(unsigned char);
  198. pout += sizeof(unsigned char);
  199. }
  200. }
  201. else if (!m_b8bit) {
  202. for (;cb > 0; --cb) { // for (;cb > 0; cb -= sizeof(short)) {
  203. short int *psi = (short int *)pin;
  204. short int *pso = (short int *)pout;
  205. int i, j;
  206. i = *psi;
  207. j = i;
  208. DoOneSample(&i, &j);
  209. i += j;
  210. i /= 2;
  211. *pso = (short)i;
  212. pin += sizeof(short);
  213. pout += sizeof(short);
  214. }
  215. }
  216. }
  217. else if (m_cChannels == 2) {
  218. if (m_b8bit) {
  219. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(unsigned char)) {
  220. int i, j;
  221. i = *(pin+0)-128;
  222. j = *(pin+1)-128;
  223. i *=256; j *=256;
  224. DoOneSample(&i, &j);
  225. i /= 256; j /= 256;
  226. *(pout+0) = (unsigned char)(i + 128);
  227. *(pout+1) = (unsigned char)(j + 128);
  228. pin += 2 * sizeof(unsigned char);
  229. pout += 2 * sizeof(unsigned char);
  230. }
  231. }
  232. else if (!m_b8bit) {
  233. for (;cb > 0; --cb) { // for (;cb > 0; cb -= 2 * sizeof(short)) {
  234. short int *psi = (short int *)pin;
  235. short int *pso = (short int *)pout;
  236. int i, j;
  237. i = *(psi+0);
  238. j = *(psi+1);
  239. DoOneSample(&i, &j);
  240. *(pso+0) = (short)i;
  241. *(pso+1) = (short)j;
  242. pin += 2 * sizeof(short);
  243. pout += 2 * sizeof(short);
  244. }
  245. }
  246. }
  247. // } EAX
  248. return S_OK;
  249. }
  250. //////////////////////////////////////////////////////////////////////////////
  251. //
  252. // CDirectSoundEchoDMO::ProcessInPlace
  253. //
  254. HRESULT CDirectSoundEchoDMO::ProcessInPlace(ULONG ulQuanta, LPBYTE pcbData, REFERENCE_TIME rtStart, DWORD dwFlags)
  255. {
  256. // Update parameter values from any curves that may be in effect.
  257. this->UpdateActiveParams(rtStart, *this);
  258. return FBRProcess(ulQuanta, pcbData, pcbData);
  259. }
  260. //////////////////////////////////////////////////////////////////////////////
  261. //
  262. // CDirectSoundEchoDMO::SetParam
  263. //
  264. HRESULT CDirectSoundEchoDMO::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
  265. {
  266. if (!m_EaxSamplesPerSec) return DMO_E_TYPE_NOT_ACCEPTED; // NO TYPE!
  267. switch (dwParamIndex)
  268. {
  269. // { EAX
  270. case EFP_Wetdrymix :
  271. CHECK_PARAM(DSFXECHO_WETDRYMIX_MIN, DSFXECHO_WETDRYMIX_MAX);
  272. PUT_EAX_VALUE(Wetlevel, value / 100);
  273. break;
  274. case EFP_Feedback : {
  275. CHECK_PARAM(DSFXECHO_FEEDBACK_MIN, DSFXECHO_FEEDBACK_MAX);
  276. MP_DATA valueFeedbackFactor = value / 100; // ratio out of one instead of 100
  277. PUT_EAX_VALUE(Lpfb, TOFRACTION(valueFeedbackFactor/2));
  278. PUT_EAX_VALUE(Lpff, TOFRACTION(sqrt(1.0 - valueFeedbackFactor*valueFeedbackFactor)));
  279. break;
  280. }
  281. case EFP_DelayLeft : {
  282. CHECK_PARAM(DSFXECHO_LEFTDELAY_MIN, DSFXECHO_LEFTDELAY_MAX);
  283. PUT_EAX_LVAL(DelayLRead, (value * FractMultiplier) /1000 * m_EaxSamplesPerSec);
  284. break;
  285. }
  286. case EFP_DelayRight : {
  287. CHECK_PARAM(DSFXECHO_RIGHTDELAY_MIN, DSFXECHO_RIGHTDELAY_MAX);
  288. PUT_EAX_LVAL(DelayRRead, (value * FractMultiplier) /1000 * m_EaxSamplesPerSec);
  289. break;
  290. case EFP_PanDelay : {
  291. CHECK_PARAM(DSFXECHO_PANDELAY_MIN, DSFXECHO_PANDELAY_MAX);
  292. PUT_EAX_LVAL(Pan, value);
  293. #if 0
  294. if(value)
  295. {
  296. //Panned Delay
  297. float fval = m_EaxDelayRRead;
  298. m_EaxDelayRRead = m_EaxDelayLRead;
  299. m_EaxDelayLRead = fval;
  300. }
  301. else
  302. {
  303. //Unpanned Delay
  304. }
  305. #endif
  306. break;
  307. }
  308. }
  309. // } EAX
  310. default:
  311. return E_FAIL;
  312. }
  313. // Let base class set this so it can handle all the rest of the param calls.
  314. // Skip the base class if fSkipPasssingToParamManager. This indicates that we're calling the function
  315. // internally using valuds that came from the base class -- thus there's no need to tell it values it
  316. // already knows.
  317. return fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
  318. }
  319. //////////////////////////////////////////////////////////////////////////////
  320. //
  321. // CDirectSoundEchoDMO::SetAllParameters
  322. //
  323. STDMETHODIMP CDirectSoundEchoDMO::SetAllParameters(LPCDSFXEcho pEcho)
  324. {
  325. HRESULT hr = S_OK;
  326. // Check that the pointer is not NULL
  327. if (pEcho == NULL)
  328. {
  329. Trace(1,"ERROR: pEcho is NULL\n");
  330. hr = E_POINTER;
  331. }
  332. // Set the parameters
  333. if (SUCCEEDED(hr)) hr = SetParam(EFP_Wetdrymix, pEcho->fWetDryMix);
  334. if (SUCCEEDED(hr)) hr = SetParam(EFP_Feedback, pEcho->fFeedback);
  335. if (SUCCEEDED(hr)) hr = SetParam(EFP_DelayLeft, pEcho->fLeftDelay);
  336. if (SUCCEEDED(hr)) hr = SetParam(EFP_DelayRight, pEcho->fRightDelay);
  337. if (SUCCEEDED(hr)) hr = SetParam(EFP_PanDelay, (float)pEcho->lPanDelay);
  338. m_fDirty = true;
  339. return hr;
  340. }
  341. //////////////////////////////////////////////////////////////////////////////
  342. //
  343. // CDirectSoundEchoDMO::GetAllParameters
  344. //
  345. STDMETHODIMP CDirectSoundEchoDMO::GetAllParameters(LPDSFXEcho pEcho)
  346. {
  347. HRESULT hr = S_OK;
  348. MP_DATA mpd;
  349. if (pEcho == NULL)
  350. {
  351. return E_POINTER;
  352. }
  353. #define GET_PARAM(x,y) \
  354. if (SUCCEEDED(hr)) { \
  355. hr = GetParam(x, &mpd); \
  356. if (SUCCEEDED(hr)) pEcho->y = mpd; \
  357. }
  358. #define GET_PARAM_LONG(x,y) \
  359. if (SUCCEEDED(hr)) { \
  360. hr = GetParam(x, &mpd); \
  361. if (SUCCEEDED(hr)) pEcho->y = (long)mpd; \
  362. }
  363. GET_PARAM(EFP_Wetdrymix, fWetDryMix);
  364. GET_PARAM(EFP_Feedback, fFeedback);
  365. GET_PARAM(EFP_DelayLeft, fLeftDelay);
  366. GET_PARAM(EFP_DelayRight, fRightDelay);
  367. GET_PARAM_LONG(EFP_PanDelay, lPanDelay);
  368. return hr;
  369. }
  370. // GetClassID
  371. //
  372. // Part of the persistent file support. We must supply our class id
  373. // which can be saved in a graph file and used on loading a graph with
  374. // this fx in it to instantiate this filter via CoCreateInstance.
  375. //
  376. HRESULT CDirectSoundEchoDMO::GetClassID(CLSID *pClsid)
  377. {
  378. if (pClsid==NULL) {
  379. return E_POINTER;
  380. }
  381. *pClsid = GUID_DSFX_STANDARD_ECHO;
  382. return NOERROR;
  383. } // GetClassID