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.

1312 lines
37KB

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