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.

464 lines
13 KiB

  1. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  2. //
  3. // Declaration of CParamsManager.
  4. //
  5. #include "dmerror.h"
  6. #include "param.h"
  7. #include "math.h"
  8. #include "..\shared\validate.h"
  9. CParamsManager::CParamsManager()
  10. {
  11. m_fDirty = FALSE;
  12. m_fMusicTime = FALSE;
  13. m_cParams = 0;
  14. m_pCurveLists = NULL;
  15. m_pParamInfos = NULL;
  16. InitializeCriticalSection(&m_ParamsCriticalSection);
  17. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  18. // ever pops in stress, we can add an exception handler and retry loop.
  19. }
  20. CParamsManager::~CParamsManager()
  21. {
  22. delete[] m_pCurveLists;
  23. delete[] m_pParamInfos;
  24. DeleteCriticalSection(&m_ParamsCriticalSection);
  25. }
  26. HRESULT CParamsManager::InitParams(DWORD cParams, ParamInfo *pParamInfo)
  27. {
  28. m_pCurveLists = new CCurveList[cParams];
  29. if (!m_pCurveLists)
  30. return E_OUTOFMEMORY;
  31. // save the parameter info
  32. m_pParamInfos = new ParamInfo[cParams];
  33. if (!m_pParamInfos)
  34. return E_OUTOFMEMORY;
  35. for (DWORD dwIndex = 0; dwIndex < cParams; dwIndex++)
  36. {
  37. if (pParamInfo[dwIndex].dwIndex < cParams)
  38. {
  39. memcpy(&m_pParamInfos[pParamInfo[dwIndex].dwIndex], &pParamInfo[dwIndex], sizeof(ParamInfo));
  40. }
  41. }
  42. m_cParams = cParams;
  43. return S_OK;
  44. }
  45. HRESULT CParamsManager::GetParamCount(DWORD *pdwParams)
  46. {
  47. if (pdwParams == NULL)
  48. return E_POINTER;
  49. *pdwParams = m_cParams;
  50. return S_OK;
  51. }
  52. HRESULT CParamsManager::GetParamInfo(DWORD dwParamIndex, MP_PARAMINFO *pInfo)
  53. {
  54. if (!pInfo)
  55. {
  56. return E_POINTER;
  57. }
  58. if (dwParamIndex < m_cParams)
  59. {
  60. *pInfo = m_pParamInfos[dwParamIndex].MParamInfo;
  61. return S_OK;
  62. }
  63. else
  64. {
  65. return E_INVALIDARG;
  66. }
  67. }
  68. HRESULT CParamsManager::GetParamText(DWORD dwParamIndex, WCHAR **ppwchText)
  69. {
  70. if (!ppwchText)
  71. {
  72. return E_POINTER;
  73. }
  74. if (dwParamIndex < m_cParams)
  75. {
  76. // write string of format: "Label\0Unit\0Enums1\0Enum2\0...EnumN\0\0"
  77. ParamInfo &pinfo = m_pParamInfos[dwParamIndex];
  78. int iUnit = wcslen(pinfo.MParamInfo.szLabel) + 1; // begin writing unit text here
  79. int iEnums = iUnit + wcslen(pinfo.MParamInfo.szUnitText) + 1; // begin writing enum text here
  80. int iEnd = iEnums + wcslen(pinfo.pwchText) + 1; // write the final (second) null terminator here
  81. WCHAR *pwsz = static_cast<WCHAR *>(CoTaskMemAlloc((iEnd + 1) * sizeof(WCHAR)));
  82. if (!pwsz)
  83. return E_OUTOFMEMORY;
  84. // wcscpy will write into various points of the string, neatly terminating each with a null
  85. wcscpy(pwsz, pinfo.MParamInfo.szLabel);
  86. wcscpy(pwsz + iUnit, pinfo.MParamInfo.szUnitText);
  87. wcscpy(pwsz + iEnums, pinfo.pwchText);
  88. // The text field was defined with commas to separate the enum values.
  89. // Replace them with NULL characters now.
  90. for (WCHAR *pwch = pwsz + iEnums; *pwch; ++pwch)
  91. {
  92. if (*pwch == L',')
  93. *pwch = L'\0';
  94. }
  95. pwsz[iEnd] = L'\0';
  96. *ppwchText = pwsz;
  97. return S_OK;
  98. }
  99. else
  100. {
  101. return E_INVALIDARG;
  102. }
  103. }
  104. HRESULT CParamsManager::GetNumTimeFormats(DWORD *pdwNumTimeFormats)
  105. {
  106. if (!pdwNumTimeFormats)
  107. {
  108. return E_POINTER;
  109. }
  110. *pdwNumTimeFormats = 2;
  111. return S_OK;
  112. }
  113. HRESULT CParamsManager::GetSupportedTimeFormat(DWORD dwFormatIndex, GUID *pguidTimeFormat)
  114. {
  115. if (!pguidTimeFormat)
  116. {
  117. return E_POINTER;
  118. }
  119. if (dwFormatIndex == 0)
  120. {
  121. *pguidTimeFormat = GUID_TIME_REFERENCE;
  122. }
  123. else
  124. {
  125. *pguidTimeFormat = GUID_TIME_MUSIC;
  126. }
  127. return S_OK;
  128. }
  129. HRESULT CParamsManager::GetCurrentTimeFormat( GUID *pguidTimeFormat, MP_TIMEDATA *pTimeData)
  130. {
  131. return E_NOTIMPL;
  132. }
  133. HRESULT CParamsManager::CopyParamsFromSource( CParamsManager * pSource)
  134. {
  135. HRESULT hr = S_OK;
  136. hr = InitParams(pSource->m_cParams, pSource->m_pParamInfos);
  137. if (SUCCEEDED(hr))
  138. {
  139. DWORD dwIndex;
  140. for (dwIndex = 0; dwIndex < m_cParams; dwIndex++)
  141. {
  142. CCurveItem *pCurve = pSource->m_pCurveLists[dwIndex].GetHead();
  143. for (;pCurve;pCurve = pCurve->GetNext())
  144. {
  145. CCurveItem *pNew = new CCurveItem;
  146. if (!pNew)
  147. {
  148. return E_OUTOFMEMORY;
  149. }
  150. pNew->m_Envelope = pCurve->m_Envelope;
  151. m_pCurveLists[dwIndex].AddTail(pNew);
  152. }
  153. }
  154. }
  155. return hr;
  156. }
  157. inline float ValRange(float valToClip, float valMin, float valMax)
  158. {
  159. return valToClip < valMin
  160. ? valMin
  161. : (valToClip > valMax ? valMax : valToClip);
  162. }
  163. HRESULT CParamsManager::GetParamFloat(DWORD dwParamIndex, REFERENCE_TIME rtTime, float *pval)
  164. {
  165. HRESULT hr = S_OK;
  166. if (dwParamIndex >= m_cParams)
  167. return E_INVALIDARG;
  168. EnterCriticalSection(&m_ParamsCriticalSection);
  169. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  170. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  171. // if no points, then neutral value
  172. CCurveItem *pCurve = pList->GetHead();
  173. if (!pCurve)
  174. {
  175. *pval = pInfo->MParamInfo.mpdNeutralValue;
  176. LeaveCriticalSection(&m_ParamsCriticalSection);
  177. return S_OK;
  178. }
  179. // Find the curve during or before the requested time
  180. // If the time is during a curve, we will use that.
  181. // If not, we need the end value of the previous curve.
  182. // Our list keeps these in backwards order, so we are scanning from the
  183. // highest point in time backwards.
  184. for (;pCurve && pCurve->m_Envelope.rtStart > rtTime;pCurve = pCurve->GetNext());
  185. // If there is no pCurve, there was no curve prior to or during rtTime. Give up.
  186. if (!pCurve)
  187. {
  188. *pval = pInfo->MParamInfo.mpdNeutralValue;
  189. LeaveCriticalSection(&m_ParamsCriticalSection);
  190. return S_OK;
  191. }
  192. // Now, if pCurve ends before the requested time,
  193. // return the final value of pCurve, since that will hold until the start of the next curve.
  194. if (pCurve->m_Envelope.rtEnd < rtTime)
  195. {
  196. *pval = pCurve->m_Envelope.valEnd;
  197. LeaveCriticalSection(&m_ParamsCriticalSection);
  198. return S_OK;
  199. }
  200. // If we get this far, the curve must bound rtTime.
  201. if (pCurve->m_Envelope.iCurve & MP_CURVE_JUMP)
  202. {
  203. *pval = pCurve->m_Envelope.valEnd;
  204. LeaveCriticalSection(&m_ParamsCriticalSection);
  205. return S_OK;
  206. }
  207. REFERENCE_TIME rtTimeChange = pCurve->m_Envelope.rtEnd - pCurve->m_Envelope.rtStart;
  208. REFERENCE_TIME rtTimeIntermediate = rtTime - pCurve->m_Envelope.rtStart;
  209. float fltScalingX = static_cast<float>(rtTimeIntermediate) / rtTimeChange; // horizontal distance along curve between 0 and 1
  210. float fltScalingY; // height of curve at that point between 0 and 1 based on curve function
  211. switch (pCurve->m_Envelope.iCurve)
  212. {
  213. case MP_CURVE_SQUARE:
  214. fltScalingY = fltScalingX * fltScalingX;
  215. break;
  216. case MP_CURVE_INVSQUARE:
  217. fltScalingY = (float) sqrt(fltScalingX);
  218. break;
  219. case MP_CURVE_SINE:
  220. // �� Maybe we should have a lookup table here?
  221. fltScalingY = (float) (sin(fltScalingX * 3.1415926535 - (3.1415926535/2)) + 1) / 2;
  222. break;
  223. case MP_CURVE_LINEAR:
  224. default:
  225. fltScalingY = fltScalingX;
  226. }
  227. // Find out if we need to pull the start point from the previous curve,
  228. // the default neutral value, or the current curve.
  229. float fStartVal = pCurve->m_Envelope.valStart;
  230. if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_NEUTRALVAL)
  231. {
  232. fStartVal = pInfo->MParamInfo.mpdNeutralValue;
  233. }
  234. // Currentval, if it exists, will override neutralval.
  235. if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_CURRENTVAL)
  236. {
  237. // Take advantage of the fact that these are inserted in backwards order.
  238. // Scan for the previous curve that ends before this time.
  239. CCurveItem *pPrevious = pCurve->GetNext();
  240. for (;pPrevious && pPrevious->m_Envelope.rtEnd > rtTime;pPrevious = pPrevious->GetNext());
  241. if (pPrevious)
  242. {
  243. fStartVal = pPrevious->m_Envelope.valEnd;
  244. }
  245. }
  246. // Apply that scaling to the range of the actual points
  247. *pval = (pCurve->m_Envelope.valEnd - pCurve->m_Envelope.valStart) * fltScalingY + pCurve->m_Envelope.valStart;
  248. LeaveCriticalSection(&m_ParamsCriticalSection);
  249. return hr;
  250. }
  251. HRESULT CParamsManager::GetParamInt(DWORD dwParamIndex, REFERENCE_TIME rt, long *pval)
  252. {
  253. HRESULT hr = E_POINTER;
  254. if (pval)
  255. {
  256. float fVal;
  257. hr = GetParamFloat(dwParamIndex, rt, &fVal);
  258. if (SUCCEEDED(hr))
  259. {
  260. *pval = (long) (fVal + 1/2); // Round.
  261. }
  262. }
  263. return hr;
  264. }
  265. //////////////////////////////////////////////////////////////////////
  266. // IMediaParams
  267. HRESULT CParamsManager::GetParam(DWORD dwParamIndex, MP_DATA *pValue)
  268. {
  269. V_INAME(CParams::GetParam);
  270. V_PTR_WRITE(pValue, MP_DATA);
  271. if (dwParamIndex >= m_cParams)
  272. return E_INVALIDARG;
  273. EnterCriticalSection(&m_ParamsCriticalSection);
  274. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  275. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  276. // if no points, then neutral value
  277. CCurveItem *pCurve = pList->GetHead();
  278. if (pCurve)
  279. {
  280. *pValue = pCurve->m_Envelope.valEnd;
  281. }
  282. else
  283. {
  284. *pValue = pInfo->MParamInfo.mpdNeutralValue;
  285. }
  286. LeaveCriticalSection(&m_ParamsCriticalSection);
  287. return S_OK;
  288. }
  289. HRESULT CParamsManager::SetParam(DWORD dwParamIndex, MP_DATA value)
  290. {
  291. V_INAME(CParams::SetParam);
  292. if (dwParamIndex >= m_cParams)
  293. return E_INVALIDARG;
  294. EnterCriticalSection(&m_ParamsCriticalSection);
  295. m_fDirty = TRUE;
  296. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  297. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  298. // If we've already got a list, just force the most recent curve item to this value.
  299. // Otherwise, create a node and add it.
  300. CCurveItem *pCurve = pList->GetHead();
  301. if (!pCurve)
  302. {
  303. pCurve = new CCurveItem;
  304. if (pCurve)
  305. {
  306. pCurve->m_Envelope.rtStart = 0x8000000000000000; // Max negative.
  307. pCurve->m_Envelope.rtEnd = 0x7FFFFFFFFFFFFFFF; // Max positive.
  308. pCurve->m_Envelope.flags = 0;
  309. pList->AddHead(pCurve);
  310. }
  311. else
  312. {
  313. LeaveCriticalSection(&m_ParamsCriticalSection);
  314. return E_OUTOFMEMORY;
  315. }
  316. }
  317. pCurve->m_Envelope.valStart = value;
  318. pCurve->m_Envelope.valEnd = value;
  319. pCurve->m_Envelope.iCurve = MP_CURVE_JUMP;
  320. LeaveCriticalSection(&m_ParamsCriticalSection);
  321. return S_OK;
  322. }
  323. HRESULT CParamsManager::AddEnvelope(
  324. DWORD dwParamIndex,
  325. DWORD cPoints,
  326. MP_ENVELOPE_SEGMENT *ppEnvelope)
  327. {
  328. V_INAME(CParams::AddEnvelope);
  329. V_PTR_READ(ppEnvelope, *ppEnvelope);
  330. if (dwParamIndex >= m_cParams)
  331. return E_INVALIDARG;
  332. if (!m_pParamInfos)
  333. return DMUS_E_NOT_INIT;
  334. HRESULT hr = S_OK;
  335. EnterCriticalSection(&m_ParamsCriticalSection);
  336. m_fDirty = TRUE;
  337. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  338. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  339. DWORD dwCount;
  340. for (dwCount = 0; dwCount < cPoints; dwCount++)
  341. {
  342. CCurveItem *pCurve = new CCurveItem;
  343. if (!pCurve)
  344. {
  345. hr = E_OUTOFMEMORY;
  346. break;
  347. }
  348. pCurve->m_Envelope = ppEnvelope[dwCount];
  349. pCurve->m_Envelope.valEnd = ValRange(pCurve->m_Envelope.valEnd,
  350. pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  351. pCurve->m_Envelope.valStart = ValRange(pCurve->m_Envelope.valStart,
  352. pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  353. pList->AddHead(pCurve);
  354. }
  355. LeaveCriticalSection(&m_ParamsCriticalSection);
  356. return hr;
  357. }
  358. HRESULT CParamsManager::FlushEnvelope(
  359. DWORD dwParamIndex,
  360. REFERENCE_TIME refTimeStart,
  361. REFERENCE_TIME refTimeEnd)
  362. {
  363. if (dwParamIndex >= m_cParams)
  364. return E_INVALIDARG;
  365. if (!m_pParamInfos)
  366. return DMUS_E_NOT_INIT;
  367. if (refTimeStart >= refTimeEnd)
  368. return E_INVALIDARG;
  369. EnterCriticalSection(&m_ParamsCriticalSection);
  370. m_fDirty = TRUE;
  371. CCurveList *pList = &m_pCurveLists[dwParamIndex];
  372. ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  373. CCurveList TempList;
  374. CCurveItem *pCurve;
  375. while (pCurve = pList->RemoveHead())
  376. {
  377. if ((pCurve->m_Envelope.rtStart >= refTimeStart) &&
  378. (pCurve->m_Envelope.rtEnd <= refTimeEnd))
  379. {
  380. delete pCurve;
  381. }
  382. else
  383. {
  384. TempList.AddHead(pCurve);
  385. }
  386. }
  387. while (pCurve = TempList.RemoveHead())
  388. {
  389. pList->AddHead(pCurve);
  390. }
  391. LeaveCriticalSection(&m_ParamsCriticalSection);
  392. return S_OK;
  393. }
  394. HRESULT CParamsManager::SetTimeFormat(
  395. GUID guidTimeFormat,
  396. MP_TIMEDATA mpTimeData)
  397. {
  398. if (guidTimeFormat == GUID_TIME_REFERENCE)
  399. {
  400. m_fMusicTime = FALSE;
  401. }
  402. else if (guidTimeFormat == GUID_TIME_MUSIC)
  403. {
  404. m_fMusicTime = TRUE;
  405. }
  406. else
  407. {
  408. return E_INVALIDARG;
  409. }
  410. return S_OK;
  411. }