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.

317 lines
9.5 KiB

  1. // Transpose.cpp : Implementation of CTransposeTool
  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 "transpose.h"
  9. #include "toolhelp.h"
  10. // We keep a default chord of C7 in the scale of C, in case there is no chord track
  11. // at the time an in scale transposition is requested.
  12. DMUS_CHORD_KEY CTransposeTool::m_gDefaultChord;
  13. CTransposeTool::CTransposeTool()
  14. {
  15. ParamInfo Params[DMUS_TRANSPOSE_PARAMCOUNT] =
  16. {
  17. { DMUS_TRANSPOSE_AMOUNT, MPT_INT,MP_CAPS_ALL,-24,24,0,
  18. L"Intervals",L"Transpose",NULL}, // Tranpose - none by default
  19. { DMUS_TRANSPOSE_TYPE, MPT_ENUM,MP_CAPS_ALL,
  20. DMUS_TRANSPOSET_LINEAR,DMUS_TRANSPOSET_SCALE,DMUS_TRANSPOSET_SCALE,
  21. L"",L"Type",L"Linear,In Scale"} // Type - transpose in scale by default
  22. };
  23. InitParams(DMUS_TRANSPOSE_PARAMCOUNT,Params);
  24. m_fMusicTime = TRUE; // override default setting.
  25. wcscpy(m_gDefaultChord.wszName, L"M7");
  26. m_gDefaultChord.wMeasure = 0;
  27. m_gDefaultChord.bBeat = 0;
  28. m_gDefaultChord.bSubChordCount = 1;
  29. m_gDefaultChord.bKey = 12;
  30. m_gDefaultChord.dwScale = 0xab5ab5; // default scale is C Major
  31. m_gDefaultChord.bFlags = 0;
  32. for (int n = 0; n < DMUS_MAXSUBCHORD; n++)
  33. {
  34. m_gDefaultChord.SubChordList[n].dwChordPattern = 0x891; // default chord is major 7
  35. m_gDefaultChord.SubChordList[n].dwScalePattern = 0xab5ab5; // default scale is C Major
  36. m_gDefaultChord.SubChordList[n].dwInversionPoints = 0xffffff;
  37. m_gDefaultChord.SubChordList[n].dwLevels = 0xffffffff;
  38. m_gDefaultChord.SubChordList[n].bChordRoot = 12; // 2C
  39. m_gDefaultChord.SubChordList[n].bScaleRoot = 0;
  40. }
  41. }
  42. STDMETHODIMP_(ULONG) CTransposeTool::AddRef()
  43. {
  44. return InterlockedIncrement(&m_cRef);
  45. }
  46. STDMETHODIMP_(ULONG) CTransposeTool::Release()
  47. {
  48. if( 0 == InterlockedDecrement(&m_cRef) )
  49. {
  50. delete this;
  51. return 0;
  52. }
  53. return m_cRef;
  54. }
  55. STDMETHODIMP CTransposeTool::QueryInterface(const IID &iid, void **ppv)
  56. {
  57. if (iid == IID_IUnknown || iid == IID_IDirectMusicTool || iid == IID_IDirectMusicTool8)
  58. {
  59. *ppv = static_cast<IDirectMusicTool8*>(this);
  60. }
  61. else if(iid == IID_IPersistStream)
  62. {
  63. *ppv = static_cast<IPersistStream*>(this);
  64. }
  65. else if(iid == IID_IDirectMusicTransposeTool)
  66. {
  67. *ppv = static_cast<IDirectMusicTransposeTool*>(this);
  68. }
  69. else if(iid == IID_IMediaParams)
  70. {
  71. *ppv = static_cast<IMediaParams*>(this);
  72. }
  73. else if(iid == IID_IMediaParamInfo)
  74. {
  75. *ppv = static_cast<IMediaParamInfo*>(this);
  76. }
  77. else if(iid == IID_ISpecifyPropertyPages)
  78. {
  79. *ppv = static_cast<ISpecifyPropertyPages*>(this);
  80. }
  81. else
  82. {
  83. *ppv = NULL;
  84. return E_NOINTERFACE;
  85. }
  86. AddRef();
  87. return S_OK;
  88. }
  89. //////////////////////////////////////////////////////////////////////
  90. // IPersistStream
  91. STDMETHODIMP CTransposeTool::GetClassID(CLSID* pClassID)
  92. {
  93. if (pClassID)
  94. {
  95. *pClassID = CLSID_DirectMusicTransposeTool;
  96. return S_OK;
  97. }
  98. return E_POINTER;
  99. }
  100. //////////////////////////////////////////////////////////////////////
  101. // IPersistStream Methods:
  102. STDMETHODIMP CTransposeTool::IsDirty()
  103. {
  104. if (m_fDirty) return S_OK;
  105. else return S_FALSE;
  106. }
  107. STDMETHODIMP CTransposeTool::Load(IStream* pStream)
  108. {
  109. EnterCriticalSection(&m_CrSec);
  110. DWORD dwChunkID;
  111. DWORD dwSize;
  112. HRESULT hr = pStream->Read(&dwChunkID, sizeof(dwChunkID), NULL);
  113. hr = pStream->Read(&dwSize, sizeof(dwSize), NULL);
  114. if(SUCCEEDED(hr) && (dwChunkID == FOURCC_TRANSPOSE_CHUNK))
  115. {
  116. DMUS_IO_TRANSPOSE_HEADER Header;
  117. memset(&Header,0,sizeof(Header));
  118. hr = pStream->Read(&Header, min(sizeof(Header),dwSize), NULL);
  119. if (SUCCEEDED(hr))
  120. {
  121. SetParam(DMUS_TRANSPOSE_AMOUNT,(float) Header.lTranspose);
  122. SetParam(DMUS_TRANSPOSE_TYPE,(float) Header.dwType);
  123. }
  124. }
  125. m_fDirty = FALSE;
  126. LeaveCriticalSection(&m_CrSec);
  127. return hr;
  128. }
  129. STDMETHODIMP CTransposeTool::Save(IStream* pStream, BOOL fClearDirty)
  130. {
  131. EnterCriticalSection(&m_CrSec);
  132. DWORD dwChunkID = FOURCC_TRANSPOSE_CHUNK;
  133. DWORD dwSize = sizeof(DMUS_IO_TRANSPOSE_HEADER);
  134. HRESULT hr = pStream->Write(&dwChunkID, sizeof(dwChunkID), NULL);
  135. if (SUCCEEDED(hr))
  136. {
  137. hr = pStream->Write(&dwSize, sizeof(dwSize), NULL);
  138. }
  139. if (SUCCEEDED(hr))
  140. {
  141. DMUS_IO_TRANSPOSE_HEADER Header;
  142. GetParamInt(DMUS_TRANSPOSE_AMOUNT,MAX_REF_TIME,(long *) &Header.lTranspose);
  143. GetParamInt(DMUS_TRANSPOSE_TYPE,MAX_REF_TIME,(long *) &Header.dwType);
  144. hr = pStream->Write(&Header, sizeof(Header),NULL);
  145. }
  146. if (fClearDirty) m_fDirty = FALSE;
  147. LeaveCriticalSection(&m_CrSec);
  148. return hr;
  149. }
  150. STDMETHODIMP CTransposeTool::GetSizeMax(ULARGE_INTEGER* pcbSize)
  151. {
  152. if (pcbSize == NULL)
  153. {
  154. return E_POINTER;
  155. }
  156. pcbSize->QuadPart = sizeof(DMUS_IO_TRANSPOSE_HEADER) + 8; // Data plus RIFF header.
  157. return S_OK;
  158. }
  159. STDMETHODIMP CTransposeTool::GetPages(CAUUID * pPages)
  160. {
  161. pPages->cElems = 1;
  162. pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  163. if (pPages->pElems == NULL)
  164. return E_OUTOFMEMORY;
  165. *(pPages->pElems) = CLSID_TransposePage;
  166. return NOERROR;
  167. }
  168. /////////////////////////////////////////////////////////////////
  169. // IDirectMusicTool
  170. STDMETHODIMP CTransposeTool::ProcessPMsg( IDirectMusicPerformance* pPerf,
  171. DMUS_PMSG* pPMsg )
  172. {
  173. // returning S_FREE frees the message. If StampPMsg()
  174. // fails, there is no destination for this message so
  175. // free it.
  176. if(NULL == pPMsg->pGraph )
  177. {
  178. return DMUS_S_FREE;
  179. }
  180. if (FAILED(pPMsg->pGraph->StampPMsg(pPMsg)))
  181. {
  182. return DMUS_S_FREE;
  183. }
  184. // Only transpose notes that are not on the drum pChannel.
  185. if( (pPMsg->dwType == DMUS_PMSGT_NOTE ) && ((pPMsg->dwPChannel & 0xF) != 0x9))
  186. {
  187. // We need to know the time format so we can call GetParamInt() to read control parameters.
  188. REFERENCE_TIME rtTime;
  189. if (m_fMusicTime) rtTime = pPMsg->mtTime;
  190. else rtTime = pPMsg->rtTime;
  191. DMUS_NOTE_PMSG *pNote = (DMUS_NOTE_PMSG *) pPMsg;
  192. long lTranspose, lType;
  193. long lNote = pNote->bMidiValue;
  194. GetParamInt(DMUS_TRANSPOSE_AMOUNT,rtTime,&lTranspose);
  195. GetParamInt(DMUS_TRANSPOSE_TYPE,rtTime,&lType);
  196. if (lType == DMUS_TRANSPOSET_LINEAR)
  197. {
  198. lNote += lTranspose;
  199. while (lNote < 0) lNote += 12;
  200. while (lNote > 127) lNote -= 12;
  201. pNote->bMidiValue = (BYTE) lNote;
  202. }
  203. else
  204. {
  205. IDirectMusicPerformance8 *pPerf8;
  206. if (SUCCEEDED(pPerf->QueryInterface(IID_IDirectMusicPerformance8,(void **) &pPerf8)))
  207. {
  208. DMUS_CHORD_KEY Chord;
  209. DMUS_CHORD_KEY *pChord = &Chord;
  210. if (FAILED(pPerf8->GetParamEx(GUID_ChordParam,pNote->dwVirtualTrackID,
  211. pNote->dwGroupID,0,pNote->mtTime - pNote->nOffset, NULL, pChord)))
  212. {
  213. // Couldn't find an active scale, use major scale instead.
  214. pChord = &m_gDefaultChord;
  215. }
  216. WORD wVal;
  217. // First, use the current chord & scale to convert the note's midi value into scale position.
  218. if (SUCCEEDED(pPerf->MIDIToMusic(pNote->bMidiValue ,pChord,DMUS_PLAYMODE_PEDALPOINT,pNote->bSubChordLevel,&wVal)))
  219. {
  220. // Scale position is octave position * 7 plus chord position * 2 plus the scale position.
  221. long lScalePosition = (((wVal & 0xF000) >> 12) * 7) + (((wVal & 0xF00) >> 8) * 2) + ((wVal & 0xF0) >> 4);
  222. // Now that we are looking at scale position, we can add the transposition.
  223. lScalePosition += lTranspose;
  224. // Make sure we don't wrap around.
  225. while (lScalePosition < 0) lScalePosition += 7;
  226. // A high MIDI value of 127 translates to scale position 74.
  227. while (lScalePosition > 74) lScalePosition -= 7;
  228. wVal &= 0x000F; // Keep only the accidental.
  229. // Now, insert the values back in. Start with chord.
  230. wVal |= ((lScalePosition / 7) << 12);
  231. // Then, scale position.
  232. wVal |= ((lScalePosition % 7) << 4);
  233. pPerf->MusicToMIDI(wVal,pChord,DMUS_PLAYMODE_PEDALPOINT,
  234. pNote->bSubChordLevel,&pNote->bMidiValue);
  235. }
  236. pPerf8->Release();
  237. }
  238. }
  239. }
  240. return DMUS_S_REQUEUE;
  241. }
  242. STDMETHODIMP CTransposeTool::Clone( IDirectMusicTool ** ppTool)
  243. {
  244. CTransposeTool *pNew = new CTransposeTool;
  245. if (pNew)
  246. {
  247. HRESULT hr = pNew->CopyParamsFromSource(this);
  248. if (SUCCEEDED(hr))
  249. {
  250. *ppTool = (IDirectMusicTool *) pNew;
  251. }
  252. else
  253. {
  254. delete pNew;
  255. }
  256. return hr;
  257. }
  258. else
  259. {
  260. return E_OUTOFMEMORY;
  261. }
  262. }
  263. STDMETHODIMP CTransposeTool::SetTranspose(long lTranpose)
  264. {
  265. return SetParam(DMUS_TRANSPOSE_AMOUNT,(float) lTranpose);
  266. }
  267. STDMETHODIMP CTransposeTool::SetType(DWORD dwType)
  268. {
  269. return SetParam(DMUS_TRANSPOSE_TYPE,(float) dwType);
  270. }
  271. #define MAX_REF_TIME 0x7FFFFFFFFFFFFFFF
  272. STDMETHODIMP CTransposeTool::GetTranspose(long * plTranspose)
  273. {
  274. return GetParamInt(DMUS_TRANSPOSE_AMOUNT,MAX_REF_TIME, plTranspose);
  275. }
  276. STDMETHODIMP CTransposeTool::GetType(DWORD * pdwType)
  277. {
  278. return GetParamInt(DMUS_TRANSPOSE_TYPE,MAX_REF_TIME,(long *) pdwType);
  279. }