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.

322 lines
11 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Implementation of CAutDirectMusicPerformance.
  4. //
  5. #include "stdinc.h"
  6. #include "autperformance.h"
  7. #include <limits>
  8. #include "dmusicf.h"
  9. const WCHAR CAutDirectMusicPerformance::ms_wszClassName[] = L"Performance";
  10. //////////////////////////////////////////////////////////////////////
  11. // Method Names/DispIDs
  12. const DISPID DMPDISP_SetMasterTempo = 1;
  13. const DISPID DMPDISP_GetMasterTempo = 2;
  14. const DISPID DMPDISP_SetMasterVolume = 3;
  15. const DISPID DMPDISP_GetMasterVolume = 4;
  16. const DISPID DMPDISP_SetMasterGrooveLevel = 5;
  17. const DISPID DMPDISP_GetMasterGrooveLevel = 6;
  18. const DISPID DMPDISP_SetMasterTranspose = 7;
  19. const DISPID DMPDISP_GetMasterTranspose = 8;
  20. const DISPID DMPDISP_Trace = 9;
  21. const DISPID DMPDISP_Rand = 10;
  22. const AutDispatchMethod CAutDirectMusicPerformance::ms_Methods[] =
  23. {
  24. // dispid, name,
  25. // return: type, (opt), (iid),
  26. // parm 1: type, opt, iid,
  27. // parm 2: type, opt, iid,
  28. // ...
  29. // ADT_None
  30. { DMPDISP_SetMasterTempo, L"SetMasterTempo",
  31. ADPARAM_NORETURN,
  32. ADT_Long, false, &IID_NULL, // tempo!New value for master tempo scaling factor as a percentage. For example, 50 would halve the tempo and 200 would double it.
  33. ADT_None },
  34. /// Calls IDirectMusicPerformance::SetGlobalParam(GUID_PerfMasterTempo, tempo / 100, sizeof(float)).
  35. { DMPDISP_GetMasterTempo, L"GetMasterTempo",
  36. ADT_Long, true, &IID_NULL, // Current master tempo scaling factor as a percentage.
  37. ADT_None },
  38. /// Calls IDirectMusicPerformance::GetGlobalParam(GUID_PerfMasterTempo, X, sizeof(float)) and returns X * 100.
  39. { DMPDISP_SetMasterVolume, L"SetMasterVolume",
  40. ADPARAM_NORETURN,
  41. ADT_Long, false, &IID_NULL, // volume!New value for master volume attenuation.
  42. ADT_Long, true, &IID_NULL, // duration
  43. ADT_None },
  44. /// Calls IDirectMusicPerformance::SetGlobalParam(GUID_PerfMasterVolume, volume, sizeof(long)).
  45. /// Range is 100th of a dB. 0 is full volume.
  46. { DMPDISP_GetMasterVolume, L"GetMasterVolume",
  47. ADT_Long, true, &IID_NULL, // Current value of master volume attenuation.
  48. ADT_None },
  49. /// Calls IDirectMusicPerformance::GetGlobalParam(GUID_PerfMasterVolume, X, sizeof(long)) and returns X.
  50. { DMPDISP_SetMasterGrooveLevel, L"SetMasterGrooveLevel",
  51. ADPARAM_NORETURN,
  52. ADT_Long, false, &IID_NULL, // groove level!New value for the global groove level, which is added to the level in the command track.
  53. ADT_None },
  54. { DMPDISP_GetMasterGrooveLevel, L"GetMasterGrooveLevel",
  55. ADT_Long, true, &IID_NULL, // Current value of the global groove level, which is added to the level in the command track.
  56. ADT_None },
  57. { DMPDISP_SetMasterTranspose, L"SetMasterTranspose",
  58. ADPARAM_NORETURN,
  59. ADT_Long, false, &IID_NULL, // transpose!Number of semitones to transpose everything.
  60. ADT_None },
  61. { DMPDISP_GetMasterTranspose, L"GetMasterTranspose",
  62. ADT_Long, true, &IID_NULL, // Current global transposition (number of semitones).
  63. ADT_None },
  64. { DMPDISP_Trace, L"Trace",
  65. ADPARAM_NORETURN,
  66. ADT_Bstr, false, &IID_NULL, // string!text to output to testing log
  67. ADT_None },
  68. /// This allocates, stamps, and sends a DMUS_LYRIC_PMSG with the following fields:
  69. /// <ul>
  70. /// <li> dwPChannel = channel
  71. /// <li> dwVirtualTrackID = 0
  72. /// <li> dwGroupID = -1
  73. /// <li> mtTime = GetTime(X, 0) is called and X * 10000 is used
  74. /// <li> dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME
  75. /// <li> dwType = DMUS_PMSGT_SCRIPTLYRIC
  76. /// <li> wszString = string
  77. /// </ul>
  78. /// This is used to send text to a trace log for debugging purposes. Less commonly, a script could be
  79. /// running in an application that listens and reacts to the script's trace output.
  80. { DMPDISP_Rand, L"Rand",
  81. ADT_Long, true, &IID_NULL, // Returns a randomly-generated number
  82. ADT_Long, false, &IID_NULL, // Max value--returned number will be between 1 and this max. Cannot be zero or negative.
  83. ADT_None },
  84. { DISPID_UNKNOWN }
  85. };
  86. const DispatchHandlerEntry<CAutDirectMusicPerformance> CAutDirectMusicPerformance::ms_Handlers[] =
  87. {
  88. { DMPDISP_SetMasterTempo, SetMasterTempo },
  89. { DMPDISP_GetMasterTempo, GetMasterTempo },
  90. { DMPDISP_SetMasterVolume, SetMasterVolume },
  91. { DMPDISP_GetMasterVolume, GetMasterVolume },
  92. { DMPDISP_SetMasterGrooveLevel, SetMasterGrooveLevel },
  93. { DMPDISP_GetMasterGrooveLevel, GetMasterGrooveLevel },
  94. { DMPDISP_SetMasterTranspose, SetMasterTranspose },
  95. { DMPDISP_GetMasterTranspose, GetMasterTranspose },
  96. { DMPDISP_Trace, _Trace },
  97. { DMPDISP_Rand, Rand },
  98. { DISPID_UNKNOWN }
  99. };
  100. //////////////////////////////////////////////////////////////////////
  101. // Creation
  102. CAutDirectMusicPerformance::CAutDirectMusicPerformance(
  103. IUnknown* pUnknownOuter,
  104. const IID& iid,
  105. void** ppv,
  106. HRESULT *phr)
  107. : BaseImpPerf(pUnknownOuter, iid, ppv, phr),
  108. m_nTranspose(0),
  109. m_nVolume(0)
  110. {
  111. // set the random seed used by the Rand method
  112. m_lRand = GetTickCount();
  113. *phr = m_pITarget->QueryInterface(IID_IDirectMusicGraph, reinterpret_cast<void**>(&m_scomGraph));
  114. if (SUCCEEDED(*phr))
  115. {
  116. // Due to the aggregation contract, our object is wholely contained in the lifetime of
  117. // the outer object and we shouldn't hold any references to it.
  118. ULONG ulCheck = m_pITarget->Release();
  119. assert(ulCheck);
  120. }
  121. }
  122. HRESULT
  123. CAutDirectMusicPerformance::CreateInstance(
  124. IUnknown* pUnknownOuter,
  125. const IID& iid,
  126. void** ppv)
  127. {
  128. HRESULT hr = S_OK;
  129. CAutDirectMusicPerformance *pInst = new CAutDirectMusicPerformance(pUnknownOuter, iid, ppv, &hr);
  130. if (FAILED(hr))
  131. {
  132. delete pInst;
  133. return hr;
  134. }
  135. if (pInst == NULL)
  136. return E_OUTOFMEMORY;
  137. return hr;
  138. }
  139. //////////////////////////////////////////////////////////////////////
  140. // Automation methods
  141. HRESULT
  142. CAutDirectMusicPerformance::SetMasterTempo(AutDispatchDecodedParams *paddp)
  143. {
  144. LONG lTempo = paddp->params[0].lVal;
  145. float fltTempo = ConvertToTempo(lTempo);
  146. if (fltTempo < DMUS_MASTERTEMPO_MIN)
  147. fltTempo = DMUS_MASTERTEMPO_MIN;
  148. else if (fltTempo > DMUS_MASTERTEMPO_MAX)
  149. fltTempo = DMUS_MASTERTEMPO_MAX;
  150. return m_pITarget->SetGlobalParam(GUID_PerfMasterTempo, &fltTempo, sizeof(float));
  151. }
  152. HRESULT
  153. CAutDirectMusicPerformance::GetMasterTempo(AutDispatchDecodedParams *paddp)
  154. {
  155. LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn);
  156. if (!plRet)
  157. return S_OK;
  158. float fltTempo = 1; // default value is 1 (multiplicative identity)
  159. HRESULT hr = this->GetMasterParam(GUID_PerfMasterTempo, &fltTempo, sizeof(float));
  160. if (SUCCEEDED(hr))
  161. *plRet = ConvertFromTempo(fltTempo);
  162. return hr;
  163. }
  164. HRESULT
  165. CAutDirectMusicPerformance::SetMasterVolume(AutDispatchDecodedParams *paddp)
  166. {
  167. if (!m_scomGraph)
  168. {
  169. assert(false);
  170. return E_FAIL;
  171. }
  172. LONG lVol = paddp->params[0].lVal;
  173. LONG lDuration = paddp->params[1].lVal;
  174. return SendVolumePMsg(lVol, lDuration, DMUS_PCHANNEL_BROADCAST_PERFORMANCE, m_scomGraph, m_pITarget, &m_nVolume);
  175. }
  176. HRESULT
  177. CAutDirectMusicPerformance::GetMasterVolume(AutDispatchDecodedParams *paddp)
  178. {
  179. LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn);
  180. if (plRet)
  181. *plRet = m_nVolume;
  182. return S_OK;
  183. }
  184. HRESULT
  185. CAutDirectMusicPerformance::SetMasterGrooveLevel(AutDispatchDecodedParams *paddp)
  186. {
  187. LONG lGroove = paddp->params[0].lVal;
  188. char chGroove = ClipLongRangeToType<char>(lGroove, char());
  189. return m_pITarget->SetGlobalParam(GUID_PerfMasterGrooveLevel, reinterpret_cast<void*>(&chGroove), sizeof(char));
  190. }
  191. HRESULT
  192. CAutDirectMusicPerformance::GetMasterGrooveLevel(AutDispatchDecodedParams *paddp)
  193. {
  194. LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn);
  195. if (!plRet)
  196. return S_OK;
  197. char chGroove = 0; // default value is 0 (additive identity)
  198. HRESULT hr = this->GetMasterParam(GUID_PerfMasterGrooveLevel, reinterpret_cast<void*>(&chGroove), sizeof(char));
  199. if (SUCCEEDED(hr))
  200. *plRet = chGroove;
  201. return hr;
  202. }
  203. HRESULT
  204. CAutDirectMusicPerformance::SetMasterTranspose(AutDispatchDecodedParams *paddp)
  205. {
  206. LONG lTranspose = paddp->params[0].lVal;
  207. short nTranspose = ClipLongRangeToType<short>(lTranspose, short());
  208. SmartRef::PMsg<DMUS_TRANSPOSE_PMSG> pmsg(m_pITarget);
  209. HRESULT hr = pmsg.hr();
  210. if FAILED(hr)
  211. return hr;
  212. // Generic PMSG stuff
  213. hr = m_pITarget->GetTime(&pmsg.p->rtTime, NULL);
  214. if (FAILED(hr))
  215. return hr;
  216. pmsg.p->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME | DMUS_PMSGF_DX8;
  217. pmsg.p->dwType = DMUS_PMSGT_TRANSPOSE;
  218. pmsg.p->dwPChannel = DMUS_PCHANNEL_BROADCAST_PERFORMANCE;
  219. pmsg.p->dwVirtualTrackID = 0;
  220. pmsg.p->dwGroupID = -1;
  221. // Transpose PMSG stuff
  222. pmsg.p->nTranspose = nTranspose;
  223. pmsg.p->wMergeIndex = 0xFFFF; // �� special merge index so this won't get stepped on. is a big number OK? define a constant for this value?
  224. pmsg.StampAndSend(m_scomGraph);
  225. hr = pmsg.hr();
  226. if (SUCCEEDED(hr))
  227. m_nTranspose = nTranspose;
  228. return hr;
  229. }
  230. HRESULT
  231. CAutDirectMusicPerformance::GetMasterTranspose(AutDispatchDecodedParams *paddp)
  232. {
  233. LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn);
  234. if (plRet)
  235. *plRet = m_nTranspose;
  236. return S_OK;
  237. }
  238. HRESULT
  239. CAutDirectMusicPerformance::_Trace(AutDispatchDecodedParams *paddp)
  240. {
  241. BSTR bstr = paddp->params[0].bstrVal;
  242. int cwch = wcslen(bstr);
  243. SmartRef::PMsg<DMUS_LYRIC_PMSG> pmsg(m_pITarget, cwch * sizeof(WCHAR));
  244. HRESULT hr = pmsg.hr();
  245. if (FAILED(hr))
  246. return hr;
  247. // Generic PMSG stuff
  248. hr = m_pITarget->GetTime(&pmsg.p->rtTime, NULL);
  249. if (FAILED(hr))
  250. return hr;
  251. pmsg.p->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME;
  252. pmsg.p->dwType = DMUS_PMSGT_SCRIPTLYRIC;
  253. pmsg.p->dwPChannel = 0;
  254. pmsg.p->dwVirtualTrackID = 0;
  255. pmsg.p->dwGroupID = -1;
  256. // Lyric PMSG stuff
  257. wcscpy(pmsg.p->wszString, bstr);
  258. pmsg.StampAndSend(m_scomGraph);
  259. return pmsg.hr();
  260. }
  261. HRESULT
  262. CAutDirectMusicPerformance::Rand(AutDispatchDecodedParams *paddp)
  263. {
  264. LONG *plRet = reinterpret_cast<LONG*>(paddp->pvReturn);
  265. LONG lMax = paddp->params[0].lVal;
  266. if (lMax < 1 || lMax > 0x7fff)
  267. return E_INVALIDARG;
  268. // Use random number generation lifted from the standard library's rand.c. We don't just
  269. // use the rand function because the multithreaded library has a per-thread random chain,
  270. // but this function is called from various threads and it would be difficult to manage
  271. // getting them seeded. Generates pseudo-random numbers 0 through 32767.
  272. long lRand = ((m_lRand = m_lRand * 214013L + 2531011L) >> 16) & 0x7fff;
  273. if (plRet)
  274. *plRet = lRand % lMax + 1; // trim to the requested range [1,lMax]
  275. return S_OK;
  276. }
  277. HRESULT
  278. CAutDirectMusicPerformance::GetMasterParam(const GUID &guid, void *pParam, DWORD dwSize)
  279. {
  280. HRESULT hr = m_pITarget->GetGlobalParam(guid, pParam, dwSize);
  281. if (SUCCEEDED(hr) || hr == E_INVALIDARG) // E_INVALIDARG is the performance's polite way of telling us the param hasn't been set yet
  282. return S_OK;
  283. return hr;
  284. }