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.

223 lines
6.9 KiB

  1. //
  2. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  3. //
  4. // Declaration of CLyricsTrack.
  5. //
  6. #include "dmime.h"
  7. #include "lyrictrk.h"
  8. #include "..\shared\Validate.h"
  9. #include "dmperf.h"
  10. #include "miscutil.h"
  11. //////////////////////////////////////////////////////////////////////
  12. // Load
  13. HRESULT
  14. CLyricsTrack::LoadRiff(SmartRef::RiffIter &ri, IDirectMusicLoader *pIDMLoader)
  15. {
  16. struct LocalFunction
  17. {
  18. // Helper used by the LoadRiff function when we expected to find something
  19. // but a RiffIter becomes false. In this case, if it has a success HR
  20. // indicating there were no more items then we return DMUS_E_INVALID_LYRICSTRACK
  21. // because the stream didn't contain the data we expected. If it has a
  22. // failure hr, it was unable to read from the stream and we return its HR.
  23. static HRESULT HrFailOK(const SmartRef::RiffIter &ri)
  24. {
  25. HRESULT hr = ri.hr();
  26. return SUCCEEDED(hr) ? DMUS_E_INVALID_LYRICSTRACK : hr;
  27. }
  28. };
  29. // find <lyrt>
  30. if (!ri.Find(SmartRef::RiffIter::List, DMUS_FOURCC_LYRICSTRACK_LIST))
  31. {
  32. #ifdef DBG
  33. if (SUCCEEDED(ri.hr()))
  34. {
  35. Trace(1, "Error: Unable to load lyric track: List 'lyrt' not found.\n");
  36. }
  37. #endif
  38. return LocalFunction::HrFailOK(ri);
  39. }
  40. // find <lyrl>
  41. SmartRef::RiffIter riTrackForm = ri.Descend();
  42. if (!riTrackForm)
  43. return riTrackForm.hr();
  44. if (!riTrackForm.Find(SmartRef::RiffIter::List, DMUS_FOURCC_LYRICSTRACKEVENTS_LIST))
  45. {
  46. #ifdef DBG
  47. if (SUCCEEDED(riTrackForm.hr()))
  48. {
  49. Trace(1, "Error: Unable to load lyric track: List 'lyrl' not found.\n");
  50. }
  51. #endif
  52. return LocalFunction::HrFailOK(riTrackForm);
  53. }
  54. // process each event <lyre>
  55. SmartRef::RiffIter riEvent = riTrackForm.Descend();
  56. if (!riEvent)
  57. return riEvent.hr();
  58. for ( ; riEvent; ++riEvent)
  59. {
  60. if (riEvent.type() == SmartRef::RiffIter::List && riEvent.id() == DMUS_FOURCC_LYRICSTRACKEVENT_LIST)
  61. {
  62. HRESULT hr = this->LoadLyric(riEvent.Descend());
  63. if (FAILED(hr))
  64. return hr;
  65. }
  66. }
  67. return riEvent.hr();
  68. }
  69. //////////////////////////////////////////////////////////////////////
  70. // other methods
  71. HRESULT
  72. CLyricsTrack::PlayItem(
  73. const LyricInfo &item,
  74. statedata &state,
  75. IDirectMusicPerformance *pPerf,
  76. IDirectMusicSegmentState* pSegSt,
  77. DWORD dwVirtualID,
  78. MUSIC_TIME mtOffset,
  79. REFERENCE_TIME rtOffset,
  80. bool fClockTime)
  81. {
  82. // get the graph from the segment state
  83. IDirectMusicGraph *pGraph = NULL;
  84. HRESULT hrG = pSegSt->QueryInterface(IID_IDirectMusicGraph, reinterpret_cast<void**>(&pGraph));
  85. if (FAILED(hrG))
  86. return hrG;
  87. SmartRef::PMsg<DMUS_LYRIC_PMSG> pmsg(pPerf, 2 * wcslen(item.wstrText));
  88. if (FAILED(pmsg.hr())) {
  89. pGraph->Release();
  90. return pmsg.hr();
  91. }
  92. assert(((char*)&pmsg.p->wszString[wcslen(item.wstrText)]) + 1 < (((char*)(pmsg.p)) + pmsg.p->dwSize)); // just to make sure we haven't miscalculated. the last byte of the null of the string should fall before the byte just beyond the extent of the struct (and it could be several bytes before if the DMUS_LYRIC_PMSG struct ended up being padded to come out to an even multiple of bytes.
  93. wcscpy(pmsg.p->wszString, item.wstrText);
  94. if (fClockTime)
  95. {
  96. pmsg.p->rtTime = item.lTimePhysical * gc_RefPerMil + rtOffset;
  97. pmsg.p->dwFlags = DMUS_PMSGF_REFTIME | DMUS_PMSGF_LOCKTOREFTIME | item.dwTimingFlags;
  98. }
  99. else
  100. {
  101. pmsg.p->mtTime = item.lTimePhysical + mtOffset;
  102. pmsg.p->dwFlags = DMUS_PMSGF_MUSICTIME | item.dwTimingFlags;
  103. }
  104. pmsg.p->dwVirtualTrackID = dwVirtualID;
  105. pmsg.p->dwType = DMUS_PMSGT_LYRIC;
  106. pmsg.p->dwGroupID = 0xffffffff;
  107. pmsg.StampAndSend(pGraph);
  108. pGraph->Release();
  109. return pmsg.hr();
  110. }
  111. HRESULT
  112. CLyricsTrack::LoadLyric(SmartRef::RiffIter ri)
  113. {
  114. HRESULT hr = S_OK;
  115. if (!ri)
  116. return ri.hr();
  117. // Create an event
  118. TListItem<LyricInfo> *pItem = new TListItem<LyricInfo>;
  119. if (!pItem)
  120. return E_OUTOFMEMORY;
  121. LyricInfo &rinfo = pItem->GetItemValue();
  122. bool fFoundEventHeader = false;
  123. for ( ; ri; ++ri)
  124. {
  125. if (ri.type() != SmartRef::RiffIter::Chunk)
  126. continue;
  127. switch(ri.id())
  128. {
  129. case DMUS_FOURCC_LYRICSTRACKEVENTHEADER_CHUNK:
  130. // Read an event chunk
  131. DMUS_IO_LYRICSTRACK_EVENTHEADER ioItem;
  132. hr = SmartRef::RiffIterReadChunk(ri, &ioItem);
  133. if (FAILED(hr))
  134. {
  135. delete pItem;
  136. return hr;
  137. }
  138. // Don't allow ref/music timing flags because these are controlled by whether
  139. // the overall track is playing music or clock time and can't be set in individual
  140. // events. Similarly, the tool flush flag isn't appropriate for an event to be played.
  141. if (ioItem.dwTimingFlags & (DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_FLUSH | DMUS_PMSGF_LOCKTOREFTIME))
  142. {
  143. Trace(1, "Error: Unable to load lyric track: DMUS_PMSGF_REFTIME, DMUS_PMSGF_MUSICTIME, DMUS_PMSGF_TOOL_FLUSH, and DMUS_PMSGF_LOCKTOREFTIME are not allowed as dwTimingFlags in chunk 'lyrh'.\n");
  144. delete pItem;
  145. return DMUS_E_INVALID_LYRICSTRACK;
  146. }
  147. fFoundEventHeader = true;
  148. rinfo.dwFlags = ioItem.dwFlags;
  149. rinfo.dwTimingFlags = ioItem.dwTimingFlags;
  150. rinfo.lTriggerTime = ioItem.lTimeLogical;
  151. rinfo.lTimePhysical = ioItem.lTimePhysical;
  152. break;
  153. case DMUS_FOURCC_LYRICSTRACKEVENTTEXT_CHUNK:
  154. {
  155. hr = ri.ReadText(&rinfo.wstrText);
  156. if (FAILED(hr))
  157. {
  158. #ifdef DBG
  159. if (hr == E_FAIL)
  160. {
  161. Trace(1, "Error: Unable to load lyric track: Problem reading 'lyrn' chunk.\n");
  162. }
  163. #endif
  164. delete pItem;
  165. return hr == E_FAIL ? DMUS_E_INVALID_LYRICSTRACK : hr;
  166. }
  167. }
  168. break;
  169. default:
  170. break;
  171. }
  172. }
  173. hr = ri.hr();
  174. if (SUCCEEDED(hr) && (!fFoundEventHeader || !rinfo.wstrText))
  175. {
  176. #ifdef DBG
  177. if (!fFoundEventHeader)
  178. {
  179. Trace(1, "Error: Unable to load lyric track: Chunk 'lyrh' not found.\n");
  180. }
  181. else
  182. {
  183. Trace(1, "Error: Unable to load lyric track: Chunk 'lyrn' not found.\n");
  184. }
  185. #endif
  186. hr = DMUS_E_INVALID_LYRICSTRACK;
  187. }
  188. if (SUCCEEDED(hr))
  189. {
  190. m_EventList.AddHead(pItem);
  191. }
  192. else
  193. {
  194. delete pItem;
  195. }
  196. return hr;
  197. }