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.

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