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.

296 lines
9.1 KiB

  1. // Swing.cpp : Implementation of CSwingTool
  2. //
  3. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved
  4. //
  5. #include "dmusicc.h"
  6. #include "dmusici.h"
  7. #include "debug.h"
  8. #include "swing.h"
  9. #include "toolhelp.h"
  10. CSwingTool::CSwingTool()
  11. {
  12. ParamInfo Params[DMUS_SWING_PARAMCOUNT] =
  13. {
  14. { DMUS_SWING_STRENGTH, MPT_INT,MP_CAPS_ALL,0,100,100,
  15. L"Percent",L"Strength",NULL }, // Strength - 100% by default
  16. };
  17. InitParams(DMUS_SWING_PARAMCOUNT,Params);
  18. m_fMusicTime = TRUE; // override default setting.
  19. }
  20. STDMETHODIMP_(ULONG) CSwingTool::AddRef()
  21. {
  22. return InterlockedIncrement(&m_cRef);
  23. }
  24. STDMETHODIMP_(ULONG) CSwingTool::Release()
  25. {
  26. if( 0 == InterlockedDecrement(&m_cRef) )
  27. {
  28. delete this;
  29. return 0;
  30. }
  31. return m_cRef;
  32. }
  33. STDMETHODIMP CSwingTool::QueryInterface(const IID &iid, void **ppv)
  34. {
  35. if (iid == IID_IUnknown || iid == IID_IDirectMusicTool || iid == IID_IDirectMusicTool8)
  36. {
  37. *ppv = static_cast<IDirectMusicTool8*>(this);
  38. }
  39. else if(iid == IID_IPersistStream)
  40. {
  41. *ppv = static_cast<IPersistStream*>(this);
  42. }
  43. else if(iid == IID_IDirectMusicSwingTool)
  44. {
  45. *ppv = static_cast<IDirectMusicSwingTool*>(this);
  46. }
  47. else if(iid == IID_IMediaParams)
  48. {
  49. *ppv = static_cast<IMediaParams*>(this);
  50. }
  51. else if(iid == IID_IMediaParamInfo)
  52. {
  53. *ppv = static_cast<IMediaParamInfo*>(this);
  54. }
  55. else if(iid == IID_ISpecifyPropertyPages)
  56. {
  57. *ppv = static_cast<ISpecifyPropertyPages*>(this);
  58. }
  59. else
  60. {
  61. *ppv = NULL;
  62. return E_NOINTERFACE;
  63. }
  64. AddRef();
  65. return S_OK;
  66. }
  67. //////////////////////////////////////////////////////////////////////
  68. // IPersistStream
  69. STDMETHODIMP CSwingTool::GetClassID(CLSID* pClassID)
  70. {
  71. if (pClassID)
  72. {
  73. *pClassID = CLSID_DirectMusicSwingTool;
  74. return S_OK;
  75. }
  76. return E_POINTER;
  77. }
  78. //////////////////////////////////////////////////////////////////////
  79. // IPersistStream Methods:
  80. STDMETHODIMP CSwingTool::IsDirty()
  81. {
  82. if (m_fDirty) return S_OK;
  83. else return S_FALSE;
  84. }
  85. STDMETHODIMP CSwingTool::Load(IStream* pStream)
  86. {
  87. EnterCriticalSection(&m_CrSec);
  88. DWORD dwChunkID;
  89. DWORD dwSize;
  90. HRESULT hr = pStream->Read(&dwChunkID, sizeof(dwChunkID), NULL);
  91. hr = pStream->Read(&dwSize, sizeof(dwSize), NULL);
  92. if(SUCCEEDED(hr) && (dwChunkID == FOURCC_SWING_CHUNK))
  93. {
  94. DMUS_IO_SWING_HEADER Header;
  95. memset(&Header,0,sizeof(Header));
  96. hr = pStream->Read(&Header, min(sizeof(Header),dwSize), NULL);
  97. if (SUCCEEDED(hr))
  98. {
  99. SetParam(DMUS_SWING_STRENGTH,(float) Header.dwStrength);
  100. }
  101. }
  102. m_fDirty = FALSE;
  103. LeaveCriticalSection(&m_CrSec);
  104. return hr;
  105. }
  106. STDMETHODIMP CSwingTool::Save(IStream* pStream, BOOL fClearDirty)
  107. {
  108. EnterCriticalSection(&m_CrSec);
  109. DWORD dwChunkID = FOURCC_SWING_CHUNK;
  110. DWORD dwSize = sizeof(DMUS_IO_SWING_HEADER);
  111. HRESULT hr = pStream->Write(&dwChunkID, sizeof(dwChunkID), NULL);
  112. if (SUCCEEDED(hr))
  113. {
  114. hr = pStream->Write(&dwSize, sizeof(dwSize), NULL);
  115. }
  116. if (SUCCEEDED(hr))
  117. {
  118. DMUS_IO_SWING_HEADER Header;
  119. GetParamInt(DMUS_SWING_STRENGTH,MAX_REF_TIME,(long *)&Header.dwStrength);
  120. hr = pStream->Write(&Header, sizeof(Header),NULL);
  121. }
  122. if (fClearDirty) m_fDirty = FALSE;
  123. LeaveCriticalSection(&m_CrSec);
  124. return hr;
  125. }
  126. STDMETHODIMP CSwingTool::GetSizeMax(ULARGE_INTEGER* pcbSize)
  127. {
  128. if (pcbSize == NULL)
  129. {
  130. return E_POINTER;
  131. }
  132. pcbSize->QuadPart = sizeof(DMUS_IO_SWING_HEADER) + 8; // Data plus RIFF header.
  133. return S_OK;
  134. }
  135. STDMETHODIMP CSwingTool::GetPages(CAUUID * pPages)
  136. {
  137. pPages->cElems = 1;
  138. pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  139. if (pPages->pElems == NULL)
  140. return E_OUTOFMEMORY;
  141. *(pPages->pElems) = CLSID_SwingPage;
  142. return NOERROR;
  143. }
  144. /////////////////////////////////////////////////////////////////
  145. // IDirectMusicTool
  146. STDMETHODIMP CSwingTool::ProcessPMsg( IDirectMusicPerformance* pPerf,
  147. DMUS_PMSG* pPMsg )
  148. {
  149. // returning S_FREE frees the message. If StampPMsg()
  150. // fails, there is no destination for this message so
  151. // free it.
  152. if(NULL == pPMsg->pGraph )
  153. {
  154. return DMUS_S_FREE;
  155. }
  156. if (FAILED(pPMsg->pGraph->StampPMsg(pPMsg)))
  157. {
  158. return DMUS_S_FREE;
  159. }
  160. // We need to know the time format so we can call GetParamInt() to read control parameters.
  161. REFERENCE_TIME rtTime;
  162. if (m_fMusicTime) rtTime = pPMsg->mtTime;
  163. else rtTime = pPMsg->rtTime;
  164. if( pPMsg->dwType == DMUS_PMSGT_NOTE )
  165. {
  166. DMUS_NOTE_PMSG *pNote = (DMUS_NOTE_PMSG *) pPMsg;
  167. IDirectMusicPerformance8 *pPerf8; // We'll need the DX8 interface to access ClonePMsg.
  168. if (SUCCEEDED(pPerf->QueryInterface(IID_IDirectMusicPerformance8,(void **)&pPerf8)))
  169. {
  170. long lStrength;
  171. GetParamInt(DMUS_SWING_STRENGTH,rtTime,&lStrength);
  172. DMUS_TIMESIGNATURE TimeSig;
  173. if (SUCCEEDED(pPerf8->GetParamEx(GUID_TimeSignature,pNote->dwVirtualTrackID,pNote->dwGroupID,DMUS_SEG_ANYTRACK,pNote->mtTime,NULL,&TimeSig)))
  174. {
  175. long lGrid = ((4 * 768) / TimeSig.bBeat) / TimeSig.wGridsPerBeat;
  176. if ((TimeSig.wGridsPerBeat == 3) || (TimeSig.wGridsPerBeat == 6) ||
  177. (TimeSig.wGridsPerBeat == 9) || (TimeSig.wGridsPerBeat == 12))
  178. {
  179. // This is already in a triplet feel, so work in reverse.
  180. // Adjust the timing, as set by the lStrength parameter.
  181. // lStrength is a range from 0 for no swing to 100 for full swing.
  182. // We are moving from grids 0,1,2,3,4,5... in triplet feel to grids
  183. // 0,1,2,4,5,6... in non-triplet feel.
  184. // So, the notes need to be adjusted in time in either direction.
  185. // When we change the time, we clear the DMUS_PMSGF_REFTIME flag,
  186. // telling the performance to recalculate the reference time stamp
  187. // in the event when it is requeued.
  188. static long lFromTriplet[12] = { 0,1,2,4,5,6,8,9,10,12,13,14 };
  189. if (pNote->bGrid < 12)
  190. {
  191. // Calculate the position we are moving to.
  192. long lTwoplet = ((lGrid * 3) / 4) * lFromTriplet[pNote->bGrid];
  193. // Calculate the position we are moving from.
  194. lGrid *= pNote->bGrid;
  195. // Calculate the new time. Note that we inverse strength since we are going from triplet.
  196. pNote->mtTime += ((100 - lStrength) * (lTwoplet - lGrid)) / 100;
  197. pNote->dwFlags &= ~DMUS_PMSGF_REFTIME;
  198. }
  199. }
  200. else if (TimeSig.wGridsPerBeat <= 16)
  201. {
  202. // Adjust the timing, as set by the lStrength parameter.
  203. // lStrength is a range from 0 for no swing to 100 for full swing.
  204. // We are moving from grids 0,1,2,3 in straight ahead feel to grids
  205. // 0,1,2 in triplet feel.
  206. // So, the notes need to be adjusted in time in either direction.
  207. // When we change the time, we clear the DMUS_PMSGF_REFTIME flag,
  208. // telling the performance to recalculate the reference time stamp
  209. // in the event when it is requeued.
  210. static long lToTriplet[16] = { 0,1,2,2,3,4,5,5,6,7,8,8,9,10,11,11 };
  211. if (pNote->bGrid < 16)
  212. {
  213. // Calculate the position we are moving to.
  214. long lTriplet = ((lGrid * 4) / 3) * lToTriplet[pNote->bGrid];
  215. // Calculate the position we are moving from.
  216. Trace(0,"%ld,%ld,%ld,%ld\t%ld,%ld,%ld\t",
  217. (long)TimeSig.bBeatsPerMeasure,(long)TimeSig.bBeat,(long)TimeSig.wGridsPerBeat,
  218. lGrid,(long)pNote->bBeat,(long)pNote->bGrid,(long)pNote->nOffset);
  219. lGrid *= pNote->bGrid;
  220. Trace(0,"%ld,%ld,%ld\n",lStrength,lTriplet,lGrid);
  221. pNote->mtTime += (lStrength * (lTriplet - lGrid)) / 100;
  222. pNote->dwFlags &= ~DMUS_PMSGF_REFTIME;
  223. }
  224. }
  225. }
  226. pPerf8->Release();
  227. }
  228. }
  229. return DMUS_S_REQUEUE;
  230. }
  231. STDMETHODIMP CSwingTool::Clone( IDirectMusicTool ** ppTool)
  232. {
  233. CSwingTool *pNew = new CSwingTool;
  234. if (pNew)
  235. {
  236. HRESULT hr = pNew->CopyParamsFromSource(this);
  237. if (SUCCEEDED(hr))
  238. {
  239. *ppTool = (IDirectMusicTool *) pNew;
  240. }
  241. else
  242. {
  243. delete pNew;
  244. }
  245. return hr;
  246. }
  247. else
  248. {
  249. return E_OUTOFMEMORY;
  250. }
  251. }
  252. STDMETHODIMP CSwingTool::SetStrength(DWORD dwStrength)
  253. {
  254. return SetParam(DMUS_SWING_STRENGTH,(float) dwStrength);
  255. }
  256. STDMETHODIMP CSwingTool::GetStrength(DWORD * pdwStrength)
  257. {
  258. return GetParamInt(DMUS_SWING_STRENGTH,MAX_REF_TIME,(long *) pdwStrength);
  259. }