Leaked source code of windows server 2003
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.

251 lines
6.5 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Base classes that implement aspects of a standard DirectMusic track.
  4. // Implementations for CPlayingTrack.
  5. //
  6. //////////////////////////////////////////////////////////////////////
  7. // Creation
  8. template<class T, class EventItem, class StateData>
  9. CPlayingTrack<T, EventItem, StateData>::CPlayingTrack(
  10. long *plModuleLockCounter,
  11. const CLSID &rclsid,
  12. bool fNeedsLoader,
  13. bool fPlayInvalidations)
  14. : m_dwValidate(0),
  15. m_fNeedsLoader(fNeedsLoader),
  16. m_fPlayInvalidations(fPlayInvalidations),
  17. CBasicTrack(plModuleLockCounter, rclsid)
  18. {
  19. }
  20. //////////////////////////////////////////////////////////////////////
  21. // IPersistStream
  22. // Function used to sort the event list according to trigger time.
  23. template<class EventItem>
  24. struct CmpStruct // �� shouldn't need this, but I had trouble getting a straight templated function to match the function pointer with the NT compiler. try again later with the new one.
  25. {
  26. static BOOL EventCompare(EventItem &ri1, EventItem &ri2)
  27. {
  28. return ri1.lTriggerTime < ri2.lTriggerTime;
  29. }
  30. };
  31. template<class T, class EventItem, class StateData>
  32. STDMETHODIMP
  33. CPlayingTrack<T, EventItem, StateData>::Load(IStream* pIStream)
  34. {
  35. V_INAME(CPlayingTrack::Load);
  36. V_INTERFACE(pIStream);
  37. HRESULT hr = S_OK;
  38. SmartRef::CritSec CS(&m_CriticalSection);
  39. // Clear the event list in case we're being reloaded.
  40. m_EventList.CleanUp();
  41. // Increment counter so the next play will update state data with the new list.
  42. ++m_dwValidate;
  43. // Get the loader if requested in constructor
  44. SmartRef::ComPtr<IDirectMusicLoader> scomLoader;
  45. if (m_fNeedsLoader)
  46. {
  47. IDirectMusicGetLoader *pIGetLoader;
  48. hr = pIStream->QueryInterface(IID_IDirectMusicGetLoader, reinterpret_cast<void**>(&pIGetLoader));
  49. if (FAILED(hr))
  50. return hr;
  51. hr = pIGetLoader->GetLoader(&scomLoader);
  52. pIGetLoader->Release();
  53. if (FAILED(hr))
  54. return hr;
  55. }
  56. SmartRef::RiffIter ri(pIStream);
  57. if (!ri)
  58. return ri.hr();
  59. hr = this->LoadRiff(ri, scomLoader);
  60. if (FAILED(hr))
  61. return hr;
  62. m_EventList.MergeSort(CmpStruct<EventItem>::EventCompare);
  63. return hr;
  64. }
  65. //////////////////////////////////////////////////////////////////////
  66. // IDirectMusicTrack
  67. template<class T, class EventItem, class StateData>
  68. STDMETHODIMP
  69. CPlayingTrack<T, EventItem, StateData>::InitPlay(
  70. IDirectMusicSegmentState *pSegmentState,
  71. IDirectMusicPerformance *pPerformance,
  72. void **ppStateData,
  73. DWORD dwTrackID,
  74. DWORD dwFlags)
  75. {
  76. V_INAME(CPlayingTrack::InitPlay);
  77. V_PTRPTR_WRITE(ppStateData);
  78. V_INTERFACE(pSegmentState);
  79. V_INTERFACE(pPerformance);
  80. SmartRef::CritSec CS(&m_CriticalSection);
  81. // Set up state data
  82. StateData *pStateData = new StateData;
  83. if (!pStateData)
  84. return E_OUTOFMEMORY;
  85. *ppStateData = pStateData;
  86. return S_OK;
  87. }
  88. template<class T, class EventItem, class StateData>
  89. STDMETHODIMP
  90. CPlayingTrack<T, EventItem, StateData>::EndPlay(void *pStateData)
  91. {
  92. V_INAME(CPlayingTrack::EndPlay);
  93. V_BUFPTR_WRITE(pStateData, sizeof(StateData));
  94. SmartRef::CritSec CS(&m_CriticalSection);
  95. StateData *pSD = static_cast<StateData *>(pStateData);
  96. delete pSD;
  97. return S_OK;
  98. }
  99. template<class T, class EventItem, class StateData>
  100. STDMETHODIMP
  101. CPlayingTrack<T, EventItem, StateData>::Clone(
  102. MUSIC_TIME mtStart,
  103. MUSIC_TIME mtEnd,
  104. IDirectMusicTrack** ppTrack)
  105. {
  106. V_INAME(CPlayingTrack::Clone);
  107. V_PTRPTR_WRITE(ppTrack);
  108. SmartRef::CritSec CS(&m_CriticalSection);
  109. HRESULT hr = S_OK;
  110. T *pTrack = new T(&hr);
  111. if (FAILED(hr))
  112. return hr;
  113. *ppTrack = pTrack;
  114. if (!pTrack)
  115. return E_OUTOFMEMORY;
  116. pTrack->AddRef();
  117. for (TListItem<EventItem> *pItem = m_EventList.GetHead();
  118. pItem;
  119. pItem = pItem->GetNext())
  120. {
  121. EventItem &ritem = pItem->GetItemValue();
  122. if (ritem.lTriggerTime >= mtEnd)
  123. break;
  124. if (ritem.lTriggerTime < mtStart)
  125. continue;
  126. TListItem<EventItem> *pNewItem = new TListItem<EventItem>;
  127. if (!pNewItem)
  128. {
  129. hr = E_OUTOFMEMORY;
  130. goto End;
  131. }
  132. EventItem &rnew = pNewItem->GetItemValue();
  133. hr = rnew.Clone(ritem, mtStart);
  134. if (FAILED(hr))
  135. {
  136. delete pNewItem;
  137. goto End;
  138. }
  139. pTrack->m_EventList.AddHead(pNewItem);
  140. }
  141. pTrack->m_EventList.Reverse();
  142. ++pTrack->m_dwValidate;
  143. End:
  144. if (FAILED(hr))
  145. pTrack->Release();
  146. return hr;
  147. }
  148. template<class T, class EventItem, class StateData>
  149. HRESULT
  150. CPlayingTrack<T, EventItem, StateData>::PlayMusicOrClock(
  151. void *pStateData,
  152. MUSIC_TIME mtStart,
  153. MUSIC_TIME mtEnd,
  154. MUSIC_TIME mtOffset,
  155. REFERENCE_TIME rtOffset,
  156. DWORD dwFlags,
  157. IDirectMusicPerformance* pPerf,
  158. IDirectMusicSegmentState* pSegSt,
  159. DWORD dwVirtualID,
  160. bool fClockTime)
  161. {
  162. V_INAME(CPlayingTrack::Play);
  163. V_BUFPTR_WRITE( pStateData, sizeof(StateData));
  164. V_INTERFACE(pPerf);
  165. V_INTERFACE(pSegSt);
  166. if (dwFlags & DMUS_TRACKF_PLAY_OFF)
  167. return S_OK;
  168. SmartRef::CritSec CS(&m_CriticalSection);
  169. StateData *pSD = static_cast<StateData *>(pStateData);
  170. TListItem<EventItem> *li = pSD->pCurrentEvent;
  171. // Seek through the event list to find the proper first event if
  172. // the event list pointed to by the state data has been reloaded
  173. // or if playback has made a jump to a different position in the track.
  174. if (m_dwValidate != pSD->dwValidate ||
  175. dwFlags & (DMUS_TRACKF_SEEK | DMUS_TRACKF_LOOP | DMUS_TRACKF_FLUSH))
  176. {
  177. assert(m_dwValidate != pSD->dwValidate || dwFlags & DMUS_TRACKF_SEEK); // by contract SEEK should be set whenever the other dwFlags are
  178. li = this->Seek(mtStart);
  179. pSD->dwValidate = m_dwValidate;
  180. }
  181. if (m_fPlayInvalidations || !(dwFlags & DMUS_TRACKF_FLUSH))
  182. {
  183. for (; li; li = li->GetNext())
  184. {
  185. EventItem &rinfo = li->GetItemValue();
  186. if (rinfo.lTriggerTime < mtStart) // this can happen if DMUS_TRACKF_PLAY_OFF was set and the seek pointer remains at events from the past
  187. continue;
  188. if (rinfo.lTriggerTime >= mtEnd)
  189. break;
  190. if (FAILED(this->PlayItem(rinfo, *pSD, pPerf, pSegSt, dwVirtualID, mtOffset, rtOffset, fClockTime)))
  191. {
  192. // Returning an error from Play is not allowed. Just ignore it and assert
  193. // so we would detect this while testing.
  194. assert(false);
  195. continue;
  196. }
  197. }
  198. }
  199. pSD->pCurrentEvent = li;
  200. return li ? S_OK : DMUS_S_END;
  201. }
  202. template<class T, class EventItem, class StateData>
  203. TListItem<EventItem> *
  204. CPlayingTrack<T, EventItem, StateData>::Seek(MUSIC_TIME mtStart)
  205. {
  206. TListItem<EventItem> *li;
  207. for (li = m_EventList.GetHead();
  208. li && li->GetItemValue().lTriggerTime < mtStart;
  209. li = li->GetNext())
  210. {}
  211. return li;
  212. }