discid.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include "main.h"
  2. #include "cddb.h"
  3. #include <strsafe.h>
  4. /*
  5. * cddb_sum
  6. * Convert an integer to its text string representation, and
  7. * compute its checksum. Used by cddb_discid to derive the
  8. * disc ID.
  9. *
  10. * Args:
  11. * n - The integer value.
  12. *
  13. * Return:
  14. * The integer checksum.
  15. */
  16. int cddb_sum(int n)
  17. {
  18. char buf[12],
  19. *p;
  20. int ret = 0;
  21. /* For backward compatibility this algorithm must not change */
  22. StringCchPrintfA(buf, 12, "%lu", n);
  23. for (p = buf; *p != '\0'; p++)
  24. ret += (*p - '0');
  25. return (ret);
  26. }
  27. /*
  28. * cddb_discid
  29. * Compute a magic disc ID based on the number of tracks,
  30. * the length of each track, and a checksum of the string
  31. * that represents the offset of each track.
  32. *
  33. * Return:
  34. * The integer disc ID.
  35. */
  36. unsigned long cddb_discid(unsigned char nTracks, unsigned int* pnMin, unsigned int* pnSec)
  37. {
  38. int i,
  39. t = 0,
  40. n = 0;
  41. /* For backward compatibility this algorithm must not change */
  42. for (i = 0; i < (int) nTracks; i++)
  43. {
  44. n += cddb_sum((pnMin[i] * 60) + pnSec[i]);
  45. t += ((pnMin[i + 1] * 60) + pnSec[i + 1]) - ((pnMin[i] * 60) + pnSec[i]);
  46. }
  47. return ((n % 0xff) << 24 | t << 8 | nTracks);
  48. }
  49. // Functions used to generate the CDDB id
  50. void CDGetEndFrame(MCIDEVICEID wDeviceID,
  51. DINFO* psDI,
  52. unsigned int nOffset,
  53. unsigned int* pnFrame,
  54. unsigned int* pnMin,
  55. unsigned int* pnSec)
  56. {
  57. MCI_STATUS_PARMS sMCIStatus;
  58. sMCIStatus.dwItem = MCI_STATUS_LENGTH;
  59. MCISendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT,
  60. (DWORD_PTR)(LPVOID) &sMCIStatus);
  61. #ifdef _WIN64
  62. *pnFrame = (unsigned int)((double)sMCIStatus.dwReturn * (75.0 / 1000.0));
  63. #else
  64. {
  65. int nFrame;
  66. static double tmp = 75.0 / 1000.0;
  67. unsigned long a = sMCIStatus.dwReturn;
  68. __asm
  69. {
  70. fld qword ptr tmp
  71. fild dword ptr a
  72. fmul
  73. fistp dword ptr nFrame
  74. }
  75. *pnFrame = nFrame;
  76. }
  77. #endif
  78. pnFrame[0] += 1 + nOffset; // Due to bug in MCI according to CDDB docs!
  79. psDI->nDiscLength = (pnFrame[0] / 75);
  80. *pnMin = pnFrame[0] / 75 / 60;
  81. *pnSec = (pnFrame[0] / 75) % 60;
  82. }
  83. void CDGetAbsoluteTrackPos(MCIDEVICEID wDeviceID,
  84. unsigned int nTrack,
  85. unsigned int* pnFrame,
  86. unsigned int* pnMin,
  87. unsigned int* pnSec)
  88. {
  89. MCI_STATUS_PARMS sMCIStatus;
  90. sMCIStatus.dwItem = MCI_STATUS_POSITION;
  91. sMCIStatus.dwTrack = nTrack;
  92. MCISendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT,
  93. (DWORD_PTR)(LPVOID) &sMCIStatus);
  94. #ifdef _WIN64
  95. *pnFrame = (int)((double)sMCIStatus.dwReturn * (75.0 / 1000.0));
  96. #else
  97. {
  98. static double tmp = 75.0 / 1000.0;
  99. unsigned long a = sMCIStatus.dwReturn;
  100. __asm
  101. {
  102. fld qword ptr tmp
  103. fild dword ptr a
  104. fmul
  105. fistp dword ptr a
  106. }
  107. *pnFrame = a;
  108. }
  109. #endif
  110. *pnMin = *pnFrame / 75 / 60;
  111. *pnSec = (*pnFrame / 75) % 60;
  112. }
  113. int GetDiscID(MCIDEVICEID wDeviceID, DINFO* psDI)
  114. {
  115. MCI_SET_PARMS sMCISet;
  116. unsigned int nLoop;
  117. unsigned int nMCITracks = CDGetTracks(wDeviceID);
  118. unsigned int* pnMin = NULL;
  119. unsigned int* pnSec = NULL;
  120. if (nMCITracks > 65535) return 1;
  121. if (nMCITracks > 128) nMCITracks = 128;
  122. psDI->ntracks = nMCITracks;
  123. pnMin = (unsigned int*)GlobalAlloc(GPTR, (nMCITracks + 1) * 2 * sizeof(unsigned int));
  124. if (!pnMin) return 1;
  125. pnSec = pnMin + (nMCITracks + 1);
  126. sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  127. MCISendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
  128. for (nLoop = 0 ; nLoop < nMCITracks; nLoop ++)
  129. CDGetAbsoluteTrackPos(wDeviceID, nLoop + 1, &psDI->pnFrames[nLoop], &pnMin[nLoop], &pnSec[nLoop]);
  130. CDGetEndFrame(wDeviceID, psDI, psDI->pnFrames[0], &psDI->pnFrames[nLoop], &pnMin[nLoop], &pnSec[nLoop]);
  131. psDI->CDDBID = cddb_discid((unsigned char)nMCITracks, pnMin, pnSec);
  132. sMCISet.dwTimeFormat = MCI_FORMAT_TMSF;
  133. MCISendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
  134. if (pnMin)
  135. {
  136. GlobalFree(pnMin);
  137. }
  138. return 0;
  139. }