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.

1316 lines
37KB

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