The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

1311 lines
37KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. namespace CDReaderHelpers
  19. {
  20. #define FILE_ANY_ACCESS 0
  21. #ifndef FILE_READ_ACCESS
  22. #define FILE_READ_ACCESS 1
  23. #endif
  24. #ifndef FILE_WRITE_ACCESS
  25. #define FILE_WRITE_ACCESS 2
  26. #endif
  27. #define METHOD_BUFFERED 0
  28. #define IOCTL_SCSI_BASE 4
  29. #define SCSI_IOCTL_DATA_OUT 0
  30. #define SCSI_IOCTL_DATA_IN 1
  31. #define SCSI_IOCTL_DATA_UNSPECIFIED 2
  32. #define CTL_CODE2(DevType, Function, Method, Access) (((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
  33. #define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE2( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
  34. #define IOCTL_SCSI_GET_ADDRESS CTL_CODE2( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )
  35. #define SENSE_LEN 14
  36. #define SRB_ENABLE_RESIDUAL_COUNT 0x04
  37. #define SRB_DIR_IN 0x08
  38. #define SRB_DIR_OUT 0x10
  39. #define SRB_EVENT_NOTIFY 0x40
  40. #define SC_HA_INQUIRY 0x00
  41. #define SC_GET_DEV_TYPE 0x01
  42. #define SC_EXEC_SCSI_CMD 0x02
  43. #define SS_PENDING 0x00
  44. #define SS_COMP 0x01
  45. #define SS_ERR 0x04
  46. enum
  47. {
  48. READTYPE_ANY = 0,
  49. READTYPE_ATAPI1 = 1,
  50. READTYPE_ATAPI2 = 2,
  51. READTYPE_READ6 = 3,
  52. READTYPE_READ10 = 4,
  53. READTYPE_READ_D8 = 5,
  54. READTYPE_READ_D4 = 6,
  55. READTYPE_READ_D4_1 = 7,
  56. READTYPE_READ10_2 = 8
  57. };
  58. struct SCSI_PASS_THROUGH
  59. {
  60. USHORT Length;
  61. UCHAR ScsiStatus;
  62. UCHAR PathId;
  63. UCHAR TargetId;
  64. UCHAR Lun;
  65. UCHAR CdbLength;
  66. UCHAR SenseInfoLength;
  67. UCHAR DataIn;
  68. ULONG DataTransferLength;
  69. ULONG TimeOutValue;
  70. ULONG DataBufferOffset;
  71. ULONG SenseInfoOffset;
  72. UCHAR Cdb[16];
  73. };
  74. struct SCSI_PASS_THROUGH_DIRECT
  75. {
  76. USHORT Length;
  77. UCHAR ScsiStatus;
  78. UCHAR PathId;
  79. UCHAR TargetId;
  80. UCHAR Lun;
  81. UCHAR CdbLength;
  82. UCHAR SenseInfoLength;
  83. UCHAR DataIn;
  84. ULONG DataTransferLength;
  85. ULONG TimeOutValue;
  86. PVOID DataBuffer;
  87. ULONG SenseInfoOffset;
  88. UCHAR Cdb[16];
  89. };
  90. struct SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
  91. {
  92. SCSI_PASS_THROUGH_DIRECT spt;
  93. ULONG Filler;
  94. UCHAR ucSenseBuf[32];
  95. };
  96. struct SCSI_ADDRESS
  97. {
  98. ULONG Length;
  99. UCHAR PortNumber;
  100. UCHAR PathId;
  101. UCHAR TargetId;
  102. UCHAR Lun;
  103. };
  104. #pragma pack(1)
  105. struct SRB_GDEVBlock
  106. {
  107. BYTE SRB_Cmd;
  108. BYTE SRB_Status;
  109. BYTE SRB_HaID;
  110. BYTE SRB_Flags;
  111. DWORD SRB_Hdr_Rsvd;
  112. BYTE SRB_Target;
  113. BYTE SRB_Lun;
  114. BYTE SRB_DeviceType;
  115. BYTE SRB_Rsvd1;
  116. BYTE pad[68];
  117. };
  118. struct SRB_ExecSCSICmd
  119. {
  120. BYTE SRB_Cmd;
  121. BYTE SRB_Status;
  122. BYTE SRB_HaID;
  123. BYTE SRB_Flags;
  124. DWORD SRB_Hdr_Rsvd;
  125. BYTE SRB_Target;
  126. BYTE SRB_Lun;
  127. WORD SRB_Rsvd1;
  128. DWORD SRB_BufLen;
  129. BYTE *SRB_BufPointer;
  130. BYTE SRB_SenseLen;
  131. BYTE SRB_CDBLen;
  132. BYTE SRB_HaStat;
  133. BYTE SRB_TargStat;
  134. VOID *SRB_PostProc;
  135. BYTE SRB_Rsvd2[20];
  136. BYTE CDBByte[16];
  137. BYTE SenseArea[SENSE_LEN + 2];
  138. };
  139. struct SRB
  140. {
  141. BYTE SRB_Cmd;
  142. BYTE SRB_Status;
  143. BYTE SRB_HaId;
  144. BYTE SRB_Flags;
  145. DWORD SRB_Hdr_Rsvd;
  146. };
  147. struct TOCTRACK
  148. {
  149. BYTE rsvd;
  150. BYTE ADR;
  151. BYTE trackNumber;
  152. BYTE rsvd2;
  153. BYTE addr[4];
  154. };
  155. struct TOC
  156. {
  157. WORD tocLen;
  158. BYTE firstTrack;
  159. BYTE lastTrack;
  160. TOCTRACK tracks[100];
  161. };
  162. #pragma pack()
  163. //==============================================================================
  164. struct CDDeviceDescription
  165. {
  166. CDDeviceDescription() : ha (0), tgt (0), lun (0), scsiDriveLetter (0)
  167. {
  168. }
  169. void createDescription (const char* data)
  170. {
  171. description << String (data + 8, 8).trim() // vendor
  172. << ' ' << String (data + 16, 16).trim() // product id
  173. << ' ' << String (data + 32, 4).trim(); // rev
  174. }
  175. String description;
  176. BYTE ha, tgt, lun;
  177. char scsiDriveLetter; // will be 0 if not using scsi
  178. };
  179. //==============================================================================
  180. class CDReadBuffer
  181. {
  182. public:
  183. CDReadBuffer (const int numberOfFrames)
  184. : startFrame (0), numFrames (0), dataStartOffset (0),
  185. dataLength (0), bufferSize (2352 * numberOfFrames), index (0),
  186. buffer (bufferSize), wantsIndex (false)
  187. {
  188. }
  189. bool isZero() const noexcept
  190. {
  191. for (int i = 0; i < dataLength; ++i)
  192. if (buffer [dataStartOffset + i] != 0)
  193. return false;
  194. return true;
  195. }
  196. int startFrame, numFrames, dataStartOffset;
  197. int dataLength, bufferSize, index;
  198. HeapBlock<BYTE> buffer;
  199. bool wantsIndex;
  200. };
  201. class CDDeviceHandle;
  202. //==============================================================================
  203. class CDController
  204. {
  205. public:
  206. CDController() : initialised (false) {}
  207. virtual ~CDController() {}
  208. virtual bool read (CDReadBuffer&) = 0;
  209. virtual void shutDown() {}
  210. bool readAudio (CDReadBuffer& rb, CDReadBuffer* overlapBuffer = 0);
  211. int getLastIndex();
  212. public:
  213. CDDeviceHandle* deviceInfo;
  214. int framesToCheck, framesOverlap;
  215. bool initialised;
  216. void prepare (SRB_ExecSCSICmd& s);
  217. void perform (SRB_ExecSCSICmd& s);
  218. void setPaused (bool paused);
  219. };
  220. //==============================================================================
  221. class CDDeviceHandle
  222. {
  223. public:
  224. CDDeviceHandle (const CDDeviceDescription& device, HANDLE scsiHandle_)
  225. : info (device), scsiHandle (scsiHandle_), readType (READTYPE_ANY)
  226. {
  227. }
  228. ~CDDeviceHandle()
  229. {
  230. if (controller != nullptr)
  231. {
  232. controller->shutDown();
  233. controller = 0;
  234. }
  235. if (scsiHandle != 0)
  236. CloseHandle (scsiHandle);
  237. }
  238. bool readTOC (TOC* lpToc);
  239. bool readAudio (CDReadBuffer& buffer, CDReadBuffer* overlapBuffer = 0);
  240. void openDrawer (bool shouldBeOpen);
  241. void performScsiCommand (HANDLE event, SRB_ExecSCSICmd& s);
  242. CDDeviceDescription info;
  243. HANDLE scsiHandle;
  244. BYTE readType;
  245. private:
  246. ScopedPointer<CDController> controller;
  247. bool testController (int readType, CDController* newController, CDReadBuffer& bufferToUse);
  248. };
  249. //==============================================================================
  250. HANDLE createSCSIDeviceHandle (const char driveLetter)
  251. {
  252. TCHAR devicePath[] = { '\\', '\\', '.', '\\', driveLetter, ':', 0, 0 };
  253. DWORD flags = GENERIC_READ | GENERIC_WRITE;
  254. HANDLE h = CreateFile (devicePath, flags, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  255. if (h == INVALID_HANDLE_VALUE)
  256. {
  257. flags ^= GENERIC_WRITE;
  258. h = CreateFile (devicePath, flags, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  259. }
  260. return h;
  261. }
  262. void findCDDevices (Array<CDDeviceDescription>& list)
  263. {
  264. for (char driveLetter = 'b'; driveLetter <= 'z'; ++driveLetter)
  265. {
  266. TCHAR drivePath[] = { driveLetter, ':', '\\', 0, 0 };
  267. if (GetDriveType (drivePath) == DRIVE_CDROM)
  268. {
  269. HANDLE h = createSCSIDeviceHandle (driveLetter);
  270. if (h != INVALID_HANDLE_VALUE)
  271. {
  272. char buffer[100] = { 0 };
  273. SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER p = { 0 };
  274. p.spt.Length = sizeof (SCSI_PASS_THROUGH);
  275. p.spt.CdbLength = 6;
  276. p.spt.SenseInfoLength = 24;
  277. p.spt.DataIn = SCSI_IOCTL_DATA_IN;
  278. p.spt.DataTransferLength = sizeof (buffer);
  279. p.spt.TimeOutValue = 2;
  280. p.spt.DataBuffer = buffer;
  281. p.spt.SenseInfoOffset = offsetof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
  282. p.spt.Cdb[0] = 0x12;
  283. p.spt.Cdb[4] = 100;
  284. DWORD bytesReturned = 0;
  285. if (DeviceIoControl (h, IOCTL_SCSI_PASS_THROUGH_DIRECT,
  286. &p, sizeof (p), &p, sizeof (p),
  287. &bytesReturned, 0) != 0)
  288. {
  289. CDDeviceDescription dev;
  290. dev.scsiDriveLetter = driveLetter;
  291. dev.createDescription (buffer);
  292. SCSI_ADDRESS scsiAddr = { 0 };
  293. scsiAddr.Length = sizeof (scsiAddr);
  294. if (DeviceIoControl (h, IOCTL_SCSI_GET_ADDRESS,
  295. 0, 0, &scsiAddr, sizeof (scsiAddr),
  296. &bytesReturned, 0) != 0)
  297. {
  298. dev.ha = scsiAddr.PortNumber;
  299. dev.tgt = scsiAddr.TargetId;
  300. dev.lun = scsiAddr.Lun;
  301. list.add (dev);
  302. }
  303. }
  304. CloseHandle (h);
  305. }
  306. }
  307. }
  308. }
  309. DWORD performScsiPassThroughCommand (SRB_ExecSCSICmd* const srb, const char driveLetter,
  310. HANDLE& deviceHandle, const bool retryOnFailure)
  311. {
  312. SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER s = { 0 };
  313. s.spt.Length = sizeof (SCSI_PASS_THROUGH);
  314. s.spt.CdbLength = srb->SRB_CDBLen;
  315. s.spt.DataIn = (BYTE) ((srb->SRB_Flags & SRB_DIR_IN)
  316. ? SCSI_IOCTL_DATA_IN
  317. : ((srb->SRB_Flags & SRB_DIR_OUT)
  318. ? SCSI_IOCTL_DATA_OUT
  319. : SCSI_IOCTL_DATA_UNSPECIFIED));
  320. s.spt.DataTransferLength = srb->SRB_BufLen;
  321. s.spt.TimeOutValue = 5;
  322. s.spt.DataBuffer = srb->SRB_BufPointer;
  323. s.spt.SenseInfoOffset = offsetof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
  324. memcpy (s.spt.Cdb, srb->CDBByte, srb->SRB_CDBLen);
  325. srb->SRB_Status = SS_ERR;
  326. srb->SRB_TargStat = 0x0004;
  327. DWORD bytesReturned = 0;
  328. if (DeviceIoControl (deviceHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
  329. &s, sizeof (s), &s, sizeof (s), &bytesReturned, 0) != 0)
  330. {
  331. srb->SRB_Status = SS_COMP;
  332. }
  333. else if (retryOnFailure)
  334. {
  335. const DWORD error = GetLastError();
  336. if ((error == ERROR_MEDIA_CHANGED) || (error == ERROR_INVALID_HANDLE))
  337. {
  338. if (error != ERROR_INVALID_HANDLE)
  339. CloseHandle (deviceHandle);
  340. deviceHandle = createSCSIDeviceHandle (driveLetter);
  341. return performScsiPassThroughCommand (srb, driveLetter, deviceHandle, false);
  342. }
  343. }
  344. return srb->SRB_Status;
  345. }
  346. //==============================================================================
  347. // Controller types..
  348. class ControllerType1 : public CDController
  349. {
  350. public:
  351. ControllerType1() {}
  352. bool read (CDReadBuffer& rb)
  353. {
  354. if (rb.numFrames * 2352 > rb.bufferSize)
  355. return false;
  356. SRB_ExecSCSICmd s;
  357. prepare (s);
  358. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  359. s.SRB_BufLen = rb.bufferSize;
  360. s.SRB_BufPointer = rb.buffer;
  361. s.SRB_CDBLen = 12;
  362. s.CDBByte[0] = 0xBE;
  363. s.CDBByte[3] = (BYTE) ((rb.startFrame >> 16) & 0xFF);
  364. s.CDBByte[4] = (BYTE) ((rb.startFrame >> 8) & 0xFF);
  365. s.CDBByte[5] = (BYTE) (rb.startFrame & 0xFF);
  366. s.CDBByte[8] = (BYTE) (rb.numFrames & 0xFF);
  367. s.CDBByte[9] = (BYTE) (deviceInfo->readType == READTYPE_ATAPI1 ? 0x10 : 0xF0);
  368. perform (s);
  369. if (s.SRB_Status != SS_COMP)
  370. return false;
  371. rb.dataLength = rb.numFrames * 2352;
  372. rb.dataStartOffset = 0;
  373. return true;
  374. }
  375. };
  376. //==============================================================================
  377. class ControllerType2 : public CDController
  378. {
  379. public:
  380. ControllerType2() {}
  381. void shutDown()
  382. {
  383. if (initialised)
  384. {
  385. BYTE bufPointer[] = { 0, 0, 0, 8, 83, 0, 0, 0, 0, 0, 8, 0 };
  386. SRB_ExecSCSICmd s;
  387. prepare (s);
  388. s.SRB_Flags = SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT;
  389. s.SRB_BufLen = 0x0C;
  390. s.SRB_BufPointer = bufPointer;
  391. s.SRB_CDBLen = 6;
  392. s.CDBByte[0] = 0x15;
  393. s.CDBByte[4] = 0x0C;
  394. perform (s);
  395. }
  396. }
  397. bool init()
  398. {
  399. SRB_ExecSCSICmd s;
  400. s.SRB_Status = SS_ERR;
  401. if (deviceInfo->readType == READTYPE_READ10_2)
  402. {
  403. BYTE bufPointer1[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48, 35, 6, 0, 0, 0, 0, 0, 128 };
  404. BYTE bufPointer2[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48, 1, 6, 32, 7, 0, 0, 0, 0 };
  405. for (int i = 0; i < 2; ++i)
  406. {
  407. prepare (s);
  408. s.SRB_Flags = SRB_EVENT_NOTIFY;
  409. s.SRB_BufLen = 0x14;
  410. s.SRB_BufPointer = (i == 0) ? bufPointer1 : bufPointer2;
  411. s.SRB_CDBLen = 6;
  412. s.CDBByte[0] = 0x15;
  413. s.CDBByte[1] = 0x10;
  414. s.CDBByte[4] = 0x14;
  415. perform (s);
  416. if (s.SRB_Status != SS_COMP)
  417. return false;
  418. }
  419. }
  420. else
  421. {
  422. BYTE bufPointer[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48 };
  423. prepare (s);
  424. s.SRB_Flags = SRB_EVENT_NOTIFY;
  425. s.SRB_BufLen = 0x0C;
  426. s.SRB_BufPointer = bufPointer;
  427. s.SRB_CDBLen = 6;
  428. s.CDBByte[0] = 0x15;
  429. s.CDBByte[4] = 0x0C;
  430. perform (s);
  431. }
  432. return s.SRB_Status == SS_COMP;
  433. }
  434. bool read (CDReadBuffer& rb)
  435. {
  436. if (rb.numFrames * 2352 > rb.bufferSize)
  437. return false;
  438. if (! initialised)
  439. {
  440. initialised = init();
  441. if (! initialised)
  442. return false;
  443. }
  444. SRB_ExecSCSICmd s;
  445. prepare (s);
  446. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  447. s.SRB_BufLen = rb.bufferSize;
  448. s.SRB_BufPointer = rb.buffer;
  449. s.SRB_CDBLen = 10;
  450. s.CDBByte[0] = 0x28;
  451. s.CDBByte[1] = (BYTE) (deviceInfo->info.lun << 5);
  452. s.CDBByte[3] = (BYTE) ((rb.startFrame >> 16) & 0xFF);
  453. s.CDBByte[4] = (BYTE) ((rb.startFrame >> 8) & 0xFF);
  454. s.CDBByte[5] = (BYTE) (rb.startFrame & 0xFF);
  455. s.CDBByte[8] = (BYTE) (rb.numFrames & 0xFF);
  456. perform (s);
  457. if (s.SRB_Status != SS_COMP)
  458. return false;
  459. rb.dataLength = rb.numFrames * 2352;
  460. rb.dataStartOffset = 0;
  461. return true;
  462. }
  463. };
  464. //==============================================================================
  465. class ControllerType3 : public CDController
  466. {
  467. public:
  468. ControllerType3() {}
  469. bool read (CDReadBuffer& rb)
  470. {
  471. if (rb.numFrames * 2352 > rb.bufferSize)
  472. return false;
  473. if (! initialised)
  474. {
  475. setPaused (false);
  476. initialised = true;
  477. }
  478. SRB_ExecSCSICmd s;
  479. prepare (s);
  480. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  481. s.SRB_BufLen = rb.numFrames * 2352;
  482. s.SRB_BufPointer = rb.buffer;
  483. s.SRB_CDBLen = 12;
  484. s.CDBByte[0] = 0xD8;
  485. s.CDBByte[3] = (BYTE) ((rb.startFrame >> 16) & 0xFF);
  486. s.CDBByte[4] = (BYTE) ((rb.startFrame >> 8) & 0xFF);
  487. s.CDBByte[5] = (BYTE) (rb.startFrame & 0xFF);
  488. s.CDBByte[9] = (BYTE) (rb.numFrames & 0xFF);
  489. perform (s);
  490. if (s.SRB_Status != SS_COMP)
  491. return false;
  492. rb.dataLength = rb.numFrames * 2352;
  493. rb.dataStartOffset = 0;
  494. return true;
  495. }
  496. };
  497. //==============================================================================
  498. class ControllerType4 : public CDController
  499. {
  500. public:
  501. ControllerType4() {}
  502. bool selectD4Mode()
  503. {
  504. BYTE bufPointer[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 48 };
  505. SRB_ExecSCSICmd s;
  506. prepare (s);
  507. s.SRB_Flags = SRB_EVENT_NOTIFY;
  508. s.SRB_CDBLen = 6;
  509. s.SRB_BufLen = 12;
  510. s.SRB_BufPointer = bufPointer;
  511. s.CDBByte[0] = 0x15;
  512. s.CDBByte[1] = 0x10;
  513. s.CDBByte[4] = 0x08;
  514. perform (s);
  515. return s.SRB_Status == SS_COMP;
  516. }
  517. bool read (CDReadBuffer& rb)
  518. {
  519. if (rb.numFrames * 2352 > rb.bufferSize)
  520. return false;
  521. if (! initialised)
  522. {
  523. setPaused (true);
  524. if (deviceInfo->readType == READTYPE_READ_D4_1)
  525. selectD4Mode();
  526. initialised = true;
  527. }
  528. SRB_ExecSCSICmd s;
  529. prepare (s);
  530. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  531. s.SRB_BufLen = rb.bufferSize;
  532. s.SRB_BufPointer = rb.buffer;
  533. s.SRB_CDBLen = 10;
  534. s.CDBByte[0] = 0xD4;
  535. s.CDBByte[3] = (BYTE) ((rb.startFrame >> 16) & 0xFF);
  536. s.CDBByte[4] = (BYTE) ((rb.startFrame >> 8) & 0xFF);
  537. s.CDBByte[5] = (BYTE) (rb.startFrame & 0xFF);
  538. s.CDBByte[8] = (BYTE) (rb.numFrames & 0xFF);
  539. perform (s);
  540. if (s.SRB_Status != SS_COMP)
  541. return false;
  542. rb.dataLength = rb.numFrames * 2352;
  543. rb.dataStartOffset = 0;
  544. return true;
  545. }
  546. };
  547. //==============================================================================
  548. void CDController::prepare (SRB_ExecSCSICmd& s)
  549. {
  550. zerostruct (s);
  551. s.SRB_Cmd = SC_EXEC_SCSI_CMD;
  552. s.SRB_HaID = deviceInfo->info.ha;
  553. s.SRB_Target = deviceInfo->info.tgt;
  554. s.SRB_Lun = deviceInfo->info.lun;
  555. s.SRB_SenseLen = SENSE_LEN;
  556. }
  557. void CDController::perform (SRB_ExecSCSICmd& s)
  558. {
  559. s.SRB_PostProc = CreateEvent (0, TRUE, FALSE, 0);
  560. deviceInfo->performScsiCommand (s.SRB_PostProc, s);
  561. }
  562. void CDController::setPaused (bool paused)
  563. {
  564. SRB_ExecSCSICmd s;
  565. prepare (s);
  566. s.SRB_Flags = SRB_EVENT_NOTIFY;
  567. s.SRB_CDBLen = 10;
  568. s.CDBByte[0] = 0x4B;
  569. s.CDBByte[8] = (BYTE) (paused ? 0 : 1);
  570. perform (s);
  571. }
  572. bool CDController::readAudio (CDReadBuffer& rb, CDReadBuffer* overlapBuffer)
  573. {
  574. if (overlapBuffer != nullptr)
  575. {
  576. const bool canDoJitter = (overlapBuffer->bufferSize >= 2352 * framesToCheck);
  577. const bool doJitter = canDoJitter && ! overlapBuffer->isZero();
  578. if (doJitter
  579. && overlapBuffer->startFrame > 0
  580. && overlapBuffer->numFrames > 0
  581. && overlapBuffer->dataLength > 0)
  582. {
  583. const int numFrames = rb.numFrames;
  584. if (overlapBuffer->startFrame == (rb.startFrame - framesToCheck))
  585. {
  586. rb.startFrame -= framesOverlap;
  587. if (framesToCheck < framesOverlap
  588. && numFrames + framesOverlap <= rb.bufferSize / 2352)
  589. rb.numFrames += framesOverlap;
  590. }
  591. else
  592. {
  593. overlapBuffer->dataLength = 0;
  594. overlapBuffer->startFrame = 0;
  595. overlapBuffer->numFrames = 0;
  596. }
  597. }
  598. if (! read (rb))
  599. return false;
  600. if (doJitter)
  601. {
  602. const int checkLen = framesToCheck * 2352;
  603. const int maxToCheck = rb.dataLength - checkLen;
  604. if (overlapBuffer->dataLength == 0 || overlapBuffer->isZero())
  605. return true;
  606. BYTE* const p = overlapBuffer->buffer + overlapBuffer->dataStartOffset;
  607. bool found = false;
  608. for (int i = 0; i < maxToCheck; ++i)
  609. {
  610. if (memcmp (p, rb.buffer + i, checkLen) == 0)
  611. {
  612. i += checkLen;
  613. rb.dataStartOffset = i;
  614. rb.dataLength -= i;
  615. rb.startFrame = overlapBuffer->startFrame + framesToCheck;
  616. found = true;
  617. break;
  618. }
  619. }
  620. rb.numFrames = rb.dataLength / 2352;
  621. rb.dataLength = 2352 * rb.numFrames;
  622. if (! found)
  623. return false;
  624. }
  625. if (canDoJitter)
  626. {
  627. memcpy (overlapBuffer->buffer,
  628. rb.buffer + rb.dataStartOffset + 2352 * (rb.numFrames - framesToCheck),
  629. 2352 * framesToCheck);
  630. overlapBuffer->startFrame = rb.startFrame + rb.numFrames - framesToCheck;
  631. overlapBuffer->numFrames = framesToCheck;
  632. overlapBuffer->dataLength = 2352 * framesToCheck;
  633. overlapBuffer->dataStartOffset = 0;
  634. }
  635. else
  636. {
  637. overlapBuffer->startFrame = 0;
  638. overlapBuffer->numFrames = 0;
  639. overlapBuffer->dataLength = 0;
  640. }
  641. return true;
  642. }
  643. return read (rb);
  644. }
  645. int CDController::getLastIndex()
  646. {
  647. char qdata[100];
  648. SRB_ExecSCSICmd s;
  649. prepare (s);
  650. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  651. s.SRB_BufLen = sizeof (qdata);
  652. s.SRB_BufPointer = (BYTE*) qdata;
  653. s.SRB_CDBLen = 12;
  654. s.CDBByte[0] = 0x42;
  655. s.CDBByte[1] = (BYTE) (deviceInfo->info.lun << 5);
  656. s.CDBByte[2] = 64;
  657. s.CDBByte[3] = 1; // get current position
  658. s.CDBByte[7] = 0;
  659. s.CDBByte[8] = (BYTE) sizeof (qdata);
  660. perform (s);
  661. return s.SRB_Status == SS_COMP ? qdata[7] : 0;
  662. }
  663. //==============================================================================
  664. bool CDDeviceHandle::readTOC (TOC* lpToc)
  665. {
  666. SRB_ExecSCSICmd s = { 0 };
  667. s.SRB_Cmd = SC_EXEC_SCSI_CMD;
  668. s.SRB_HaID = info.ha;
  669. s.SRB_Target = info.tgt;
  670. s.SRB_Lun = info.lun;
  671. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  672. s.SRB_BufLen = 0x324;
  673. s.SRB_BufPointer = (BYTE*) lpToc;
  674. s.SRB_SenseLen = 0x0E;
  675. s.SRB_CDBLen = 0x0A;
  676. s.SRB_PostProc = CreateEvent (0, TRUE, FALSE, 0);
  677. s.CDBByte[0] = 0x43;
  678. s.CDBByte[1] = 0x00;
  679. s.CDBByte[7] = 0x03;
  680. s.CDBByte[8] = 0x24;
  681. performScsiCommand (s.SRB_PostProc, s);
  682. return (s.SRB_Status == SS_COMP);
  683. }
  684. void CDDeviceHandle::performScsiCommand (HANDLE event, SRB_ExecSCSICmd& s)
  685. {
  686. ResetEvent (event);
  687. DWORD status = performScsiPassThroughCommand ((SRB_ExecSCSICmd*) &s, info.scsiDriveLetter, scsiHandle, true);
  688. if (status == SS_PENDING)
  689. WaitForSingleObject (event, 4000);
  690. CloseHandle (event);
  691. }
  692. bool CDDeviceHandle::readAudio (CDReadBuffer& buffer, CDReadBuffer* overlapBuffer)
  693. {
  694. if (controller == 0)
  695. {
  696. testController (READTYPE_ATAPI2, new ControllerType1(), buffer)
  697. || testController (READTYPE_ATAPI1, new ControllerType1(), buffer)
  698. || testController (READTYPE_READ10_2, new ControllerType2(), buffer)
  699. || testController (READTYPE_READ10, new ControllerType2(), buffer)
  700. || testController (READTYPE_READ_D8, new ControllerType3(), buffer)
  701. || testController (READTYPE_READ_D4, new ControllerType4(), buffer)
  702. || testController (READTYPE_READ_D4_1, new ControllerType4(), buffer);
  703. }
  704. buffer.index = 0;
  705. if (controller != nullptr && controller->readAudio (buffer, overlapBuffer))
  706. {
  707. if (buffer.wantsIndex)
  708. buffer.index = controller->getLastIndex();
  709. return true;
  710. }
  711. return false;
  712. }
  713. void CDDeviceHandle::openDrawer (bool shouldBeOpen)
  714. {
  715. if (shouldBeOpen)
  716. {
  717. if (controller != nullptr)
  718. {
  719. controller->shutDown();
  720. controller = nullptr;
  721. }
  722. if (scsiHandle != 0)
  723. {
  724. CloseHandle (scsiHandle);
  725. scsiHandle = 0;
  726. }
  727. }
  728. SRB_ExecSCSICmd s = { 0 };
  729. s.SRB_Cmd = SC_EXEC_SCSI_CMD;
  730. s.SRB_HaID = info.ha;
  731. s.SRB_Target = info.tgt;
  732. s.SRB_Lun = info.lun;
  733. s.SRB_SenseLen = SENSE_LEN;
  734. s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
  735. s.SRB_BufLen = 0;
  736. s.SRB_BufPointer = 0;
  737. s.SRB_CDBLen = 12;
  738. s.CDBByte[0] = 0x1b;
  739. s.CDBByte[1] = (BYTE) (info.lun << 5);
  740. s.CDBByte[4] = (BYTE) (shouldBeOpen ? 2 : 3);
  741. s.SRB_PostProc = CreateEvent (0, TRUE, FALSE, 0);
  742. performScsiCommand (s.SRB_PostProc, s);
  743. }
  744. bool CDDeviceHandle::testController (const int type, CDController* const newController, CDReadBuffer& rb)
  745. {
  746. controller = newController;
  747. readType = (BYTE) type;
  748. controller->deviceInfo = this;
  749. controller->framesToCheck = 1;
  750. controller->framesOverlap = 3;
  751. bool passed = false;
  752. memset (rb.buffer, 0xcd, rb.bufferSize);
  753. if (controller->read (rb))
  754. {
  755. passed = true;
  756. int* p = (int*) (rb.buffer + rb.dataStartOffset);
  757. int wrong = 0;
  758. for (int i = rb.dataLength / 4; --i >= 0;)
  759. {
  760. if (*p++ == (int) 0xcdcdcdcd)
  761. {
  762. if (++wrong == 4)
  763. {
  764. passed = false;
  765. break;
  766. }
  767. }
  768. else
  769. {
  770. wrong = 0;
  771. }
  772. }
  773. }
  774. if (! passed)
  775. {
  776. controller->shutDown();
  777. controller = nullptr;
  778. }
  779. return passed;
  780. }
  781. //==============================================================================
  782. struct CDDeviceWrapper
  783. {
  784. CDDeviceWrapper (const CDDeviceDescription& device, HANDLE scsiHandle)
  785. : deviceHandle (device, scsiHandle), overlapBuffer (3), jitter (false)
  786. {
  787. // xxx jitter never seemed to actually be enabled (??)
  788. }
  789. CDDeviceHandle deviceHandle;
  790. CDReadBuffer overlapBuffer;
  791. bool jitter;
  792. };
  793. //==============================================================================
  794. int getAddressOfTrack (const TOCTRACK& t) noexcept
  795. {
  796. return (((DWORD) t.addr[0]) << 24) + (((DWORD) t.addr[1]) << 16)
  797. + (((DWORD) t.addr[2]) << 8) + ((DWORD) t.addr[3]);
  798. }
  799. const int samplesPerFrame = 44100 / 75;
  800. const int bytesPerFrame = samplesPerFrame * 4;
  801. const int framesPerIndexRead = 4;
  802. }
  803. //==============================================================================
  804. StringArray AudioCDReader::getAvailableCDNames()
  805. {
  806. using namespace CDReaderHelpers;
  807. StringArray results;
  808. Array<CDDeviceDescription> list;
  809. findCDDevices (list);
  810. for (int i = 0; i < list.size(); ++i)
  811. {
  812. String s;
  813. if (list[i].scsiDriveLetter > 0)
  814. s << String::charToString (list[i].scsiDriveLetter).toUpperCase() << ": ";
  815. s << list[i].description;
  816. results.add (s);
  817. }
  818. return results;
  819. }
  820. AudioCDReader* AudioCDReader::createReaderForCD (const int deviceIndex)
  821. {
  822. using namespace CDReaderHelpers;
  823. Array<CDDeviceDescription> list;
  824. findCDDevices (list);
  825. if (isPositiveAndBelow (deviceIndex, list.size()))
  826. {
  827. HANDLE h = createSCSIDeviceHandle (list [deviceIndex].scsiDriveLetter);
  828. if (h != INVALID_HANDLE_VALUE)
  829. {
  830. ScopedPointer<AudioCDReader> cd (new AudioCDReader (new CDDeviceWrapper (list [deviceIndex], h)));
  831. if (cd->lengthInSamples > 0)
  832. return cd.release();
  833. }
  834. }
  835. return nullptr;
  836. }
  837. AudioCDReader::AudioCDReader (void* handle_)
  838. : AudioFormatReader (0, "CD Audio"),
  839. handle (handle_),
  840. indexingEnabled (false),
  841. lastIndex (0),
  842. firstFrameInBuffer (0),
  843. samplesInBuffer (0)
  844. {
  845. using namespace CDReaderHelpers;
  846. jassert (handle_ != nullptr);
  847. refreshTrackLengths();
  848. sampleRate = 44100.0;
  849. bitsPerSample = 16;
  850. numChannels = 2;
  851. usesFloatingPointData = false;
  852. buffer.setSize (4 * bytesPerFrame, true);
  853. }
  854. AudioCDReader::~AudioCDReader()
  855. {
  856. using namespace CDReaderHelpers;
  857. CDDeviceWrapper* const device = static_cast <CDDeviceWrapper*> (handle);
  858. delete device;
  859. }
  860. bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
  861. int64 startSampleInFile, int numSamples)
  862. {
  863. using namespace CDReaderHelpers;
  864. CDDeviceWrapper* const device = static_cast <CDDeviceWrapper*> (handle);
  865. bool ok = true;
  866. while (numSamples > 0)
  867. {
  868. const int bufferStartSample = firstFrameInBuffer * samplesPerFrame;
  869. const int bufferEndSample = bufferStartSample + samplesInBuffer;
  870. if (startSampleInFile >= bufferStartSample
  871. && startSampleInFile < bufferEndSample)
  872. {
  873. const int toDo = (int) jmin ((int64) numSamples, bufferEndSample - startSampleInFile);
  874. int* const l = destSamples[0] + startOffsetInDestBuffer;
  875. int* const r = numDestChannels > 1 ? (destSamples[1] + startOffsetInDestBuffer) : nullptr;
  876. const short* src = (const short*) buffer.getData();
  877. src += 2 * (startSampleInFile - bufferStartSample);
  878. for (int i = 0; i < toDo; ++i)
  879. {
  880. l[i] = src [i << 1] << 16;
  881. if (r != nullptr)
  882. r[i] = src [(i << 1) + 1] << 16;
  883. }
  884. startOffsetInDestBuffer += toDo;
  885. startSampleInFile += toDo;
  886. numSamples -= toDo;
  887. }
  888. else
  889. {
  890. const int framesInBuffer = buffer.getSize() / bytesPerFrame;
  891. const int frameNeeded = (int) (startSampleInFile / samplesPerFrame);
  892. if (firstFrameInBuffer + framesInBuffer != frameNeeded)
  893. {
  894. device->overlapBuffer.dataLength = 0;
  895. device->overlapBuffer.startFrame = 0;
  896. device->overlapBuffer.numFrames = 0;
  897. device->jitter = false;
  898. }
  899. firstFrameInBuffer = frameNeeded;
  900. lastIndex = 0;
  901. CDReadBuffer readBuffer (framesInBuffer + 4);
  902. readBuffer.wantsIndex = indexingEnabled;
  903. int i;
  904. for (i = 5; --i >= 0;)
  905. {
  906. readBuffer.startFrame = frameNeeded;
  907. readBuffer.numFrames = framesInBuffer;
  908. if (device->deviceHandle.readAudio (readBuffer, device->jitter ? &device->overlapBuffer : 0))
  909. break;
  910. else
  911. device->overlapBuffer.dataLength = 0;
  912. }
  913. if (i >= 0)
  914. {
  915. buffer.copyFrom (readBuffer.buffer + readBuffer.dataStartOffset, 0, readBuffer.dataLength);
  916. samplesInBuffer = readBuffer.dataLength >> 2;
  917. lastIndex = readBuffer.index;
  918. }
  919. else
  920. {
  921. int* l = destSamples[0] + startOffsetInDestBuffer;
  922. int* r = numDestChannels > 1 ? (destSamples[1] + startOffsetInDestBuffer) : nullptr;
  923. while (--numSamples >= 0)
  924. {
  925. *l++ = 0;
  926. if (r != nullptr)
  927. *r++ = 0;
  928. }
  929. // sometimes the read fails for just the very last couple of blocks, so
  930. // we'll ignore and errors in the last half-second of the disk..
  931. ok = startSampleInFile > (trackStartSamples [getNumTracks()] - 20000);
  932. break;
  933. }
  934. }
  935. }
  936. return ok;
  937. }
  938. bool AudioCDReader::isCDStillPresent() const
  939. {
  940. using namespace CDReaderHelpers;
  941. TOC toc = { 0 };
  942. return static_cast <CDDeviceWrapper*> (handle)->deviceHandle.readTOC (&toc);
  943. }
  944. void AudioCDReader::refreshTrackLengths()
  945. {
  946. using namespace CDReaderHelpers;
  947. trackStartSamples.clear();
  948. zeromem (audioTracks, sizeof (audioTracks));
  949. TOC toc = { 0 };
  950. if (static_cast <CDDeviceWrapper*> (handle)->deviceHandle.readTOC (&toc))
  951. {
  952. int numTracks = 1 + toc.lastTrack - toc.firstTrack;
  953. for (int i = 0; i <= numTracks; ++i)
  954. {
  955. trackStartSamples.add (samplesPerFrame * getAddressOfTrack (toc.tracks [i]));
  956. audioTracks [i] = ((toc.tracks[i].ADR & 4) == 0);
  957. }
  958. }
  959. lengthInSamples = getPositionOfTrackStart (getNumTracks());
  960. }
  961. bool AudioCDReader::isTrackAudio (int trackNum) const
  962. {
  963. return trackNum >= 0 && trackNum < getNumTracks() && audioTracks [trackNum];
  964. }
  965. void AudioCDReader::enableIndexScanning (bool b)
  966. {
  967. indexingEnabled = b;
  968. }
  969. int AudioCDReader::getLastIndex() const
  970. {
  971. return lastIndex;
  972. }
  973. int AudioCDReader::getIndexAt (int samplePos)
  974. {
  975. using namespace CDReaderHelpers;
  976. CDDeviceWrapper* const device = static_cast <CDDeviceWrapper*> (handle);
  977. const int frameNeeded = samplePos / samplesPerFrame;
  978. device->overlapBuffer.dataLength = 0;
  979. device->overlapBuffer.startFrame = 0;
  980. device->overlapBuffer.numFrames = 0;
  981. device->jitter = false;
  982. firstFrameInBuffer = 0;
  983. lastIndex = 0;
  984. CDReadBuffer readBuffer (4 + framesPerIndexRead);
  985. readBuffer.wantsIndex = true;
  986. int i;
  987. for (i = 5; --i >= 0;)
  988. {
  989. readBuffer.startFrame = frameNeeded;
  990. readBuffer.numFrames = framesPerIndexRead;
  991. if (device->deviceHandle.readAudio (readBuffer))
  992. break;
  993. }
  994. if (i >= 0)
  995. return readBuffer.index;
  996. return -1;
  997. }
  998. Array<int> AudioCDReader::findIndexesInTrack (const int trackNumber)
  999. {
  1000. using namespace CDReaderHelpers;
  1001. Array <int> indexes;
  1002. const int trackStart = getPositionOfTrackStart (trackNumber);
  1003. const int trackEnd = getPositionOfTrackStart (trackNumber + 1);
  1004. bool needToScan = true;
  1005. if (trackEnd - trackStart > 20 * 44100)
  1006. {
  1007. // check the end of the track for indexes before scanning the whole thing
  1008. needToScan = false;
  1009. int pos = jmax (trackStart, trackEnd - 44100 * 5);
  1010. bool seenAnIndex = false;
  1011. while (pos <= trackEnd - samplesPerFrame)
  1012. {
  1013. const int index = getIndexAt (pos);
  1014. if (index == 0)
  1015. {
  1016. // lead-out, so skip back a bit if we've not found any indexes yet..
  1017. if (seenAnIndex)
  1018. break;
  1019. pos -= 44100 * 5;
  1020. if (pos < trackStart)
  1021. break;
  1022. }
  1023. else
  1024. {
  1025. if (index > 0)
  1026. seenAnIndex = true;
  1027. if (index > 1)
  1028. {
  1029. needToScan = true;
  1030. break;
  1031. }
  1032. pos += samplesPerFrame * framesPerIndexRead;
  1033. }
  1034. }
  1035. }
  1036. if (needToScan)
  1037. {
  1038. CDDeviceWrapper* const device = static_cast <CDDeviceWrapper*> (handle);
  1039. int pos = trackStart;
  1040. int last = -1;
  1041. while (pos < trackEnd - samplesPerFrame * 10)
  1042. {
  1043. const int frameNeeded = pos / samplesPerFrame;
  1044. device->overlapBuffer.dataLength = 0;
  1045. device->overlapBuffer.startFrame = 0;
  1046. device->overlapBuffer.numFrames = 0;
  1047. device->jitter = false;
  1048. firstFrameInBuffer = 0;
  1049. CDReadBuffer readBuffer (4);
  1050. readBuffer.wantsIndex = true;
  1051. int i;
  1052. for (i = 5; --i >= 0;)
  1053. {
  1054. readBuffer.startFrame = frameNeeded;
  1055. readBuffer.numFrames = framesPerIndexRead;
  1056. if (device->deviceHandle.readAudio (readBuffer))
  1057. break;
  1058. }
  1059. if (i < 0)
  1060. break;
  1061. if (readBuffer.index > last && readBuffer.index > 1)
  1062. {
  1063. last = readBuffer.index;
  1064. indexes.add (pos);
  1065. }
  1066. pos += samplesPerFrame * framesPerIndexRead;
  1067. }
  1068. indexes.removeFirstMatchingValue (trackStart);
  1069. }
  1070. return indexes;
  1071. }
  1072. void AudioCDReader::ejectDisk()
  1073. {
  1074. using namespace CDReaderHelpers;
  1075. static_cast <CDDeviceWrapper*> (handle)->deviceHandle.openDrawer (true);
  1076. }