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.

1626 lines
55KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #undef WINDOWS
  19. #undef log
  20. /* The ASIO SDK *should* declare its callback functions as being __cdecl, but different versions seem
  21. to be pretty random about whether or not they do this. If you hit an error using these functions
  22. it'll be because you're trying to build using __stdcall, in which case you'd need to either get hold of
  23. an ASIO SDK which correctly specifies __cdecl, or add the __cdecl keyword to its functions yourself.
  24. */
  25. #define JUCE_ASIOCALLBACK __cdecl
  26. //==============================================================================
  27. namespace ASIODebugging
  28. {
  29. #if ASIO_DEBUGGING
  30. static void log (const String& context, long error)
  31. {
  32. const char* err = "unknown error";
  33. if (error == ASE_NotPresent) err = "Not Present";
  34. else if (error == ASE_HWMalfunction) err = "Hardware Malfunction";
  35. else if (error == ASE_InvalidParameter) err = "Invalid Parameter";
  36. else if (error == ASE_InvalidMode) err = "Invalid Mode";
  37. else if (error == ASE_SPNotAdvancing) err = "Sample position not advancing";
  38. else if (error == ASE_NoClock) err = "No Clock";
  39. else if (error == ASE_NoMemory) err = "Out of memory";
  40. log ("ASIO error: " + context + " - " + err);
  41. }
  42. #define log(a) { Logger::writeToLog (a); DBG (a) }
  43. #define logError(a, b) ASIODebugging::log ((a), (b))
  44. #else
  45. #define log(a) {}
  46. #define logError(a, b) {}
  47. #endif
  48. }
  49. //==============================================================================
  50. struct ASIOSampleFormat
  51. {
  52. ASIOSampleFormat() noexcept {}
  53. ASIOSampleFormat (const long type) noexcept
  54. : bitDepth (24),
  55. littleEndian (true),
  56. formatIsFloat (false),
  57. byteStride (4)
  58. {
  59. switch (type)
  60. {
  61. case ASIOSTInt16MSB: byteStride = 2; littleEndian = false; bitDepth = 16; break;
  62. case ASIOSTInt24MSB: byteStride = 3; littleEndian = false; break;
  63. case ASIOSTInt32MSB: bitDepth = 32; littleEndian = false; break;
  64. case ASIOSTFloat32MSB: bitDepth = 32; littleEndian = false; formatIsFloat = true; break;
  65. case ASIOSTFloat64MSB: bitDepth = 64; byteStride = 8; littleEndian = false; break;
  66. case ASIOSTInt32MSB16: bitDepth = 16; littleEndian = false; break;
  67. case ASIOSTInt32MSB18: littleEndian = false; break;
  68. case ASIOSTInt32MSB20: littleEndian = false; break;
  69. case ASIOSTInt32MSB24: littleEndian = false; break;
  70. case ASIOSTInt16LSB: byteStride = 2; bitDepth = 16; break;
  71. case ASIOSTInt24LSB: byteStride = 3; break;
  72. case ASIOSTInt32LSB: bitDepth = 32; break;
  73. case ASIOSTFloat32LSB: bitDepth = 32; formatIsFloat = true; break;
  74. case ASIOSTFloat64LSB: bitDepth = 64; byteStride = 8; break;
  75. case ASIOSTInt32LSB16: bitDepth = 16; break;
  76. case ASIOSTInt32LSB18: break; // (unhandled)
  77. case ASIOSTInt32LSB20: break; // (unhandled)
  78. case ASIOSTInt32LSB24: break;
  79. case ASIOSTDSDInt8LSB1: break; // (unhandled)
  80. case ASIOSTDSDInt8MSB1: break; // (unhandled)
  81. case ASIOSTDSDInt8NER8: break; // (unhandled)
  82. default:
  83. jassertfalse; // (not a valid format code..)
  84. break;
  85. }
  86. }
  87. void convertToFloat (const void* const src, float* const dst, const int samps) const noexcept
  88. {
  89. if (formatIsFloat)
  90. {
  91. memcpy (dst, src, samps * sizeof (float));
  92. }
  93. else
  94. {
  95. switch (bitDepth)
  96. {
  97. case 16: convertInt16ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
  98. case 24: convertInt24ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
  99. case 32: convertInt32ToFloat (static_cast <const char*> (src), dst, byteStride, samps, littleEndian); break;
  100. default: jassertfalse; break;
  101. }
  102. }
  103. }
  104. void convertFromFloat (const float* const src, void* const dst, const int samps) const noexcept
  105. {
  106. if (formatIsFloat)
  107. {
  108. memcpy (dst, src, samps * sizeof (float));
  109. }
  110. else
  111. {
  112. switch (bitDepth)
  113. {
  114. case 16: convertFloatToInt16 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
  115. case 24: convertFloatToInt24 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
  116. case 32: convertFloatToInt32 (src, static_cast <char*> (dst), byteStride, samps, littleEndian); break;
  117. default: jassertfalse; break;
  118. }
  119. }
  120. }
  121. void clear (void* dst, const int numSamps) noexcept
  122. {
  123. if (dst != nullptr)
  124. zeromem (dst, numSamps * byteStride);
  125. }
  126. int bitDepth, byteStride;
  127. bool formatIsFloat, littleEndian;
  128. private:
  129. static void convertInt16ToFloat (const char* src, float* dest, const int srcStrideBytes,
  130. int numSamples, const bool littleEndian) noexcept
  131. {
  132. const double g = 1.0 / 32768.0;
  133. if (littleEndian)
  134. {
  135. while (--numSamples >= 0)
  136. {
  137. *dest++ = (float) (g * (short) ByteOrder::littleEndianShort (src));
  138. src += srcStrideBytes;
  139. }
  140. }
  141. else
  142. {
  143. while (--numSamples >= 0)
  144. {
  145. *dest++ = (float) (g * (short) ByteOrder::bigEndianShort (src));
  146. src += srcStrideBytes;
  147. }
  148. }
  149. }
  150. static void convertFloatToInt16 (const float* src, char* dest, const int dstStrideBytes,
  151. int numSamples, const bool littleEndian) noexcept
  152. {
  153. const double maxVal = (double) 0x7fff;
  154. if (littleEndian)
  155. {
  156. while (--numSamples >= 0)
  157. {
  158. *(uint16*) dest = ByteOrder::swapIfBigEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  159. dest += dstStrideBytes;
  160. }
  161. }
  162. else
  163. {
  164. while (--numSamples >= 0)
  165. {
  166. *(uint16*) dest = ByteOrder::swapIfLittleEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  167. dest += dstStrideBytes;
  168. }
  169. }
  170. }
  171. static void convertInt24ToFloat (const char* src, float* dest, const int srcStrideBytes,
  172. int numSamples, const bool littleEndian) noexcept
  173. {
  174. const double g = 1.0 / 0x7fffff;
  175. if (littleEndian)
  176. {
  177. while (--numSamples >= 0)
  178. {
  179. *dest++ = (float) (g * ByteOrder::littleEndian24Bit (src));
  180. src += srcStrideBytes;
  181. }
  182. }
  183. else
  184. {
  185. while (--numSamples >= 0)
  186. {
  187. *dest++ = (float) (g * ByteOrder::bigEndian24Bit (src));
  188. src += srcStrideBytes;
  189. }
  190. }
  191. }
  192. static void convertFloatToInt24 (const float* src, char* dest, const int dstStrideBytes,
  193. int numSamples, const bool littleEndian) noexcept
  194. {
  195. const double maxVal = (double) 0x7fffff;
  196. if (littleEndian)
  197. {
  198. while (--numSamples >= 0)
  199. {
  200. ByteOrder::littleEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)), dest);
  201. dest += dstStrideBytes;
  202. }
  203. }
  204. else
  205. {
  206. while (--numSamples >= 0)
  207. {
  208. ByteOrder::bigEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)), dest);
  209. dest += dstStrideBytes;
  210. }
  211. }
  212. }
  213. static void convertInt32ToFloat (const char* src, float* dest, const int srcStrideBytes,
  214. int numSamples, const bool littleEndian) noexcept
  215. {
  216. const double g = 1.0 / 0x7fffffff;
  217. if (littleEndian)
  218. {
  219. while (--numSamples >= 0)
  220. {
  221. *dest++ = (float) (g * (int) ByteOrder::littleEndianInt (src));
  222. src += srcStrideBytes;
  223. }
  224. }
  225. else
  226. {
  227. while (--numSamples >= 0)
  228. {
  229. *dest++ = (float) (g * (int) ByteOrder::bigEndianInt (src));
  230. src += srcStrideBytes;
  231. }
  232. }
  233. }
  234. static void convertFloatToInt32 (const float* src, char* dest, const int dstStrideBytes,
  235. int numSamples, const bool littleEndian) noexcept
  236. {
  237. const double maxVal = (double) 0x7fffffff;
  238. if (littleEndian)
  239. {
  240. while (--numSamples >= 0)
  241. {
  242. *(uint32*) dest = ByteOrder::swapIfBigEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  243. dest += dstStrideBytes;
  244. }
  245. }
  246. else
  247. {
  248. while (--numSamples >= 0)
  249. {
  250. *(uint32*) dest = ByteOrder::swapIfLittleEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  251. dest += dstStrideBytes;
  252. }
  253. }
  254. }
  255. };
  256. //==============================================================================
  257. class ASIOAudioIODevice;
  258. static ASIOAudioIODevice* volatile currentASIODev[3] = { 0 };
  259. extern HWND juce_messageWindowHandle;
  260. //==============================================================================
  261. class ASIOAudioIODevice : public AudioIODevice,
  262. private Timer
  263. {
  264. public:
  265. ASIOAudioIODevice (const String& devName, const CLSID clsID, const int slotNumber,
  266. const String& dllForDirectLoading)
  267. : AudioIODevice (devName, "ASIO"),
  268. asioObject (nullptr),
  269. classId (clsID),
  270. optionalDllForDirectLoading (dllForDirectLoading),
  271. currentBitDepth (16),
  272. currentSampleRate (0),
  273. deviceIsOpen (false),
  274. isStarted (false),
  275. buffersCreated (false),
  276. postOutput (true),
  277. insideControlPanelModalLoop (false),
  278. shouldUsePreferredSize (false)
  279. {
  280. name = devName;
  281. inBuffers.calloc (4);
  282. outBuffers.calloc (4);
  283. jassert (currentASIODev [slotNumber] == nullptr);
  284. currentASIODev [slotNumber] = this;
  285. openDevice();
  286. }
  287. ~ASIOAudioIODevice()
  288. {
  289. for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
  290. if (currentASIODev[i] == this)
  291. currentASIODev[i] = nullptr;
  292. close();
  293. log ("ASIO - exiting");
  294. removeCurrentDriver();
  295. }
  296. void updateSampleRates()
  297. {
  298. // find a list of sample rates..
  299. const double possibleSampleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
  300. sampleRates.clear();
  301. if (asioObject != nullptr)
  302. {
  303. for (int index = 0; index < numElementsInArray (possibleSampleRates); ++index)
  304. {
  305. const long err = asioObject->canSampleRate (possibleSampleRates[index]);
  306. if (err == 0)
  307. {
  308. sampleRates.add ((int) possibleSampleRates[index]);
  309. log ("rate: " + String ((int) possibleSampleRates[index]));
  310. }
  311. else if (err != ASE_NoClock)
  312. {
  313. logError ("CanSampleRate", err);
  314. }
  315. }
  316. if (sampleRates.size() == 0)
  317. {
  318. double cr = 0;
  319. const long err = asioObject->getSampleRate (&cr);
  320. log ("No sample rates supported - current rate: " + String ((int) cr));
  321. if (err == 0)
  322. sampleRates.add ((int) cr);
  323. }
  324. }
  325. }
  326. StringArray getOutputChannelNames() { return outputChannelNames; }
  327. StringArray getInputChannelNames() { return inputChannelNames; }
  328. int getNumSampleRates() { return sampleRates.size(); }
  329. double getSampleRate (int index) { return sampleRates [index]; }
  330. int getNumBufferSizesAvailable() { return bufferSizes.size(); }
  331. int getBufferSizeSamples (int index) { return bufferSizes [index]; }
  332. int getDefaultBufferSize() { return preferredSize; }
  333. String open (const BigInteger& inputChannels,
  334. const BigInteger& outputChannels,
  335. double sr,
  336. int bufferSizeSamples)
  337. {
  338. close();
  339. currentCallback = nullptr;
  340. if (bufferSizeSamples <= 0)
  341. shouldUsePreferredSize = true;
  342. if (asioObject == nullptr || ! isASIOOpen)
  343. {
  344. log ("Warning: device not open");
  345. const String err (openDevice());
  346. if (asioObject == nullptr || ! isASIOOpen)
  347. return err;
  348. }
  349. isStarted = false;
  350. bufferIndex = -1;
  351. long err = 0;
  352. long newPreferredSize = 0;
  353. minSize = 0;
  354. maxSize = 0;
  355. granularity = 0;
  356. if (asioObject->getBufferSize (&minSize, &maxSize, &newPreferredSize, &granularity) == 0)
  357. {
  358. if (preferredSize != 0 && newPreferredSize != 0 && newPreferredSize != preferredSize)
  359. shouldUsePreferredSize = true;
  360. preferredSize = newPreferredSize;
  361. }
  362. // unfortunate workaround for certain manufacturers whose drivers crash horribly if you make
  363. // dynamic changes to the buffer size...
  364. shouldUsePreferredSize = shouldUsePreferredSize
  365. || getName().containsIgnoreCase ("Digidesign");
  366. if (shouldUsePreferredSize)
  367. {
  368. log ("Using preferred size for buffer..");
  369. if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == 0)
  370. {
  371. bufferSizeSamples = preferredSize;
  372. }
  373. else
  374. {
  375. bufferSizeSamples = 1024;
  376. logError ("GetBufferSize1", err);
  377. }
  378. shouldUsePreferredSize = false;
  379. }
  380. int sampleRate = roundDoubleToInt (sr);
  381. currentSampleRate = sampleRate;
  382. currentBlockSizeSamples = bufferSizeSamples;
  383. currentChansOut.clear();
  384. currentChansIn.clear();
  385. inBuffers.clear (totalNumInputChans + 1);
  386. outBuffers.clear (totalNumOutputChans + 1);
  387. updateSampleRates();
  388. if (sampleRate == 0 || (sampleRates.size() > 0 && ! sampleRates.contains (sampleRate)))
  389. sampleRate = sampleRates[0];
  390. jassert (sampleRate != 0);
  391. if (sampleRate == 0)
  392. sampleRate = 44100;
  393. ASIOClockSource clocks[32] = { 0 };
  394. long numSources = numElementsInArray (clocks);
  395. asioObject->getClockSources (clocks, &numSources);
  396. bool isSourceSet = false;
  397. // careful not to remove this loop because it does more than just logging!
  398. for (int i = 0; i < numSources; ++i)
  399. {
  400. String s ("clock: ");
  401. s += clocks[i].name;
  402. if (clocks[i].isCurrentSource)
  403. {
  404. isSourceSet = true;
  405. s << " (cur)";
  406. }
  407. log (s);
  408. }
  409. if (numSources > 1 && ! isSourceSet)
  410. {
  411. log ("setting clock source");
  412. asioObject->setClockSource (clocks[0].index);
  413. Thread::sleep (20);
  414. }
  415. else
  416. {
  417. if (numSources == 0)
  418. {
  419. log ("ASIO - no clock sources!");
  420. }
  421. }
  422. double cr = 0;
  423. err = asioObject->getSampleRate (&cr);
  424. if (err == 0)
  425. {
  426. currentSampleRate = cr;
  427. }
  428. else
  429. {
  430. logError ("GetSampleRate", err);
  431. currentSampleRate = 0;
  432. }
  433. error = String::empty;
  434. needToReset = false;
  435. isReSync = false;
  436. err = 0;
  437. buffersCreated = false;
  438. if (currentSampleRate != sampleRate)
  439. {
  440. log ("ASIO samplerate: " + String (currentSampleRate) + " to " + String (sampleRate));
  441. err = asioObject->setSampleRate (sampleRate);
  442. if (err == ASE_NoClock && numSources > 0)
  443. {
  444. log ("trying to set a clock source..");
  445. Thread::sleep (10);
  446. err = asioObject->setClockSource (clocks[0].index);
  447. if (err != 0)
  448. {
  449. logError ("SetClock", err);
  450. }
  451. Thread::sleep (10);
  452. err = asioObject->setSampleRate (sampleRate);
  453. }
  454. }
  455. if (err == 0)
  456. {
  457. currentSampleRate = sampleRate;
  458. if (needToReset)
  459. {
  460. if (isReSync)
  461. {
  462. log ("Resync request");
  463. }
  464. log ("! Resetting ASIO after sample rate change");
  465. removeCurrentDriver();
  466. loadDriver();
  467. const String error (initDriver());
  468. if (error.isNotEmpty())
  469. {
  470. log ("ASIOInit: " + error);
  471. }
  472. needToReset = false;
  473. isReSync = false;
  474. }
  475. numActiveInputChans = 0;
  476. numActiveOutputChans = 0;
  477. ASIOBufferInfo* info = bufferInfos;
  478. for (int i = 0; i < totalNumInputChans; ++i)
  479. {
  480. if (inputChannels[i])
  481. {
  482. currentChansIn.setBit (i);
  483. info->isInput = 1;
  484. info->channelNum = i;
  485. info->buffers[0] = info->buffers[1] = nullptr;
  486. ++info;
  487. ++numActiveInputChans;
  488. }
  489. }
  490. for (int i = 0; i < totalNumOutputChans; ++i)
  491. {
  492. if (outputChannels[i])
  493. {
  494. currentChansOut.setBit (i);
  495. info->isInput = 0;
  496. info->channelNum = i;
  497. info->buffers[0] = info->buffers[1] = nullptr;
  498. ++info;
  499. ++numActiveOutputChans;
  500. }
  501. }
  502. const int totalBuffers = numActiveInputChans + numActiveOutputChans;
  503. setCallbackFunctions();
  504. log ("disposing buffers");
  505. err = asioObject->disposeBuffers();
  506. log ("creating buffers: " + String (totalBuffers) + ", " + String (currentBlockSizeSamples));
  507. err = asioObject->createBuffers (bufferInfos,
  508. totalBuffers,
  509. currentBlockSizeSamples,
  510. &callbacks);
  511. if (err != 0)
  512. {
  513. currentBlockSizeSamples = preferredSize;
  514. logError ("create buffers 2", err);
  515. asioObject->disposeBuffers();
  516. err = asioObject->createBuffers (bufferInfos,
  517. totalBuffers,
  518. currentBlockSizeSamples,
  519. &callbacks);
  520. }
  521. if (err == 0)
  522. {
  523. buffersCreated = true;
  524. tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32);
  525. int n = 0;
  526. Array <int> types;
  527. currentBitDepth = 16;
  528. for (int i = 0; i < (int) totalNumInputChans; ++i)
  529. {
  530. if (inputChannels[i])
  531. {
  532. inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n);
  533. ASIOChannelInfo channelInfo = { 0 };
  534. channelInfo.channel = i;
  535. channelInfo.isInput = 1;
  536. asioObject->getChannelInfo (&channelInfo);
  537. types.addIfNotAlreadyThere (channelInfo.type);
  538. inputFormat[n] = ASIOSampleFormat (channelInfo.type);
  539. currentBitDepth = jmax (currentBitDepth, inputFormat[n].bitDepth);
  540. ++n;
  541. }
  542. }
  543. jassert (numActiveInputChans == n);
  544. n = 0;
  545. for (int i = 0; i < (int) totalNumOutputChans; ++i)
  546. {
  547. if (outputChannels[i])
  548. {
  549. outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n));
  550. ASIOChannelInfo channelInfo = { 0 };
  551. channelInfo.channel = i;
  552. channelInfo.isInput = 0;
  553. asioObject->getChannelInfo (&channelInfo);
  554. types.addIfNotAlreadyThere (channelInfo.type);
  555. outputFormat[n] = ASIOSampleFormat (channelInfo.type);
  556. currentBitDepth = jmax (currentBitDepth, outputFormat[n].bitDepth);
  557. ++n;
  558. }
  559. }
  560. jassert (numActiveOutputChans == n);
  561. for (int i = types.size(); --i >= 0;)
  562. {
  563. log ("channel format: " + String (types[i]));
  564. }
  565. jassert (n <= totalBuffers);
  566. for (int i = 0; i < numActiveOutputChans; ++i)
  567. {
  568. outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[0], currentBlockSizeSamples);
  569. outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[1], currentBlockSizeSamples);
  570. }
  571. inputLatency = outputLatency = 0;
  572. if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
  573. {
  574. log ("ASIO - no latencies");
  575. }
  576. else
  577. {
  578. log ("ASIO latencies: " + String ((int) outputLatency) + ", " + String ((int) inputLatency));
  579. }
  580. deviceIsOpen = true;
  581. log ("starting ASIO");
  582. calledback = false;
  583. err = asioObject->start();
  584. if (err != 0)
  585. {
  586. deviceIsOpen = false;
  587. log ("ASIO - stop on failure");
  588. Thread::sleep (10);
  589. asioObject->stop();
  590. error = "Can't start device";
  591. Thread::sleep (10);
  592. }
  593. else
  594. {
  595. int count = 300;
  596. while (--count > 0 && ! calledback)
  597. Thread::sleep (10);
  598. isStarted = true;
  599. if (! calledback)
  600. {
  601. error = "Device didn't start correctly";
  602. log ("ASIO didn't callback - stopping..");
  603. asioObject->stop();
  604. }
  605. }
  606. }
  607. else
  608. {
  609. error = "Can't create i/o buffers";
  610. }
  611. }
  612. else
  613. {
  614. error = "Can't set sample rate: ";
  615. error << sampleRate;
  616. }
  617. if (error.isNotEmpty())
  618. {
  619. logError (error, err);
  620. disposeBuffers();
  621. Thread::sleep (20);
  622. isStarted = false;
  623. deviceIsOpen = false;
  624. const String errorCopy (error);
  625. close(); // (this resets the error string)
  626. error = errorCopy;
  627. }
  628. needToReset = false;
  629. isReSync = false;
  630. return error;
  631. }
  632. void close()
  633. {
  634. error = String::empty;
  635. stopTimer();
  636. stop();
  637. if (isASIOOpen && deviceIsOpen)
  638. {
  639. const ScopedLock sl (callbackLock);
  640. deviceIsOpen = false;
  641. isStarted = false;
  642. needToReset = false;
  643. isReSync = false;
  644. log ("ASIO - stopping");
  645. if (asioObject != nullptr)
  646. {
  647. Thread::sleep (20);
  648. asioObject->stop();
  649. Thread::sleep (10);
  650. disposeBuffers();
  651. }
  652. Thread::sleep (10);
  653. }
  654. }
  655. bool isOpen() { return deviceIsOpen || insideControlPanelModalLoop; }
  656. bool isPlaying() { return isASIOOpen && (currentCallback != nullptr); }
  657. int getCurrentBufferSizeSamples() { return currentBlockSizeSamples; }
  658. double getCurrentSampleRate() { return currentSampleRate; }
  659. int getCurrentBitDepth() { return currentBitDepth; }
  660. BigInteger getActiveOutputChannels() const { return currentChansOut; }
  661. BigInteger getActiveInputChannels() const { return currentChansIn; }
  662. int getOutputLatencyInSamples() { return outputLatency + currentBlockSizeSamples / 4; }
  663. int getInputLatencyInSamples() { return inputLatency + currentBlockSizeSamples / 4; }
  664. void start (AudioIODeviceCallback* callback)
  665. {
  666. if (callback != nullptr)
  667. {
  668. callback->audioDeviceAboutToStart (this);
  669. const ScopedLock sl (callbackLock);
  670. currentCallback = callback;
  671. }
  672. }
  673. void stop()
  674. {
  675. AudioIODeviceCallback* const lastCallback = currentCallback;
  676. {
  677. const ScopedLock sl (callbackLock);
  678. currentCallback = nullptr;
  679. }
  680. if (lastCallback != nullptr)
  681. lastCallback->audioDeviceStopped();
  682. }
  683. String getLastError() { return error; }
  684. bool hasControlPanel() const { return true; }
  685. bool showControlPanel()
  686. {
  687. log ("ASIO - showing control panel");
  688. bool done = false;
  689. JUCE_TRY
  690. {
  691. // are there are devices that need to be closed before showing their control panel?
  692. // close();
  693. insideControlPanelModalLoop = true;
  694. const uint32 started = Time::getMillisecondCounter();
  695. if (asioObject != nullptr)
  696. {
  697. asioObject->controlPanel();
  698. const int spent = (int) Time::getMillisecondCounter() - (int) started;
  699. log ("spent: " + String (spent));
  700. if (spent > 300)
  701. {
  702. shouldUsePreferredSize = true;
  703. done = true;
  704. }
  705. }
  706. }
  707. JUCE_CATCH_ALL
  708. insideControlPanelModalLoop = false;
  709. return done;
  710. }
  711. void resetRequest() noexcept
  712. {
  713. needToReset = true;
  714. }
  715. void resyncRequest() noexcept
  716. {
  717. needToReset = true;
  718. isReSync = true;
  719. }
  720. void timerCallback()
  721. {
  722. if (! insideControlPanelModalLoop)
  723. {
  724. stopTimer();
  725. // used to cause a reset
  726. log ("! ASIO restart request!");
  727. if (deviceIsOpen)
  728. {
  729. AudioIODeviceCallback* const oldCallback = currentCallback;
  730. close();
  731. open (BigInteger (currentChansIn), BigInteger (currentChansOut),
  732. currentSampleRate, currentBlockSizeSamples);
  733. if (oldCallback != nullptr)
  734. start (oldCallback);
  735. }
  736. }
  737. else
  738. {
  739. startTimer (100);
  740. }
  741. }
  742. private:
  743. //==============================================================================
  744. IASIO* volatile asioObject;
  745. ASIOCallbacks callbacks;
  746. CLSID classId;
  747. const String optionalDllForDirectLoading;
  748. String error;
  749. long totalNumInputChans, totalNumOutputChans;
  750. StringArray inputChannelNames, outputChannelNames;
  751. Array<int> sampleRates, bufferSizes;
  752. long inputLatency, outputLatency;
  753. long minSize, maxSize, preferredSize, granularity;
  754. int volatile currentBlockSizeSamples;
  755. int volatile currentBitDepth;
  756. double volatile currentSampleRate;
  757. BigInteger currentChansOut, currentChansIn;
  758. AudioIODeviceCallback* volatile currentCallback;
  759. CriticalSection callbackLock;
  760. HeapBlock<ASIOBufferInfo> bufferInfos;
  761. HeapBlock<float*> inBuffers, outBuffers;
  762. HeapBlock<ASIOSampleFormat> inputFormat, outputFormat;
  763. WaitableEvent event1;
  764. HeapBlock <float> tempBuffer;
  765. int volatile bufferIndex, numActiveInputChans, numActiveOutputChans;
  766. bool deviceIsOpen, isStarted, buffersCreated;
  767. bool volatile isASIOOpen;
  768. bool volatile calledback;
  769. bool volatile littleEndian, postOutput, needToReset, isReSync;
  770. bool volatile insideControlPanelModalLoop;
  771. bool volatile shouldUsePreferredSize;
  772. //==============================================================================
  773. void removeCurrentDriver()
  774. {
  775. if (asioObject != nullptr)
  776. {
  777. asioObject->Release();
  778. asioObject = nullptr;
  779. }
  780. }
  781. bool loadDriver()
  782. {
  783. removeCurrentDriver();
  784. JUCE_TRY
  785. {
  786. if (CoCreateInstance (classId, 0, CLSCTX_INPROC_SERVER,
  787. classId, (void**) &asioObject) == S_OK)
  788. {
  789. return true;
  790. }
  791. // If a class isn't registered but we have a path for it, we can fallback to
  792. // doing a direct load of the COM object (only available via the juce_createASIOAudioIODeviceForGUID function).
  793. if (optionalDllForDirectLoading.isNotEmpty())
  794. {
  795. HMODULE h = LoadLibrary (optionalDllForDirectLoading.toWideCharPointer());
  796. if (h != 0)
  797. {
  798. typedef HRESULT (CALLBACK* DllGetClassObjectFunc) (REFCLSID clsid, REFIID iid, LPVOID* ppv);
  799. DllGetClassObjectFunc dllGetClassObject = (DllGetClassObjectFunc) GetProcAddress (h, "DllGetClassObject");
  800. if (dllGetClassObject != 0)
  801. {
  802. IClassFactory* classFactory = nullptr;
  803. HRESULT hr = dllGetClassObject (classId, IID_IClassFactory, (void**) &classFactory);
  804. if (classFactory != nullptr)
  805. {
  806. hr = classFactory->CreateInstance (0, classId, (void**) &asioObject);
  807. classFactory->Release();
  808. }
  809. return asioObject != nullptr;
  810. }
  811. }
  812. }
  813. }
  814. JUCE_CATCH_ALL
  815. asioObject = nullptr;
  816. return false;
  817. }
  818. String initDriver()
  819. {
  820. if (asioObject != nullptr)
  821. {
  822. char buffer [256] = { 0 };
  823. if (! asioObject->init (juce_messageWindowHandle))
  824. {
  825. asioObject->getErrorMessage (buffer);
  826. return String (buffer, sizeof (buffer) - 1);
  827. }
  828. // just in case any daft drivers expect this to be called..
  829. asioObject->getDriverName (buffer);
  830. return String::empty;
  831. }
  832. return "No Driver";
  833. }
  834. String openDevice()
  835. {
  836. // open the device and get its info..
  837. log ("opening ASIO device: " + getName());
  838. needToReset = false;
  839. isReSync = false;
  840. outputChannelNames.clear();
  841. inputChannelNames.clear();
  842. bufferSizes.clear();
  843. sampleRates.clear();
  844. isASIOOpen = false;
  845. deviceIsOpen = false;
  846. totalNumInputChans = 0;
  847. totalNumOutputChans = 0;
  848. numActiveInputChans = 0;
  849. numActiveOutputChans = 0;
  850. currentCallback = nullptr;
  851. error = String::empty;
  852. if (getName().isEmpty())
  853. return error;
  854. long err = 0;
  855. if (loadDriver())
  856. {
  857. if ((error = initDriver()).isEmpty())
  858. {
  859. numActiveInputChans = 0;
  860. numActiveOutputChans = 0;
  861. totalNumInputChans = 0;
  862. totalNumOutputChans = 0;
  863. if (asioObject != nullptr
  864. && (err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans)) == 0)
  865. {
  866. log (String ((int) totalNumInputChans) + " in, " + String ((int) totalNumOutputChans) + " out");
  867. const int chansToAllocate = totalNumInputChans + totalNumOutputChans + 4;
  868. bufferInfos.calloc (chansToAllocate);
  869. inBuffers.calloc (chansToAllocate);
  870. outBuffers.calloc (chansToAllocate);
  871. inputFormat.calloc (chansToAllocate);
  872. outputFormat.calloc (chansToAllocate);
  873. if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == 0)
  874. {
  875. // find a list of buffer sizes..
  876. log (String ((int) minSize) + " " + String ((int) maxSize) + " " + String ((int) preferredSize) + " " + String ((int) granularity));
  877. if (granularity >= 0)
  878. {
  879. granularity = jmax (1, (int) granularity);
  880. for (int i = jmax ((int) minSize, (int) granularity); i < jmin (6400, (int) maxSize); i += granularity)
  881. bufferSizes.addIfNotAlreadyThere (granularity * (i / granularity));
  882. }
  883. else if (granularity < 0)
  884. {
  885. for (int i = 0; i < 18; ++i)
  886. {
  887. const int s = (1 << i);
  888. if (s >= minSize && s <= maxSize)
  889. bufferSizes.add (s);
  890. }
  891. }
  892. if (! bufferSizes.contains (preferredSize))
  893. bufferSizes.insert (0, preferredSize);
  894. double currentRate = 0;
  895. asioObject->getSampleRate (&currentRate);
  896. if (currentRate <= 0.0 || currentRate > 192001.0)
  897. {
  898. log ("setting sample rate");
  899. err = asioObject->setSampleRate (44100.0);
  900. if (err != 0)
  901. {
  902. logError ("setting sample rate", err);
  903. }
  904. asioObject->getSampleRate (&currentRate);
  905. }
  906. currentSampleRate = currentRate;
  907. postOutput = (asioObject->outputReady() == 0);
  908. if (postOutput)
  909. {
  910. log ("ASIO outputReady = ok");
  911. }
  912. updateSampleRates();
  913. // ..because cubase does it at this point
  914. inputLatency = outputLatency = 0;
  915. if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
  916. {
  917. log ("ASIO - no latencies");
  918. }
  919. log ("latencies: " + String ((int) inputLatency) + ", " + String ((int) outputLatency));
  920. // create some dummy buffers now.. because cubase does..
  921. numActiveInputChans = 0;
  922. numActiveOutputChans = 0;
  923. ASIOBufferInfo* info = bufferInfos;
  924. int i, numChans = 0;
  925. for (i = 0; i < jmin (2, (int) totalNumInputChans); ++i)
  926. {
  927. info->isInput = 1;
  928. info->channelNum = i;
  929. info->buffers[0] = info->buffers[1] = nullptr;
  930. ++info;
  931. ++numChans;
  932. }
  933. const int outputBufferIndex = numChans;
  934. for (i = 0; i < jmin (2, (int) totalNumOutputChans); ++i)
  935. {
  936. info->isInput = 0;
  937. info->channelNum = i;
  938. info->buffers[0] = info->buffers[1] = nullptr;
  939. ++info;
  940. ++numChans;
  941. }
  942. setCallbackFunctions();
  943. log ("creating buffers (dummy): " + String (numChans) + ", " + String ((int) preferredSize));
  944. if (preferredSize > 0)
  945. {
  946. err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks);
  947. if (err != 0)
  948. {
  949. logError ("dummy buffers", err);
  950. }
  951. }
  952. long newInps = 0, newOuts = 0;
  953. asioObject->getChannels (&newInps, &newOuts);
  954. if (totalNumInputChans != newInps || totalNumOutputChans != newOuts)
  955. {
  956. totalNumInputChans = newInps;
  957. totalNumOutputChans = newOuts;
  958. log (String ((int) totalNumInputChans) + " in; " + String ((int) totalNumOutputChans) + " out");
  959. }
  960. updateSampleRates();
  961. for (i = 0; i < totalNumInputChans; ++i)
  962. {
  963. ASIOChannelInfo channelInfo = { 0 };
  964. channelInfo.channel = i;
  965. channelInfo.isInput = 1;
  966. asioObject->getChannelInfo (&channelInfo);
  967. inputChannelNames.add (String (CharPointer_UTF8 (channelInfo.name)));
  968. }
  969. for (i = 0; i < totalNumOutputChans; ++i)
  970. {
  971. ASIOChannelInfo channelInfo = { 0 };
  972. channelInfo.channel = i;
  973. channelInfo.isInput = 0;
  974. asioObject->getChannelInfo (&channelInfo);
  975. outputChannelNames.add (String (CharPointer_UTF8 (channelInfo.name)));
  976. outputFormat[i] = ASIOSampleFormat (channelInfo.type);
  977. if (i < 2)
  978. {
  979. // clear the channels that are used with the dummy stuff
  980. outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[0], preferredSize);
  981. outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[1], preferredSize);
  982. }
  983. }
  984. outputChannelNames.trim();
  985. inputChannelNames.trim();
  986. outputChannelNames.appendNumbersToDuplicates (false, true);
  987. inputChannelNames.appendNumbersToDuplicates (false, true);
  988. // start and stop because cubase does it..
  989. asioObject->getLatencies (&inputLatency, &outputLatency);
  990. if ((err = asioObject->start()) != 0)
  991. {
  992. // ignore an error here, as it might start later after setting other stuff up
  993. logError ("ASIO start", err);
  994. }
  995. Thread::sleep (100);
  996. asioObject->stop();
  997. }
  998. else
  999. {
  1000. error = "Can't detect buffer sizes";
  1001. }
  1002. }
  1003. else
  1004. {
  1005. error = "Can't detect asio channels";
  1006. }
  1007. }
  1008. }
  1009. else
  1010. {
  1011. error = "No such device";
  1012. }
  1013. if (error.isNotEmpty())
  1014. {
  1015. logError (error, err);
  1016. disposeBuffers();
  1017. removeCurrentDriver();
  1018. isASIOOpen = false;
  1019. }
  1020. else
  1021. {
  1022. isASIOOpen = true;
  1023. log ("ASIO device open");
  1024. }
  1025. deviceIsOpen = false;
  1026. needToReset = false;
  1027. isReSync = false;
  1028. return error;
  1029. }
  1030. void disposeBuffers()
  1031. {
  1032. if (asioObject != nullptr && buffersCreated)
  1033. {
  1034. buffersCreated = false;
  1035. asioObject->disposeBuffers();
  1036. }
  1037. }
  1038. //==============================================================================
  1039. void JUCE_ASIOCALLBACK callback (const long index)
  1040. {
  1041. if (isStarted)
  1042. {
  1043. bufferIndex = index;
  1044. processBuffer();
  1045. }
  1046. else
  1047. {
  1048. if (postOutput && (asioObject != nullptr))
  1049. asioObject->outputReady();
  1050. }
  1051. calledback = true;
  1052. }
  1053. void processBuffer()
  1054. {
  1055. const ASIOBufferInfo* const infos = bufferInfos;
  1056. const int bi = bufferIndex;
  1057. const ScopedLock sl (callbackLock);
  1058. if (needToReset)
  1059. {
  1060. needToReset = false;
  1061. if (isReSync)
  1062. {
  1063. log ("! ASIO resync");
  1064. isReSync = false;
  1065. }
  1066. else
  1067. {
  1068. startTimer (20);
  1069. }
  1070. }
  1071. if (bi >= 0)
  1072. {
  1073. const int samps = currentBlockSizeSamples;
  1074. if (currentCallback != nullptr)
  1075. {
  1076. for (int i = 0; i < numActiveInputChans; ++i)
  1077. {
  1078. jassert (inBuffers[i] != nullptr);
  1079. inputFormat[i].convertToFloat (infos[i].buffers[bi], inBuffers[i], samps);
  1080. }
  1081. currentCallback->audioDeviceIOCallback (const_cast <const float**> (inBuffers.getData()), numActiveInputChans,
  1082. outBuffers, numActiveOutputChans, samps);
  1083. for (int i = 0; i < numActiveOutputChans; ++i)
  1084. {
  1085. jassert (outBuffers[i] != nullptr);
  1086. outputFormat[i].convertFromFloat (outBuffers[i], infos [numActiveInputChans + i].buffers[bi], samps);
  1087. }
  1088. }
  1089. else
  1090. {
  1091. for (int i = 0; i < numActiveOutputChans; ++i)
  1092. outputFormat[i].clear (infos[numActiveInputChans + i].buffers[bi], samps);
  1093. }
  1094. }
  1095. if (postOutput)
  1096. asioObject->outputReady();
  1097. }
  1098. //==============================================================================
  1099. template <int deviceIndex>
  1100. struct ASIOCallbackFunctions
  1101. {
  1102. static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback (ASIOTime*, long index, long)
  1103. {
  1104. if (currentASIODev[deviceIndex] != nullptr)
  1105. currentASIODev[deviceIndex]->callback (index);
  1106. return nullptr;
  1107. }
  1108. static void JUCE_ASIOCALLBACK bufferSwitchCallback (long index, long)
  1109. {
  1110. if (currentASIODev[deviceIndex] != nullptr)
  1111. currentASIODev[deviceIndex]->callback (index);
  1112. }
  1113. static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*)
  1114. {
  1115. return ASIOAudioIODevice::asioMessagesCallback (selector, value, deviceIndex);
  1116. }
  1117. static void setCallbacks (ASIOCallbacks& callbacks)
  1118. {
  1119. callbacks.bufferSwitch = &bufferSwitchCallback;
  1120. callbacks.asioMessage = &asioMessagesCallback;
  1121. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback;
  1122. }
  1123. };
  1124. void setCallbackFunctions()
  1125. {
  1126. callbacks.sampleRateDidChange = &sampleRateChangedCallback;
  1127. if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks);
  1128. else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks);
  1129. else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks);
  1130. else jassertfalse;
  1131. }
  1132. //==============================================================================
  1133. static long asioMessagesCallback (long selector, long value, const int deviceIndex)
  1134. {
  1135. switch (selector)
  1136. {
  1137. case kAsioSelectorSupported:
  1138. if (value == kAsioResetRequest
  1139. || value == kAsioEngineVersion
  1140. || value == kAsioResyncRequest
  1141. || value == kAsioLatenciesChanged
  1142. || value == kAsioSupportsInputMonitor)
  1143. return 1;
  1144. break;
  1145. case kAsioBufferSizeChange:
  1146. break;
  1147. case kAsioResetRequest:
  1148. if (currentASIODev[deviceIndex] != nullptr)
  1149. currentASIODev[deviceIndex]->resetRequest();
  1150. return 1;
  1151. case kAsioResyncRequest:
  1152. if (currentASIODev[deviceIndex] != nullptr)
  1153. currentASIODev[deviceIndex]->resyncRequest();
  1154. return 1;
  1155. case kAsioLatenciesChanged:
  1156. return 1;
  1157. case kAsioEngineVersion:
  1158. return 2;
  1159. case kAsioSupportsTimeInfo:
  1160. case kAsioSupportsTimeCode:
  1161. return 0;
  1162. }
  1163. return 0;
  1164. }
  1165. static void JUCE_ASIOCALLBACK sampleRateChangedCallback (ASIOSampleRate)
  1166. {
  1167. }
  1168. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ASIOAudioIODevice);
  1169. };
  1170. //==============================================================================
  1171. class ASIOAudioIODeviceType : public AudioIODeviceType
  1172. {
  1173. public:
  1174. ASIOAudioIODeviceType()
  1175. : AudioIODeviceType ("ASIO"),
  1176. hasScanned (false)
  1177. {
  1178. CoInitialize (0);
  1179. }
  1180. //==============================================================================
  1181. void scanForDevices()
  1182. {
  1183. hasScanned = true;
  1184. deviceNames.clear();
  1185. classIds.clear();
  1186. HKEY hk = 0;
  1187. int index = 0;
  1188. if (RegOpenKey (HKEY_LOCAL_MACHINE, _T("software\\asio"), &hk) == ERROR_SUCCESS)
  1189. {
  1190. TCHAR name [256];
  1191. while (RegEnumKey (hk, index++, name, numElementsInArray (name)) == ERROR_SUCCESS)
  1192. addDriverInfo (name, hk);
  1193. RegCloseKey (hk);
  1194. }
  1195. }
  1196. StringArray getDeviceNames (bool /*wantInputNames*/) const
  1197. {
  1198. jassert (hasScanned); // need to call scanForDevices() before doing this
  1199. return deviceNames;
  1200. }
  1201. int getDefaultDeviceIndex (bool) const
  1202. {
  1203. jassert (hasScanned); // need to call scanForDevices() before doing this
  1204. for (int i = deviceNames.size(); --i >= 0;)
  1205. if (deviceNames[i].containsIgnoreCase ("asio4all"))
  1206. return i; // asio4all is a safe choice for a default..
  1207. #if JUCE_DEBUG
  1208. if (deviceNames.size() > 1 && deviceNames[0].containsIgnoreCase ("digidesign"))
  1209. return 1; // (the digi m-box driver crashes the app when you run
  1210. // it in the debugger, which can be a bit annoying)
  1211. #endif
  1212. return 0;
  1213. }
  1214. static int findFreeSlot()
  1215. {
  1216. for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
  1217. if (currentASIODev[i] == 0)
  1218. return i;
  1219. jassertfalse; // unfortunately you can only have a finite number
  1220. // of ASIO devices open at the same time..
  1221. return -1;
  1222. }
  1223. int getIndexOfDevice (AudioIODevice* d, bool /*asInput*/) const
  1224. {
  1225. jassert (hasScanned); // need to call scanForDevices() before doing this
  1226. return d == nullptr ? -1 : deviceNames.indexOf (d->getName());
  1227. }
  1228. bool hasSeparateInputsAndOutputs() const { return false; }
  1229. AudioIODevice* createDevice (const String& outputDeviceName,
  1230. const String& inputDeviceName)
  1231. {
  1232. // ASIO can't open two different devices for input and output - they must be the same one.
  1233. jassert (inputDeviceName == outputDeviceName || outputDeviceName.isEmpty() || inputDeviceName.isEmpty());
  1234. jassert (hasScanned); // need to call scanForDevices() before doing this
  1235. const int index = deviceNames.indexOf (outputDeviceName.isNotEmpty() ? outputDeviceName
  1236. : inputDeviceName);
  1237. if (index >= 0)
  1238. {
  1239. const int freeSlot = findFreeSlot();
  1240. if (freeSlot >= 0)
  1241. return new ASIOAudioIODevice (outputDeviceName, *(classIds [index]), freeSlot, String::empty);
  1242. }
  1243. return nullptr;
  1244. }
  1245. //==============================================================================
  1246. private:
  1247. StringArray deviceNames;
  1248. OwnedArray <CLSID> classIds;
  1249. bool hasScanned;
  1250. //==============================================================================
  1251. static bool checkClassIsOk (const String& classId)
  1252. {
  1253. HKEY hk = 0;
  1254. bool ok = false;
  1255. if (RegOpenKey (HKEY_CLASSES_ROOT, _T("clsid"), &hk) == ERROR_SUCCESS)
  1256. {
  1257. int index = 0;
  1258. TCHAR name [512];
  1259. while (RegEnumKey (hk, index++, name, numElementsInArray (name)) == ERROR_SUCCESS)
  1260. {
  1261. if (classId.equalsIgnoreCase (name))
  1262. {
  1263. HKEY subKey, pathKey;
  1264. if (RegOpenKeyEx (hk, name, 0, KEY_READ, &subKey) == ERROR_SUCCESS)
  1265. {
  1266. if (RegOpenKeyEx (subKey, _T("InprocServer32"), 0, KEY_READ, &pathKey) == ERROR_SUCCESS)
  1267. {
  1268. TCHAR pathName [1024] = { 0 };
  1269. DWORD dtype = REG_SZ;
  1270. DWORD dsize = sizeof (pathName);
  1271. if (RegQueryValueEx (pathKey, 0, 0, &dtype, (LPBYTE) pathName, &dsize) == ERROR_SUCCESS)
  1272. // In older code, this used to check for the existance of the file, but there are situations
  1273. // where our process doesn't have access to it, but where the driver still loads ok..
  1274. ok = (pathName[0] != 0);
  1275. RegCloseKey (pathKey);
  1276. }
  1277. RegCloseKey (subKey);
  1278. }
  1279. break;
  1280. }
  1281. }
  1282. RegCloseKey (hk);
  1283. }
  1284. return ok;
  1285. }
  1286. //==============================================================================
  1287. void addDriverInfo (const String& keyName, HKEY hk)
  1288. {
  1289. HKEY subKey;
  1290. if (RegOpenKeyEx (hk, keyName.toWideCharPointer(), 0, KEY_READ, &subKey) == ERROR_SUCCESS)
  1291. {
  1292. TCHAR buf [256] = { 0 };
  1293. DWORD dtype = REG_SZ;
  1294. DWORD dsize = sizeof (buf);
  1295. if (RegQueryValueEx (subKey, _T("clsid"), 0, &dtype, (LPBYTE) buf, &dsize) == ERROR_SUCCESS)
  1296. {
  1297. if (dsize > 0 && checkClassIsOk (buf))
  1298. {
  1299. CLSID classId;
  1300. if (CLSIDFromString ((LPOLESTR) buf, &classId) == S_OK)
  1301. {
  1302. dtype = REG_SZ;
  1303. dsize = sizeof (buf);
  1304. String deviceName;
  1305. if (RegQueryValueEx (subKey, _T("description"), 0, &dtype, (LPBYTE) buf, &dsize) == ERROR_SUCCESS)
  1306. deviceName = buf;
  1307. else
  1308. deviceName = keyName;
  1309. log ("found " + deviceName);
  1310. deviceNames.add (deviceName);
  1311. classIds.add (new CLSID (classId));
  1312. }
  1313. }
  1314. RegCloseKey (subKey);
  1315. }
  1316. }
  1317. }
  1318. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ASIOAudioIODeviceType);
  1319. };
  1320. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_ASIO()
  1321. {
  1322. return new ASIOAudioIODeviceType();
  1323. }
  1324. AudioIODevice* juce_createASIOAudioIODeviceForGUID (const String& name, void* guid,
  1325. const String& optionalDllForDirectLoading)
  1326. {
  1327. const int freeSlot = ASIOAudioIODeviceType::findFreeSlot();
  1328. if (freeSlot < 0)
  1329. return nullptr;
  1330. return new ASIOAudioIODevice (name, *(CLSID*) guid, freeSlot, optionalDllForDirectLoading);
  1331. }
  1332. #undef logError
  1333. #undef log