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.

1309 lines
36KB

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