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.

332 lines
11 KiB

  1. /******************************************************************************
  2. Copyright (c) 1985-1998 Microsoft Corporation
  3. Title: foramts.c - Multimedia Systems Media Control Interface
  4. Contains specific mci time format conversion functions
  5. Version: 1.00
  6. Date: 7-MAR-1991
  7. Author: Greg Simons
  8. ------------------------------------------------------------------------------
  9. Change log:
  10. DATE REV DESCRIPTION
  11. ----------- ----- -----------------------------------------------------------
  12. 7-MAR-1991 GregSi Original
  13. *****************************************************************************/
  14. #define UNICODE
  15. //MMSYSTEM
  16. #define MMNOSOUND - Sound support
  17. #define MMNOWAVE - Waveform support
  18. #define MMNOAUX - Auxiliary output support
  19. #define MMNOJOY - Joystick support
  20. //MMDDK
  21. #define NOWAVEDEV - Waveform support
  22. #define NOAUXDEV - Auxiliary output support
  23. #define NOJOYDEV - Joystick support
  24. #include <windows.h>
  25. #include <mmsystem.h>
  26. #include <mmddk.h>
  27. #include "mmsys.h"
  28. #include "list.h"
  29. #include "mciseq.h"
  30. /**************************** PRIVATE PROTOTYPES *************************/
  31. PRIVATE DWORD NEAR PASCAL FPSDisplay(DWORD dwDisplayType);
  32. PRIVATE DWORD NEAR PASCAL FPSFile(int wFileDiv);
  33. PRIVATE DWORD NEAR PASCAL HMSFToFrames(DWORD dwCurrent, DWORD dwFormat);
  34. PRIVATE DWORD NEAR PASCAL HMSFToMS(DWORD dwHmsf, DWORD dwFormat);
  35. PRIVATE DWORD NEAR PASCAL FramesToHMSF(DWORD dwFrames, DWORD dwFormat);
  36. /**************************** PRIVATE FUNCTIONS *************************/
  37. PRIVATE DWORD NEAR PASCAL FPSDisplay(DWORD dwDisplayType)
  38. // return the frames per second for smpte display types
  39. // (utility function for format conversion routines)
  40. {
  41. switch (dwDisplayType)
  42. {
  43. case MCI_FORMAT_SMPTE_24:
  44. return 24;
  45. case MCI_FORMAT_SMPTE_25:
  46. return 25;
  47. case MCI_FORMAT_SMPTE_30DROP:
  48. case MCI_FORMAT_SMPTE_30:
  49. return 30;
  50. #ifdef DEBUG
  51. default:
  52. return 0;
  53. #endif
  54. } //switch
  55. return 0;
  56. }
  57. PRIVATE DWORD NEAR PASCAL FPSFile(int wFileDiv)
  58. {
  59. // returns frames per second based file division type
  60. switch (wFileDiv)
  61. {
  62. case SEQ_DIV_SMPTE_24:
  63. return 24;
  64. case SEQ_DIV_SMPTE_25:
  65. return 25;
  66. case SEQ_DIV_SMPTE_30:
  67. case SEQ_DIV_SMPTE_30DROP:
  68. return 30;
  69. #ifdef DEBUG
  70. default:
  71. return 0;
  72. #endif
  73. } //switch
  74. return 0;
  75. }
  76. PRIVATE DWORD NEAR PASCAL HMSFToFrames(DWORD dwCurrent, DWORD dwFormat)
  77. /* convert from hmsf (colonized) format to raw frames */
  78. {
  79. DWORD dwReturn;
  80. HMSF hmsf = * ((HMSF FAR *) &dwCurrent); // cast dwCurrent to hmsf
  81. int fps = (int)FPSDisplay(dwFormat);
  82. dwReturn = ((DWORD)hmsf.hours * 60 * 60 * fps) +
  83. ((DWORD)hmsf.minutes * 60 * fps) +
  84. ((DWORD)hmsf.seconds * fps) +
  85. hmsf.frames;
  86. return dwReturn;
  87. }
  88. PRIVATE DWORD NEAR PASCAL HMSFToMS(DWORD dwHmsf, DWORD dwFormat)
  89. // convert hmsf (colonized) format to milliseconds
  90. {
  91. DWORD dwReturn;
  92. DWORD dwFrames = HMSFToFrames(dwHmsf, dwFormat);
  93. int fps = (int)FPSDisplay(dwFormat);
  94. dwReturn = ((dwFrames * 1000) + (fps/2)) / fps; // (fps/2) for rounding
  95. return dwReturn;
  96. }
  97. PRIVATE DWORD NEAR PASCAL FramesToHMSF(DWORD dwFrames, DWORD dwFormat)
  98. // convert from frames to hmsf (colonized) format
  99. {
  100. HMSF hmsf;
  101. int fps = (int)FPSDisplay(dwFormat);
  102. hmsf.hours = (BYTE)(dwFrames / ((DWORD) 60 * 60 * fps));
  103. hmsf.minutes = (BYTE)((dwFrames % ((DWORD) 60 * 60 * fps)) / (60 * fps));
  104. hmsf.seconds = (BYTE)((dwFrames % ((DWORD) 60 * fps)) / fps);
  105. hmsf.frames = (BYTE)((dwFrames % fps));
  106. return * ((DWORD FAR *) &hmsf);
  107. }
  108. /**************************** PUBLIC FUNCTIONS *************************/
  109. PUBLIC BOOL NEAR PASCAL ColonizeOutput(pSeqStreamType pStream)
  110. // tells whether the user display type is such that the output should
  111. // displayed colonoized (i.e. "hh:mm:ss:ff")
  112. {
  113. if ((pStream->userDisplayType == MCI_FORMAT_SMPTE_24) ||
  114. (pStream->userDisplayType == MCI_FORMAT_SMPTE_25) ||
  115. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30DROP) ||
  116. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30))
  117. // smpte times are the only colonized formats
  118. return TRUE;
  119. else
  120. return FALSE;
  121. }
  122. PUBLIC BOOL NEAR PASCAL FormatsEqual(pSeqStreamType pStream)
  123. // tells whether the display format is compatible with the file format
  124. // (i.e. will conversion have to be done in interaction with the user)
  125. {
  126. BOOL bReturn;
  127. // Essentially, ppqn file type only compatible with song pointer display;
  128. // SMPTE compatible with anything but ppqn
  129. if (pStream->fileDivType == SEQ_DIV_PPQN)
  130. {
  131. if (pStream->userDisplayType == MCI_SEQ_FORMAT_SONGPTR)
  132. bReturn = TRUE;
  133. else
  134. bReturn = FALSE;
  135. }
  136. else
  137. {
  138. if ((pStream->userDisplayType == MCI_FORMAT_SMPTE_24) ||
  139. (pStream->userDisplayType == MCI_FORMAT_SMPTE_25) ||
  140. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30DROP) ||
  141. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30))
  142. bReturn = TRUE;
  143. else
  144. bReturn = FALSE;
  145. }
  146. return bReturn;
  147. }
  148. PUBLIC DWORD NEAR PASCAL CnvtTimeToSeq(pSeqStreamType pStream, DWORD dwCurrent, MIDISEQINFO FAR * pSeqInfo)
  149. /* The sequencer understands two time units: Ticks for ppqn files,
  150. or frames for smpte files. The user data is presented either as
  151. song pointer, milliseconds, or H(our)M(inute)S(econd)F(rame).
  152. This routine converts FROM user time TO sequencer time.
  153. */
  154. {
  155. DWORD dwMs; // milliseconds
  156. DWORD fps; // frames per second;
  157. DWORD dwReturn;
  158. DWORD dwTicks;
  159. if (FormatsEqual(pStream))
  160. {
  161. if ((pStream->userDisplayType == MCI_FORMAT_SMPTE_24) ||
  162. (pStream->userDisplayType == MCI_FORMAT_SMPTE_25) ||
  163. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30) ||
  164. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30DROP))
  165. // both file and display are smpte
  166. dwReturn = pSeqInfo->wResolution *
  167. HMSFToFrames(dwCurrent, pStream->userDisplayType);
  168. else
  169. //both file and display are ppqn (convert song pointer to ppqn)
  170. dwReturn = (pSeqInfo->wResolution * dwCurrent) / 4;
  171. }
  172. else if (pStream->fileDivType == SEQ_DIV_PPQN)
  173. //ppqn file, display format !ppqn
  174. {
  175. if (pStream->userDisplayType != MCI_FORMAT_MILLISECONDS)
  176. // must be smpte -- convert hmsf to milliseconds
  177. dwMs = HMSFToMS(dwCurrent, pStream->userDisplayType);
  178. else // must be milliseconds already
  179. dwMs = dwCurrent;
  180. // now that we have milliseconds, we must ask the sequencer to
  181. // convert them to ppqn (using it's internal tempo map)
  182. midiSeqMessage((HMIDISEQ) pStream->hSeq, SEQ_MSTOTICKS,
  183. dwMs, (DWORD_PTR)(LPSTR) &dwTicks); // passed back in dwTicks
  184. dwReturn = dwTicks;
  185. }
  186. else // smpte file, display format != smpte
  187. {
  188. // NB: don't worry about SONGPTR -- it's illegal here
  189. // also, don't worry about HMSF -- it's equal
  190. // The only possible case is ms -> ticks
  191. fps = FPSFile(pStream->fileDivType);
  192. dwReturn = ((dwCurrent * fps * pSeqInfo->wResolution) + 500) / 1000; // add 500 to round
  193. }
  194. return dwReturn;
  195. }
  196. PUBLIC DWORD NEAR PASCAL CnvtTimeFromSeq(pSeqStreamType pStream, DWORD dwTicks, MIDISEQINFO FAR * pSeqInfo)
  197. // This routine converts FROM sequencer time TO user time.
  198. {
  199. DWORD dwMs; // milliseconds
  200. DWORD fps; // frames per second;
  201. DWORD dwReturn;
  202. DWORD dwFrames;
  203. DWORD dwNativeUnits;
  204. if (pSeqInfo->wDivType == SEQ_DIV_PPQN)
  205. dwNativeUnits = (dwTicks * 4) / pSeqInfo->wResolution;
  206. else
  207. dwNativeUnits = dwTicks / pSeqInfo->wResolution;
  208. if (FormatsEqual(pStream))
  209. {
  210. if ((pStream->userDisplayType == MCI_FORMAT_SMPTE_24) ||
  211. (pStream->userDisplayType == MCI_FORMAT_SMPTE_25) ||
  212. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30) ||
  213. (pStream->userDisplayType == MCI_FORMAT_SMPTE_30DROP))
  214. dwReturn = FramesToHMSF(dwNativeUnits, pStream->userDisplayType);
  215. else
  216. dwReturn = dwNativeUnits; // no conversion needed
  217. }
  218. else if (pStream->fileDivType == SEQ_DIV_PPQN)
  219. {
  220. // convert song ptr to ms
  221. midiSeqMessage((HMIDISEQ) pStream->hSeq, SEQ_TICKSTOMS,
  222. dwTicks, (DWORD_PTR)(LPSTR) &dwMs); // passed back in dwSongPtr
  223. if (pStream->userDisplayType == MCI_FORMAT_MILLISECONDS)
  224. dwReturn = dwMs;
  225. else
  226. // convert from ms to frames, and then frames to hmsf format
  227. {
  228. fps = FPSDisplay(pStream->userDisplayType);
  229. dwFrames = (dwMs * fps) / 1000;
  230. dwReturn = FramesToHMSF(dwFrames, pStream->userDisplayType);
  231. }
  232. }
  233. else // smpte file
  234. {
  235. // NB: don't worry about SONGPTR -- it's illegal here
  236. // also, don't worry about HMSF -- it's "equal"
  237. // The only possible case is frames->ms
  238. // set stream display type default based on file div type
  239. fps = FPSFile(pStream->fileDivType);
  240. dwReturn = ((dwTicks * 1000) + (fps/2)) /
  241. (fps * pSeqInfo->wResolution);
  242. // add (fps/2) to round
  243. // BTW: it would take > 39 hours to overflow @ 30fps (23:59:59:29 is max)
  244. }
  245. return dwReturn;
  246. }
  247. PUBLIC BOOL NEAR PASCAL RangeCheck(pSeqStreamType pStream, DWORD dwValue)
  248. /* range checks raw, unconverted data. checks if data is negative, or past
  249. end of file length. also checks if smpte hours, minutes, seconds and frames
  250. are all valid. Returns TRUE if legal, otherwise FALSE */
  251. {
  252. int fps;
  253. HMSF hmsf;
  254. DWORD dwLength;
  255. MIDISEQINFO seqInfo;
  256. // Get length, and convert it to display format
  257. midiSeqMessage((HMIDISEQ) pStream->hSeq,
  258. SEQ_GETINFO, (DWORD_PTR) (LPMIDISEQINFO) &seqInfo, 0L);
  259. dwLength = CnvtTimeFromSeq(pStream, seqInfo.dwLength, &seqInfo);
  260. switch (pStream->userDisplayType) // check length based on user format
  261. {
  262. case MCI_FORMAT_SMPTE_24:
  263. case MCI_FORMAT_SMPTE_25:
  264. case MCI_FORMAT_SMPTE_30:
  265. case MCI_FORMAT_SMPTE_30DROP:
  266. hmsf = * ((HMSF FAR *) &dwValue);
  267. fps = (int)FPSDisplay(pStream->userDisplayType); // get frames per second
  268. // check for format errors
  269. if (((int)hmsf.frames >= fps) || (hmsf.seconds >= 60) ||
  270. (hmsf.minutes >= 60) || (hmsf.hours > 24))
  271. return FALSE;
  272. // don't check for negative values, since using unsigned bytes
  273. // (2's comp. negs would get caught above anyway)
  274. // check for length error
  275. if (HMSFToMS(* ((DWORD FAR *) &dwValue), pStream->userDisplayType) >
  276. HMSFToMS(dwLength, pStream->userDisplayType))
  277. return FALSE;
  278. break;
  279. case MCI_SEQ_FORMAT_SONGPTR:
  280. case MCI_FORMAT_MILLISECONDS:
  281. if (dwValue > dwLength)
  282. return FALSE; // past end
  283. }
  284. return TRUE;
  285. }