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.

1650 lines
54KB

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