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.

1972 lines
63KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE && JUCE_ASIO
  21. #undef WINDOWS
  22. //==============================================================================
  23. // #define ASIO_DEBUGGING
  24. #ifdef ASIO_DEBUGGING
  25. #define log(a) { Logger::writeToLog (a); DBG (a) }
  26. #else
  27. #define log(a) {}
  28. #endif
  29. //==============================================================================
  30. #ifdef ASIO_DEBUGGING
  31. static void logError (const String& context, long error)
  32. {
  33. String err ("unknown error");
  34. if (error == ASE_NotPresent)
  35. err = "Not Present";
  36. else if (error == ASE_HWMalfunction)
  37. err = "Hardware Malfunction";
  38. else if (error == ASE_InvalidParameter)
  39. err = "Invalid Parameter";
  40. else if (error == ASE_InvalidMode)
  41. err = "Invalid Mode";
  42. else if (error == ASE_SPNotAdvancing)
  43. err = "Sample position not advancing";
  44. else if (error == ASE_NoClock)
  45. err = "No Clock";
  46. else if (error == ASE_NoMemory)
  47. err = "Out of memory";
  48. log (T("!!error: ") + context + T(" - ") + err);
  49. }
  50. #else
  51. #define logError(a, b) {}
  52. #endif
  53. //==============================================================================
  54. class ASIOAudioIODevice;
  55. static ASIOAudioIODevice* volatile currentASIODev[3] = { 0, 0, 0 };
  56. static const int maxASIOChannels = 160;
  57. //==============================================================================
  58. class JUCE_API ASIOAudioIODevice : public AudioIODevice,
  59. private Timer
  60. {
  61. public:
  62. Component ourWindow;
  63. ASIOAudioIODevice (const String& name_, const CLSID classId_, const int slotNumber,
  64. const String& optionalDllForDirectLoading_)
  65. : AudioIODevice (name_, T("ASIO")),
  66. asioObject (0),
  67. classId (classId_),
  68. optionalDllForDirectLoading (optionalDllForDirectLoading_),
  69. currentBitDepth (16),
  70. currentSampleRate (0),
  71. tempBuffer (0),
  72. isOpen_ (false),
  73. isStarted (false),
  74. postOutput (true),
  75. insideControlPanelModalLoop (false),
  76. shouldUsePreferredSize (false)
  77. {
  78. name = name_;
  79. ourWindow.addToDesktop (0);
  80. windowHandle = ourWindow.getWindowHandle();
  81. jassert (currentASIODev [slotNumber] == 0);
  82. currentASIODev [slotNumber] = this;
  83. openDevice();
  84. }
  85. ~ASIOAudioIODevice()
  86. {
  87. for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
  88. if (currentASIODev[i] == this)
  89. currentASIODev[i] = 0;
  90. close();
  91. log ("ASIO - exiting");
  92. removeCurrentDriver();
  93. juce_free (tempBuffer);
  94. }
  95. void updateSampleRates()
  96. {
  97. // find a list of sample rates..
  98. const double possibleSampleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
  99. sampleRates.clear();
  100. if (asioObject != 0)
  101. {
  102. for (int index = 0; index < numElementsInArray (possibleSampleRates); ++index)
  103. {
  104. const long err = asioObject->canSampleRate (possibleSampleRates[index]);
  105. if (err == 0)
  106. {
  107. sampleRates.add ((int) possibleSampleRates[index]);
  108. log (T("rate: ") + String ((int) possibleSampleRates[index]));
  109. }
  110. else if (err != ASE_NoClock)
  111. {
  112. logError (T("CanSampleRate"), err);
  113. }
  114. }
  115. if (sampleRates.size() == 0)
  116. {
  117. double cr = 0;
  118. const long err = asioObject->getSampleRate (&cr);
  119. log (T("No sample rates supported - current rate: ") + String ((int) cr));
  120. if (err == 0)
  121. sampleRates.add ((int) cr);
  122. }
  123. }
  124. }
  125. const StringArray getOutputChannelNames()
  126. {
  127. return outputChannelNames;
  128. }
  129. const StringArray getInputChannelNames()
  130. {
  131. return inputChannelNames;
  132. }
  133. int getNumSampleRates()
  134. {
  135. return sampleRates.size();
  136. }
  137. double getSampleRate (int index)
  138. {
  139. return sampleRates [index];
  140. }
  141. int getNumBufferSizesAvailable()
  142. {
  143. return bufferSizes.size();
  144. }
  145. int getBufferSizeSamples (int index)
  146. {
  147. return bufferSizes [index];
  148. }
  149. int getDefaultBufferSize()
  150. {
  151. return preferredSize;
  152. }
  153. const String open (const BitArray& inputChannels,
  154. const BitArray& outputChannels,
  155. double sr,
  156. int bufferSizeSamples)
  157. {
  158. close();
  159. currentCallback = 0;
  160. if (bufferSizeSamples <= 0)
  161. shouldUsePreferredSize = true;
  162. if (asioObject == 0 || ! isASIOOpen)
  163. {
  164. log ("Warning: device not open");
  165. const String err (openDevice());
  166. if (asioObject == 0 || ! isASIOOpen)
  167. return err;
  168. }
  169. isStarted = false;
  170. bufferIndex = -1;
  171. long err = 0;
  172. long newPreferredSize = 0;
  173. // if the preferred size has just changed, assume it's a control panel thing and use it as the new value.
  174. minSize = 0;
  175. maxSize = 0;
  176. newPreferredSize = 0;
  177. granularity = 0;
  178. if (asioObject->getBufferSize (&minSize, &maxSize, &newPreferredSize, &granularity) == 0)
  179. {
  180. if (preferredSize != 0 && newPreferredSize != 0 && newPreferredSize != preferredSize)
  181. shouldUsePreferredSize = true;
  182. preferredSize = newPreferredSize;
  183. }
  184. // unfortunate workaround for certain manufacturers whose drivers crash horribly if you make
  185. // dynamic changes to the buffer size...
  186. shouldUsePreferredSize = shouldUsePreferredSize
  187. || getName().containsIgnoreCase (T("Digidesign"));
  188. if (shouldUsePreferredSize)
  189. {
  190. log ("Using preferred size for buffer..");
  191. if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == 0)
  192. {
  193. bufferSizeSamples = preferredSize;
  194. }
  195. else
  196. {
  197. bufferSizeSamples = 1024;
  198. logError ("GetBufferSize1", err);
  199. }
  200. shouldUsePreferredSize = false;
  201. }
  202. int sampleRate = roundDoubleToInt (sr);
  203. currentSampleRate = sampleRate;
  204. currentBlockSizeSamples = bufferSizeSamples;
  205. currentChansOut.clear();
  206. currentChansIn.clear();
  207. zeromem (inBuffers, sizeof (inBuffers));
  208. zeromem (outBuffers, sizeof (outBuffers));
  209. updateSampleRates();
  210. if (sampleRate == 0 || (sampleRates.size() > 0 && ! sampleRates.contains (sampleRate)))
  211. sampleRate = sampleRates[0];
  212. jassert (sampleRate != 0);
  213. if (sampleRate == 0)
  214. sampleRate = 44100;
  215. long numSources = 32;
  216. ASIOClockSource clocks[32];
  217. zeromem (clocks, sizeof (clocks));
  218. asioObject->getClockSources (clocks, &numSources);
  219. bool isSourceSet = false;
  220. // careful not to remove this loop because it does more than just logging!
  221. int i;
  222. for (i = 0; i < numSources; ++i)
  223. {
  224. String s ("clock: ");
  225. s += clocks[i].name;
  226. if (clocks[i].isCurrentSource)
  227. {
  228. isSourceSet = true;
  229. s << " (cur)";
  230. }
  231. log (s);
  232. }
  233. if (numSources > 1 && ! isSourceSet)
  234. {
  235. log ("setting clock source");
  236. asioObject->setClockSource (clocks[0].index);
  237. Thread::sleep (20);
  238. }
  239. else
  240. {
  241. if (numSources == 0)
  242. {
  243. log ("ASIO - no clock sources!");
  244. }
  245. }
  246. double cr = 0;
  247. err = asioObject->getSampleRate (&cr);
  248. if (err == 0)
  249. {
  250. currentSampleRate = cr;
  251. }
  252. else
  253. {
  254. logError ("GetSampleRate", err);
  255. currentSampleRate = 0;
  256. }
  257. error = String::empty;
  258. needToReset = false;
  259. isReSync = false;
  260. err = 0;
  261. bool buffersCreated = false;
  262. if (currentSampleRate != sampleRate)
  263. {
  264. log (T("ASIO samplerate: ") + String (currentSampleRate) + T(" to ") + String (sampleRate));
  265. err = asioObject->setSampleRate (sampleRate);
  266. if (err == ASE_NoClock && numSources > 0)
  267. {
  268. log ("trying to set a clock source..");
  269. Thread::sleep (10);
  270. err = asioObject->setClockSource (clocks[0].index);
  271. if (err != 0)
  272. {
  273. logError ("SetClock", err);
  274. }
  275. Thread::sleep (10);
  276. err = asioObject->setSampleRate (sampleRate);
  277. }
  278. }
  279. if (err == 0)
  280. {
  281. currentSampleRate = sampleRate;
  282. if (needToReset)
  283. {
  284. if (isReSync)
  285. {
  286. log ("Resync request");
  287. }
  288. log ("! Resetting ASIO after sample rate change");
  289. removeCurrentDriver();
  290. loadDriver();
  291. const String error (initDriver());
  292. if (error.isNotEmpty())
  293. {
  294. log (T("ASIOInit: ") + error);
  295. }
  296. needToReset = false;
  297. isReSync = false;
  298. }
  299. numActiveInputChans = 0;
  300. numActiveOutputChans = 0;
  301. ASIOBufferInfo* info = bufferInfos;
  302. int i;
  303. for (i = 0; i < totalNumInputChans; ++i)
  304. {
  305. if (inputChannels[i])
  306. {
  307. currentChansIn.setBit (i);
  308. info->isInput = 1;
  309. info->channelNum = i;
  310. info->buffers[0] = info->buffers[1] = 0;
  311. ++info;
  312. ++numActiveInputChans;
  313. }
  314. }
  315. for (i = 0; i < totalNumOutputChans; ++i)
  316. {
  317. if (outputChannels[i])
  318. {
  319. currentChansOut.setBit (i);
  320. info->isInput = 0;
  321. info->channelNum = i;
  322. info->buffers[0] = info->buffers[1] = 0;
  323. ++info;
  324. ++numActiveOutputChans;
  325. }
  326. }
  327. const int totalBuffers = numActiveInputChans + numActiveOutputChans;
  328. callbacks.sampleRateDidChange = &sampleRateChangedCallback;
  329. if (currentASIODev[0] == this)
  330. {
  331. callbacks.bufferSwitch = &bufferSwitchCallback0;
  332. callbacks.asioMessage = &asioMessagesCallback0;
  333. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0;
  334. }
  335. else if (currentASIODev[1] == this)
  336. {
  337. callbacks.bufferSwitch = &bufferSwitchCallback1;
  338. callbacks.asioMessage = &asioMessagesCallback1;
  339. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1;
  340. }
  341. else if (currentASIODev[2] == this)
  342. {
  343. callbacks.bufferSwitch = &bufferSwitchCallback2;
  344. callbacks.asioMessage = &asioMessagesCallback2;
  345. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2;
  346. }
  347. else
  348. {
  349. jassertfalse
  350. }
  351. log ("disposing buffers");
  352. err = asioObject->disposeBuffers();
  353. log (T("creating buffers: ") + String (totalBuffers) + T(", ") + String (currentBlockSizeSamples));
  354. err = asioObject->createBuffers (bufferInfos,
  355. totalBuffers,
  356. currentBlockSizeSamples,
  357. &callbacks);
  358. if (err != 0)
  359. {
  360. currentBlockSizeSamples = preferredSize;
  361. logError ("create buffers 2", err);
  362. asioObject->disposeBuffers();
  363. err = asioObject->createBuffers (bufferInfos,
  364. totalBuffers,
  365. currentBlockSizeSamples,
  366. &callbacks);
  367. }
  368. if (err == 0)
  369. {
  370. buffersCreated = true;
  371. juce_free (tempBuffer);
  372. tempBuffer = (float*) juce_calloc (totalBuffers * currentBlockSizeSamples * sizeof (float) + 128);
  373. int n = 0;
  374. Array <int> types;
  375. currentBitDepth = 16;
  376. for (i = 0; i < jmin (totalNumInputChans, maxASIOChannels); ++i)
  377. {
  378. if (inputChannels[i])
  379. {
  380. inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n);
  381. ASIOChannelInfo channelInfo;
  382. zerostruct (channelInfo);
  383. channelInfo.channel = i;
  384. channelInfo.isInput = 1;
  385. asioObject->getChannelInfo (&channelInfo);
  386. types.addIfNotAlreadyThere (channelInfo.type);
  387. typeToFormatParameters (channelInfo.type,
  388. inputChannelBitDepths[n],
  389. inputChannelBytesPerSample[n],
  390. inputChannelIsFloat[n],
  391. inputChannelLittleEndian[n]);
  392. currentBitDepth = jmax (currentBitDepth, inputChannelBitDepths[n]);
  393. ++n;
  394. }
  395. }
  396. jassert (numActiveInputChans == n);
  397. n = 0;
  398. for (i = 0; i < jmin (totalNumOutputChans, maxASIOChannels); ++i)
  399. {
  400. if (outputChannels[i])
  401. {
  402. outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n));
  403. ASIOChannelInfo channelInfo;
  404. zerostruct (channelInfo);
  405. channelInfo.channel = i;
  406. channelInfo.isInput = 0;
  407. asioObject->getChannelInfo (&channelInfo);
  408. types.addIfNotAlreadyThere (channelInfo.type);
  409. typeToFormatParameters (channelInfo.type,
  410. outputChannelBitDepths[n],
  411. outputChannelBytesPerSample[n],
  412. outputChannelIsFloat[n],
  413. outputChannelLittleEndian[n]);
  414. currentBitDepth = jmax (currentBitDepth, outputChannelBitDepths[n]);
  415. ++n;
  416. }
  417. }
  418. jassert (numActiveOutputChans == n);
  419. for (i = types.size(); --i >= 0;)
  420. {
  421. log (T("channel format: ") + String (types[i]));
  422. }
  423. jassert (n <= totalBuffers);
  424. for (i = 0; i < numActiveOutputChans; ++i)
  425. {
  426. const int size = currentBlockSizeSamples * (outputChannelBitDepths[i] >> 3);
  427. if (bufferInfos [numActiveInputChans + i].buffers[0] == 0
  428. || bufferInfos [numActiveInputChans + i].buffers[1] == 0)
  429. {
  430. log ("!! Null buffers");
  431. }
  432. else
  433. {
  434. zeromem (bufferInfos[numActiveInputChans + i].buffers[0], size);
  435. zeromem (bufferInfos[numActiveInputChans + i].buffers[1], size);
  436. }
  437. }
  438. inputLatency = outputLatency = 0;
  439. if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
  440. {
  441. log ("ASIO - no latencies");
  442. }
  443. else
  444. {
  445. log (T("ASIO latencies: ")
  446. + String ((int) outputLatency)
  447. + T(", ")
  448. + String ((int) inputLatency));
  449. }
  450. isOpen_ = true;
  451. log ("starting ASIO");
  452. calledback = false;
  453. err = asioObject->start();
  454. if (err != 0)
  455. {
  456. isOpen_ = false;
  457. log ("ASIO - stop on failure");
  458. Thread::sleep (10);
  459. asioObject->stop();
  460. error = "Can't start device";
  461. Thread::sleep (10);
  462. }
  463. else
  464. {
  465. int count = 300;
  466. while (--count > 0 && ! calledback)
  467. Thread::sleep (10);
  468. isStarted = true;
  469. if (! calledback)
  470. {
  471. error = "Device didn't start correctly";
  472. log ("ASIO didn't callback - stopping..");
  473. asioObject->stop();
  474. }
  475. }
  476. }
  477. else
  478. {
  479. error = "Can't create i/o buffers";
  480. }
  481. }
  482. else
  483. {
  484. error = "Can't set sample rate: ";
  485. error << sampleRate;
  486. }
  487. if (error.isNotEmpty())
  488. {
  489. logError (error, err);
  490. if (asioObject != 0 && buffersCreated)
  491. asioObject->disposeBuffers();
  492. Thread::sleep (20);
  493. isStarted = false;
  494. isOpen_ = false;
  495. close();
  496. }
  497. needToReset = false;
  498. isReSync = false;
  499. return error;
  500. }
  501. void close()
  502. {
  503. error = String::empty;
  504. stopTimer();
  505. stop();
  506. if (isASIOOpen && isOpen_)
  507. {
  508. const ScopedLock sl (callbackLock);
  509. isOpen_ = false;
  510. isStarted = false;
  511. needToReset = false;
  512. isReSync = false;
  513. log ("ASIO - stopping");
  514. if (asioObject != 0)
  515. {
  516. Thread::sleep (20);
  517. asioObject->stop();
  518. Thread::sleep (10);
  519. asioObject->disposeBuffers();
  520. }
  521. Thread::sleep (10);
  522. }
  523. }
  524. bool isOpen()
  525. {
  526. return isOpen_ || insideControlPanelModalLoop;
  527. }
  528. int getCurrentBufferSizeSamples()
  529. {
  530. return currentBlockSizeSamples;
  531. }
  532. double getCurrentSampleRate()
  533. {
  534. return currentSampleRate;
  535. }
  536. const BitArray getActiveOutputChannels() const
  537. {
  538. return currentChansOut;
  539. }
  540. const BitArray getActiveInputChannels() const
  541. {
  542. return currentChansIn;
  543. }
  544. int getCurrentBitDepth()
  545. {
  546. return currentBitDepth;
  547. }
  548. int getOutputLatencyInSamples()
  549. {
  550. return outputLatency + currentBlockSizeSamples / 4;
  551. }
  552. int getInputLatencyInSamples()
  553. {
  554. return inputLatency + currentBlockSizeSamples / 4;
  555. }
  556. void start (AudioIODeviceCallback* callback)
  557. {
  558. if (callback != 0)
  559. {
  560. callback->audioDeviceAboutToStart (this);
  561. const ScopedLock sl (callbackLock);
  562. currentCallback = callback;
  563. }
  564. }
  565. void stop()
  566. {
  567. AudioIODeviceCallback* const lastCallback = currentCallback;
  568. {
  569. const ScopedLock sl (callbackLock);
  570. currentCallback = 0;
  571. }
  572. if (lastCallback != 0)
  573. lastCallback->audioDeviceStopped();
  574. }
  575. bool isPlaying()
  576. {
  577. return isASIOOpen && (currentCallback != 0);
  578. }
  579. const String getLastError()
  580. {
  581. return error;
  582. }
  583. bool hasControlPanel() const
  584. {
  585. return true;
  586. }
  587. bool showControlPanel()
  588. {
  589. log ("ASIO - showing control panel");
  590. Component modalWindow (String::empty);
  591. modalWindow.setOpaque (true);
  592. modalWindow.addToDesktop (0);
  593. modalWindow.enterModalState();
  594. bool done = false;
  595. JUCE_TRY
  596. {
  597. // are there are devices that need to be closed before showing their control panel?
  598. // close();
  599. insideControlPanelModalLoop = true;
  600. const uint32 started = Time::getMillisecondCounter();
  601. if (asioObject != 0)
  602. {
  603. asioObject->controlPanel();
  604. const int spent = (int) Time::getMillisecondCounter() - (int) started;
  605. log (T("spent: ") + String (spent));
  606. if (spent > 300)
  607. {
  608. shouldUsePreferredSize = true;
  609. done = true;
  610. }
  611. }
  612. }
  613. JUCE_CATCH_ALL
  614. insideControlPanelModalLoop = false;
  615. return done;
  616. }
  617. void resetRequest() throw()
  618. {
  619. needToReset = true;
  620. }
  621. void resyncRequest() throw()
  622. {
  623. needToReset = true;
  624. isReSync = true;
  625. }
  626. void timerCallback()
  627. {
  628. if (! insideControlPanelModalLoop)
  629. {
  630. stopTimer();
  631. // used to cause a reset
  632. log ("! ASIO restart request!");
  633. if (isOpen_)
  634. {
  635. AudioIODeviceCallback* const oldCallback = currentCallback;
  636. close();
  637. open (BitArray (currentChansIn), BitArray (currentChansOut),
  638. currentSampleRate, currentBlockSizeSamples);
  639. if (oldCallback != 0)
  640. start (oldCallback);
  641. }
  642. }
  643. else
  644. {
  645. startTimer (100);
  646. }
  647. }
  648. //==============================================================================
  649. juce_UseDebuggingNewOperator
  650. private:
  651. //==============================================================================
  652. IASIO* volatile asioObject;
  653. ASIOCallbacks callbacks;
  654. void* windowHandle;
  655. CLSID classId;
  656. const String optionalDllForDirectLoading;
  657. String error;
  658. long totalNumInputChans, totalNumOutputChans;
  659. StringArray inputChannelNames, outputChannelNames;
  660. Array<int> sampleRates, bufferSizes;
  661. long inputLatency, outputLatency;
  662. long minSize, maxSize, preferredSize, granularity;
  663. int volatile currentBlockSizeSamples;
  664. int volatile currentBitDepth;
  665. double volatile currentSampleRate;
  666. BitArray currentChansOut, currentChansIn;
  667. AudioIODeviceCallback* volatile currentCallback;
  668. CriticalSection callbackLock;
  669. ASIOBufferInfo bufferInfos [maxASIOChannels];
  670. float* inBuffers [maxASIOChannels];
  671. float* outBuffers [maxASIOChannels];
  672. int inputChannelBitDepths [maxASIOChannels];
  673. int outputChannelBitDepths [maxASIOChannels];
  674. int inputChannelBytesPerSample [maxASIOChannels];
  675. int outputChannelBytesPerSample [maxASIOChannels];
  676. bool inputChannelIsFloat [maxASIOChannels];
  677. bool outputChannelIsFloat [maxASIOChannels];
  678. bool inputChannelLittleEndian [maxASIOChannels];
  679. bool outputChannelLittleEndian [maxASIOChannels];
  680. WaitableEvent event1;
  681. float* tempBuffer;
  682. int volatile bufferIndex, numActiveInputChans, numActiveOutputChans;
  683. bool isOpen_, isStarted;
  684. bool volatile isASIOOpen;
  685. bool volatile calledback;
  686. bool volatile littleEndian, postOutput, needToReset, isReSync;
  687. bool volatile insideControlPanelModalLoop;
  688. bool volatile shouldUsePreferredSize;
  689. //==============================================================================
  690. void removeCurrentDriver()
  691. {
  692. if (asioObject != 0)
  693. {
  694. asioObject->Release();
  695. asioObject = 0;
  696. }
  697. }
  698. bool loadDriver()
  699. {
  700. removeCurrentDriver();
  701. JUCE_TRY
  702. {
  703. if (CoCreateInstance (classId, 0, CLSCTX_INPROC_SERVER,
  704. classId, (void**) &asioObject) == S_OK)
  705. {
  706. return true;
  707. }
  708. // If a class isn't registered but we have a path for it, we can fallback to
  709. // doing a direct load of the COM object (only available via the juce_createASIOAudioIODeviceForGUID function).
  710. if (optionalDllForDirectLoading.isNotEmpty())
  711. {
  712. HMODULE h = LoadLibrary (optionalDllForDirectLoading);
  713. if (h != 0)
  714. {
  715. typedef HRESULT (CALLBACK* DllGetClassObjectFunc) (REFCLSID clsid, REFIID iid, LPVOID* ppv);
  716. DllGetClassObjectFunc dllGetClassObject = (DllGetClassObjectFunc) GetProcAddress (h, "DllGetClassObject");
  717. if (dllGetClassObject != 0)
  718. {
  719. IClassFactory* classFactory = 0;
  720. HRESULT hr = dllGetClassObject (classId, IID_IClassFactory, (void**) &classFactory);
  721. if (classFactory != 0)
  722. {
  723. hr = classFactory->CreateInstance (0, classId, (void**) &asioObject);
  724. classFactory->Release();
  725. }
  726. return asioObject != 0;
  727. }
  728. }
  729. }
  730. }
  731. JUCE_CATCH_ALL
  732. asioObject = 0;
  733. return false;
  734. }
  735. const String initDriver()
  736. {
  737. if (asioObject != 0)
  738. {
  739. char buffer [256];
  740. zeromem (buffer, sizeof (buffer));
  741. if (! asioObject->init (windowHandle))
  742. {
  743. asioObject->getErrorMessage (buffer);
  744. return String (buffer, sizeof (buffer) - 1);
  745. }
  746. // just in case any daft drivers expect this to be called..
  747. asioObject->getDriverName (buffer);
  748. return String::empty;
  749. }
  750. return "No Driver";
  751. }
  752. const String openDevice()
  753. {
  754. // use this in case the driver starts opening dialog boxes..
  755. Component modalWindow (String::empty);
  756. modalWindow.setOpaque (true);
  757. modalWindow.addToDesktop (0);
  758. modalWindow.enterModalState();
  759. // open the device and get its info..
  760. log (T("opening ASIO device: ") + getName());
  761. needToReset = false;
  762. isReSync = false;
  763. outputChannelNames.clear();
  764. inputChannelNames.clear();
  765. bufferSizes.clear();
  766. sampleRates.clear();
  767. isASIOOpen = false;
  768. isOpen_ = false;
  769. totalNumInputChans = 0;
  770. totalNumOutputChans = 0;
  771. numActiveInputChans = 0;
  772. numActiveOutputChans = 0;
  773. currentCallback = 0;
  774. error = String::empty;
  775. if (getName().isEmpty())
  776. return error;
  777. long err = 0;
  778. if (loadDriver())
  779. {
  780. if ((error = initDriver()).isEmpty())
  781. {
  782. numActiveInputChans = 0;
  783. numActiveOutputChans = 0;
  784. totalNumInputChans = 0;
  785. totalNumOutputChans = 0;
  786. if (asioObject != 0
  787. && (err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans)) == 0)
  788. {
  789. log (String ((int) totalNumInputChans) + T(" in, ") + String ((int) totalNumOutputChans) + T(" out"));
  790. if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == 0)
  791. {
  792. // find a list of buffer sizes..
  793. log (String ((int) minSize) + T(" ") + String ((int) maxSize) + T(" ") + String ((int)preferredSize) + T(" ") + String ((int)granularity));
  794. if (granularity >= 0)
  795. {
  796. granularity = jmax (1, (int) granularity);
  797. for (int i = jmax (minSize, (int) granularity); i < jmin (6400, maxSize); i += granularity)
  798. bufferSizes.addIfNotAlreadyThere (granularity * (i / granularity));
  799. }
  800. else if (granularity < 0)
  801. {
  802. for (int i = 0; i < 18; ++i)
  803. {
  804. const int s = (1 << i);
  805. if (s >= minSize && s <= maxSize)
  806. bufferSizes.add (s);
  807. }
  808. }
  809. if (! bufferSizes.contains (preferredSize))
  810. bufferSizes.insert (0, preferredSize);
  811. double currentRate = 0;
  812. asioObject->getSampleRate (&currentRate);
  813. if (currentRate <= 0.0 || currentRate > 192001.0)
  814. {
  815. log ("setting sample rate");
  816. err = asioObject->setSampleRate (44100.0);
  817. if (err != 0)
  818. {
  819. logError ("setting sample rate", err);
  820. }
  821. asioObject->getSampleRate (&currentRate);
  822. }
  823. currentSampleRate = currentRate;
  824. postOutput = (asioObject->outputReady() == 0);
  825. if (postOutput)
  826. {
  827. log ("ASIO outputReady = ok");
  828. }
  829. updateSampleRates();
  830. // ..because cubase does it at this point
  831. inputLatency = outputLatency = 0;
  832. if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
  833. {
  834. log ("ASIO - no latencies");
  835. }
  836. log (String ("latencies: ")
  837. + String ((int) inputLatency)
  838. + T(", ") + String ((int) outputLatency));
  839. // create some dummy buffers now.. because cubase does..
  840. numActiveInputChans = 0;
  841. numActiveOutputChans = 0;
  842. ASIOBufferInfo* info = bufferInfos;
  843. int i, numChans = 0;
  844. for (i = 0; i < jmin (2, totalNumInputChans); ++i)
  845. {
  846. info->isInput = 1;
  847. info->channelNum = i;
  848. info->buffers[0] = info->buffers[1] = 0;
  849. ++info;
  850. ++numChans;
  851. }
  852. const int outputBufferIndex = numChans;
  853. for (i = 0; i < jmin (2, totalNumOutputChans); ++i)
  854. {
  855. info->isInput = 0;
  856. info->channelNum = i;
  857. info->buffers[0] = info->buffers[1] = 0;
  858. ++info;
  859. ++numChans;
  860. }
  861. callbacks.sampleRateDidChange = &sampleRateChangedCallback;
  862. if (currentASIODev[0] == this)
  863. {
  864. callbacks.bufferSwitch = &bufferSwitchCallback0;
  865. callbacks.asioMessage = &asioMessagesCallback0;
  866. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0;
  867. }
  868. else if (currentASIODev[1] == this)
  869. {
  870. callbacks.bufferSwitch = &bufferSwitchCallback1;
  871. callbacks.asioMessage = &asioMessagesCallback1;
  872. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1;
  873. }
  874. else if (currentASIODev[2] == this)
  875. {
  876. callbacks.bufferSwitch = &bufferSwitchCallback2;
  877. callbacks.asioMessage = &asioMessagesCallback2;
  878. callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2;
  879. }
  880. else
  881. {
  882. jassertfalse
  883. }
  884. log (T("creating buffers (dummy): ") + String (numChans)
  885. + T(", ") + String ((int) preferredSize));
  886. if (preferredSize > 0)
  887. {
  888. err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks);
  889. if (err != 0)
  890. {
  891. logError ("dummy buffers", err);
  892. }
  893. }
  894. long newInps = 0, newOuts = 0;
  895. asioObject->getChannels (&newInps, &newOuts);
  896. if (totalNumInputChans != newInps || totalNumOutputChans != newOuts)
  897. {
  898. totalNumInputChans = newInps;
  899. totalNumOutputChans = newOuts;
  900. log (String ((int) totalNumInputChans) + T(" in; ")
  901. + String ((int) totalNumOutputChans) + T(" out"));
  902. }
  903. updateSampleRates();
  904. ASIOChannelInfo channelInfo;
  905. channelInfo.type = 0;
  906. for (i = 0; i < totalNumInputChans; ++i)
  907. {
  908. zerostruct (channelInfo);
  909. channelInfo.channel = i;
  910. channelInfo.isInput = 1;
  911. asioObject->getChannelInfo (&channelInfo);
  912. inputChannelNames.add (String (channelInfo.name));
  913. }
  914. for (i = 0; i < totalNumOutputChans; ++i)
  915. {
  916. zerostruct (channelInfo);
  917. channelInfo.channel = i;
  918. channelInfo.isInput = 0;
  919. asioObject->getChannelInfo (&channelInfo);
  920. outputChannelNames.add (String (channelInfo.name));
  921. typeToFormatParameters (channelInfo.type,
  922. outputChannelBitDepths[i],
  923. outputChannelBytesPerSample[i],
  924. outputChannelIsFloat[i],
  925. outputChannelLittleEndian[i]);
  926. if (i < 2)
  927. {
  928. // clear the channels that are used with the dummy stuff
  929. const int bytesPerBuffer = preferredSize * (outputChannelBitDepths[i] >> 3);
  930. zeromem (bufferInfos [outputBufferIndex + i].buffers[0], bytesPerBuffer);
  931. zeromem (bufferInfos [outputBufferIndex + i].buffers[1], bytesPerBuffer);
  932. }
  933. }
  934. outputChannelNames.trim();
  935. inputChannelNames.trim();
  936. outputChannelNames.appendNumbersToDuplicates (false, true);
  937. inputChannelNames.appendNumbersToDuplicates (false, true);
  938. // start and stop because cubase does it..
  939. asioObject->getLatencies (&inputLatency, &outputLatency);
  940. if ((err = asioObject->start()) != 0)
  941. {
  942. // ignore an error here, as it might start later after setting other stuff up
  943. logError ("ASIO start", err);
  944. }
  945. Thread::sleep (100);
  946. asioObject->stop();
  947. }
  948. else
  949. {
  950. error = "Can't detect buffer sizes";
  951. }
  952. }
  953. else
  954. {
  955. error = "Can't detect asio channels";
  956. }
  957. }
  958. }
  959. else
  960. {
  961. error = "No such device";
  962. }
  963. if (error.isNotEmpty())
  964. {
  965. logError (error, err);
  966. if (asioObject != 0)
  967. asioObject->disposeBuffers();
  968. removeCurrentDriver();
  969. isASIOOpen = false;
  970. }
  971. else
  972. {
  973. isASIOOpen = true;
  974. log ("ASIO device open");
  975. }
  976. isOpen_ = false;
  977. needToReset = false;
  978. isReSync = false;
  979. return error;
  980. }
  981. //==============================================================================
  982. void callback (const long index) throw()
  983. {
  984. if (isStarted)
  985. {
  986. bufferIndex = index;
  987. processBuffer();
  988. }
  989. else
  990. {
  991. if (postOutput && (asioObject != 0))
  992. asioObject->outputReady();
  993. }
  994. calledback = true;
  995. }
  996. void processBuffer() throw()
  997. {
  998. const ASIOBufferInfo* const infos = bufferInfos;
  999. const int bi = bufferIndex;
  1000. const ScopedLock sl (callbackLock);
  1001. if (needToReset)
  1002. {
  1003. needToReset = false;
  1004. if (isReSync)
  1005. {
  1006. log ("! ASIO resync");
  1007. isReSync = false;
  1008. }
  1009. else
  1010. {
  1011. startTimer (20);
  1012. }
  1013. }
  1014. if (bi >= 0)
  1015. {
  1016. const int samps = currentBlockSizeSamples;
  1017. if (currentCallback != 0)
  1018. {
  1019. int i;
  1020. for (i = 0; i < numActiveInputChans; ++i)
  1021. {
  1022. float* const dst = inBuffers[i];
  1023. jassert (dst != 0);
  1024. const char* const src = (const char*) (infos[i].buffers[bi]);
  1025. if (inputChannelIsFloat[i])
  1026. {
  1027. memcpy (dst, src, samps * sizeof (float));
  1028. }
  1029. else
  1030. {
  1031. jassert (dst == tempBuffer + (samps * i));
  1032. switch (inputChannelBitDepths[i])
  1033. {
  1034. case 16:
  1035. convertInt16ToFloat (src, dst, inputChannelBytesPerSample[i],
  1036. samps, inputChannelLittleEndian[i]);
  1037. break;
  1038. case 24:
  1039. convertInt24ToFloat (src, dst, inputChannelBytesPerSample[i],
  1040. samps, inputChannelLittleEndian[i]);
  1041. break;
  1042. case 32:
  1043. convertInt32ToFloat (src, dst, inputChannelBytesPerSample[i],
  1044. samps, inputChannelLittleEndian[i]);
  1045. break;
  1046. case 64:
  1047. jassertfalse
  1048. break;
  1049. }
  1050. }
  1051. }
  1052. currentCallback->audioDeviceIOCallback ((const float**) inBuffers,
  1053. numActiveInputChans,
  1054. outBuffers,
  1055. numActiveOutputChans,
  1056. samps);
  1057. for (i = 0; i < numActiveOutputChans; ++i)
  1058. {
  1059. float* const src = outBuffers[i];
  1060. jassert (src != 0);
  1061. char* const dst = (char*) (infos [numActiveInputChans + i].buffers[bi]);
  1062. if (outputChannelIsFloat[i])
  1063. {
  1064. memcpy (dst, src, samps * sizeof (float));
  1065. }
  1066. else
  1067. {
  1068. jassert (src == tempBuffer + (samps * (numActiveInputChans + i)));
  1069. switch (outputChannelBitDepths[i])
  1070. {
  1071. case 16:
  1072. convertFloatToInt16 (src, dst, outputChannelBytesPerSample[i],
  1073. samps, outputChannelLittleEndian[i]);
  1074. break;
  1075. case 24:
  1076. convertFloatToInt24 (src, dst, outputChannelBytesPerSample[i],
  1077. samps, outputChannelLittleEndian[i]);
  1078. break;
  1079. case 32:
  1080. convertFloatToInt32 (src, dst, outputChannelBytesPerSample[i],
  1081. samps, outputChannelLittleEndian[i]);
  1082. break;
  1083. case 64:
  1084. jassertfalse
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. else
  1091. {
  1092. for (int i = 0; i < numActiveOutputChans; ++i)
  1093. {
  1094. const int bytesPerBuffer = samps * (outputChannelBitDepths[i] >> 3);
  1095. zeromem (infos[numActiveInputChans + i].buffers[bi], bytesPerBuffer);
  1096. }
  1097. }
  1098. }
  1099. if (postOutput)
  1100. asioObject->outputReady();
  1101. }
  1102. //==============================================================================
  1103. static ASIOTime* bufferSwitchTimeInfoCallback0 (ASIOTime*, long index, long) throw()
  1104. {
  1105. if (currentASIODev[0] != 0)
  1106. currentASIODev[0]->callback (index);
  1107. return 0;
  1108. }
  1109. static ASIOTime* bufferSwitchTimeInfoCallback1 (ASIOTime*, long index, long) throw()
  1110. {
  1111. if (currentASIODev[1] != 0)
  1112. currentASIODev[1]->callback (index);
  1113. return 0;
  1114. }
  1115. static ASIOTime* bufferSwitchTimeInfoCallback2 (ASIOTime*, long index, long) throw()
  1116. {
  1117. if (currentASIODev[2] != 0)
  1118. currentASIODev[2]->callback (index);
  1119. return 0;
  1120. }
  1121. static void bufferSwitchCallback0 (long index, long) throw()
  1122. {
  1123. if (currentASIODev[0] != 0)
  1124. currentASIODev[0]->callback (index);
  1125. }
  1126. static void bufferSwitchCallback1 (long index, long) throw()
  1127. {
  1128. if (currentASIODev[1] != 0)
  1129. currentASIODev[1]->callback (index);
  1130. }
  1131. static void bufferSwitchCallback2 (long index, long) throw()
  1132. {
  1133. if (currentASIODev[2] != 0)
  1134. currentASIODev[2]->callback (index);
  1135. }
  1136. static long asioMessagesCallback0 (long selector, long value, void*, double*) throw()
  1137. {
  1138. return asioMessagesCallback (selector, value, 0);
  1139. }
  1140. static long asioMessagesCallback1 (long selector, long value, void*, double*) throw()
  1141. {
  1142. return asioMessagesCallback (selector, value, 1);
  1143. }
  1144. static long asioMessagesCallback2 (long selector, long value, void*, double*) throw()
  1145. {
  1146. return asioMessagesCallback (selector, value, 2);
  1147. }
  1148. //==============================================================================
  1149. static long asioMessagesCallback (long selector, long value, const int deviceIndex) throw()
  1150. {
  1151. switch (selector)
  1152. {
  1153. case kAsioSelectorSupported:
  1154. if (value == kAsioResetRequest
  1155. || value == kAsioEngineVersion
  1156. || value == kAsioResyncRequest
  1157. || value == kAsioLatenciesChanged
  1158. || value == kAsioSupportsInputMonitor)
  1159. return 1;
  1160. break;
  1161. case kAsioBufferSizeChange:
  1162. break;
  1163. case kAsioResetRequest:
  1164. if (currentASIODev[deviceIndex] != 0)
  1165. currentASIODev[deviceIndex]->resetRequest();
  1166. return 1;
  1167. case kAsioResyncRequest:
  1168. if (currentASIODev[deviceIndex] != 0)
  1169. currentASIODev[deviceIndex]->resyncRequest();
  1170. return 1;
  1171. case kAsioLatenciesChanged:
  1172. return 1;
  1173. case kAsioEngineVersion:
  1174. return 2;
  1175. case kAsioSupportsTimeInfo:
  1176. case kAsioSupportsTimeCode:
  1177. return 0;
  1178. }
  1179. return 0;
  1180. }
  1181. static void sampleRateChangedCallback (ASIOSampleRate) throw()
  1182. {
  1183. }
  1184. //==============================================================================
  1185. static void convertInt16ToFloat (const char* src,
  1186. float* dest,
  1187. const int srcStrideBytes,
  1188. int numSamples,
  1189. const bool littleEndian) throw()
  1190. {
  1191. const double g = 1.0 / 32768.0;
  1192. if (littleEndian)
  1193. {
  1194. while (--numSamples >= 0)
  1195. {
  1196. *dest++ = (float) (g * (short) littleEndianShort (src));
  1197. src += srcStrideBytes;
  1198. }
  1199. }
  1200. else
  1201. {
  1202. while (--numSamples >= 0)
  1203. {
  1204. *dest++ = (float) (g * (short) bigEndianShort (src));
  1205. src += srcStrideBytes;
  1206. }
  1207. }
  1208. }
  1209. static void convertFloatToInt16 (const float* src,
  1210. char* dest,
  1211. const int dstStrideBytes,
  1212. int numSamples,
  1213. const bool littleEndian) throw()
  1214. {
  1215. const double maxVal = (double) 0x7fff;
  1216. if (littleEndian)
  1217. {
  1218. while (--numSamples >= 0)
  1219. {
  1220. *(uint16*) dest = swapIfBigEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  1221. dest += dstStrideBytes;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. while (--numSamples >= 0)
  1227. {
  1228. *(uint16*) dest = swapIfLittleEndian ((uint16) (short) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  1229. dest += dstStrideBytes;
  1230. }
  1231. }
  1232. }
  1233. static void convertInt24ToFloat (const char* src,
  1234. float* dest,
  1235. const int srcStrideBytes,
  1236. int numSamples,
  1237. const bool littleEndian) throw()
  1238. {
  1239. const double g = 1.0 / 0x7fffff;
  1240. if (littleEndian)
  1241. {
  1242. while (--numSamples >= 0)
  1243. {
  1244. *dest++ = (float) (g * littleEndian24Bit (src));
  1245. src += srcStrideBytes;
  1246. }
  1247. }
  1248. else
  1249. {
  1250. while (--numSamples >= 0)
  1251. {
  1252. *dest++ = (float) (g * bigEndian24Bit (src));
  1253. src += srcStrideBytes;
  1254. }
  1255. }
  1256. }
  1257. static void convertFloatToInt24 (const float* src,
  1258. char* dest,
  1259. const int dstStrideBytes,
  1260. int numSamples,
  1261. const bool littleEndian) throw()
  1262. {
  1263. const double maxVal = (double) 0x7fffff;
  1264. if (littleEndian)
  1265. {
  1266. while (--numSamples >= 0)
  1267. {
  1268. littleEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)), dest);
  1269. dest += dstStrideBytes;
  1270. }
  1271. }
  1272. else
  1273. {
  1274. while (--numSamples >= 0)
  1275. {
  1276. bigEndian24BitToChars ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)), dest);
  1277. dest += dstStrideBytes;
  1278. }
  1279. }
  1280. }
  1281. static void convertInt32ToFloat (const char* src,
  1282. float* dest,
  1283. const int srcStrideBytes,
  1284. int numSamples,
  1285. const bool littleEndian) throw()
  1286. {
  1287. const double g = 1.0 / 0x7fffffff;
  1288. if (littleEndian)
  1289. {
  1290. while (--numSamples >= 0)
  1291. {
  1292. *dest++ = (float) (g * (int) littleEndianInt (src));
  1293. src += srcStrideBytes;
  1294. }
  1295. }
  1296. else
  1297. {
  1298. while (--numSamples >= 0)
  1299. {
  1300. *dest++ = (float) (g * (int) bigEndianInt (src));
  1301. src += srcStrideBytes;
  1302. }
  1303. }
  1304. }
  1305. static void convertFloatToInt32 (const float* src,
  1306. char* dest,
  1307. const int dstStrideBytes,
  1308. int numSamples,
  1309. const bool littleEndian) throw()
  1310. {
  1311. const double maxVal = (double) 0x7fffffff;
  1312. if (littleEndian)
  1313. {
  1314. while (--numSamples >= 0)
  1315. {
  1316. *(uint32*) dest = swapIfBigEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  1317. dest += dstStrideBytes;
  1318. }
  1319. }
  1320. else
  1321. {
  1322. while (--numSamples >= 0)
  1323. {
  1324. *(uint32*) dest = swapIfLittleEndian ((uint32) roundDoubleToInt (jlimit (-maxVal, maxVal, maxVal * *src++)));
  1325. dest += dstStrideBytes;
  1326. }
  1327. }
  1328. }
  1329. //==============================================================================
  1330. static void typeToFormatParameters (const long type,
  1331. int& bitDepth,
  1332. int& byteStride,
  1333. bool& formatIsFloat,
  1334. bool& littleEndian) throw()
  1335. {
  1336. bitDepth = 0;
  1337. littleEndian = false;
  1338. formatIsFloat = false;
  1339. switch (type)
  1340. {
  1341. case ASIOSTInt16MSB:
  1342. case ASIOSTInt16LSB:
  1343. case ASIOSTInt32MSB16:
  1344. case ASIOSTInt32LSB16:
  1345. bitDepth = 16; break;
  1346. case ASIOSTFloat32MSB:
  1347. case ASIOSTFloat32LSB:
  1348. formatIsFloat = true;
  1349. bitDepth = 32; break;
  1350. case ASIOSTInt32MSB:
  1351. case ASIOSTInt32LSB:
  1352. bitDepth = 32; break;
  1353. case ASIOSTInt24MSB:
  1354. case ASIOSTInt24LSB:
  1355. case ASIOSTInt32MSB24:
  1356. case ASIOSTInt32LSB24:
  1357. case ASIOSTInt32MSB18:
  1358. case ASIOSTInt32MSB20:
  1359. case ASIOSTInt32LSB18:
  1360. case ASIOSTInt32LSB20:
  1361. bitDepth = 24; break;
  1362. case ASIOSTFloat64MSB:
  1363. case ASIOSTFloat64LSB:
  1364. default:
  1365. bitDepth = 64;
  1366. break;
  1367. }
  1368. switch (type)
  1369. {
  1370. case ASIOSTInt16MSB:
  1371. case ASIOSTInt32MSB16:
  1372. case ASIOSTFloat32MSB:
  1373. case ASIOSTFloat64MSB:
  1374. case ASIOSTInt32MSB:
  1375. case ASIOSTInt32MSB18:
  1376. case ASIOSTInt32MSB20:
  1377. case ASIOSTInt32MSB24:
  1378. case ASIOSTInt24MSB:
  1379. littleEndian = false; break;
  1380. case ASIOSTInt16LSB:
  1381. case ASIOSTInt32LSB16:
  1382. case ASIOSTFloat32LSB:
  1383. case ASIOSTFloat64LSB:
  1384. case ASIOSTInt32LSB:
  1385. case ASIOSTInt32LSB18:
  1386. case ASIOSTInt32LSB20:
  1387. case ASIOSTInt32LSB24:
  1388. case ASIOSTInt24LSB:
  1389. littleEndian = true; break;
  1390. default:
  1391. break;
  1392. }
  1393. switch (type)
  1394. {
  1395. case ASIOSTInt16LSB:
  1396. case ASIOSTInt16MSB:
  1397. byteStride = 2; break;
  1398. case ASIOSTInt24LSB:
  1399. case ASIOSTInt24MSB:
  1400. byteStride = 3; break;
  1401. case ASIOSTInt32MSB16:
  1402. case ASIOSTInt32LSB16:
  1403. case ASIOSTInt32MSB:
  1404. case ASIOSTInt32MSB18:
  1405. case ASIOSTInt32MSB20:
  1406. case ASIOSTInt32MSB24:
  1407. case ASIOSTInt32LSB:
  1408. case ASIOSTInt32LSB18:
  1409. case ASIOSTInt32LSB20:
  1410. case ASIOSTInt32LSB24:
  1411. case ASIOSTFloat32LSB:
  1412. case ASIOSTFloat32MSB:
  1413. byteStride = 4; break;
  1414. case ASIOSTFloat64MSB:
  1415. case ASIOSTFloat64LSB:
  1416. byteStride = 8; break;
  1417. default:
  1418. break;
  1419. }
  1420. }
  1421. };
  1422. //==============================================================================
  1423. class ASIOAudioIODeviceType : public AudioIODeviceType
  1424. {
  1425. public:
  1426. ASIOAudioIODeviceType()
  1427. : AudioIODeviceType (T("ASIO")),
  1428. classIds (2),
  1429. hasScanned (false)
  1430. {
  1431. CoInitialize (0);
  1432. }
  1433. ~ASIOAudioIODeviceType()
  1434. {
  1435. }
  1436. //==============================================================================
  1437. void scanForDevices()
  1438. {
  1439. hasScanned = true;
  1440. deviceNames.clear();
  1441. classIds.clear();
  1442. HKEY hk = 0;
  1443. int index = 0;
  1444. if (RegOpenKeyA (HKEY_LOCAL_MACHINE, "software\\asio", &hk) == ERROR_SUCCESS)
  1445. {
  1446. for (;;)
  1447. {
  1448. char name [256];
  1449. if (RegEnumKeyA (hk, index++, name, 256) == ERROR_SUCCESS)
  1450. {
  1451. addDriverInfo (name, hk);
  1452. }
  1453. else
  1454. {
  1455. break;
  1456. }
  1457. }
  1458. RegCloseKey (hk);
  1459. }
  1460. }
  1461. const StringArray getDeviceNames (const bool /*wantInputNames*/) const
  1462. {
  1463. jassert (hasScanned); // need to call scanForDevices() before doing this
  1464. return deviceNames;
  1465. }
  1466. int getDefaultDeviceIndex (const bool) const
  1467. {
  1468. jassert (hasScanned); // need to call scanForDevices() before doing this
  1469. for (int i = deviceNames.size(); --i >= 0;)
  1470. if (deviceNames[i].containsIgnoreCase (T("asio4all")))
  1471. return i; // asio4all is a safe choice for a default..
  1472. #if JUCE_DEBUG
  1473. if (deviceNames.size() > 1 && deviceNames[0].containsIgnoreCase (T("digidesign")))
  1474. return 1; // (the digi m-box driver crashes the app when you run
  1475. // it in the debugger, which can be a bit annoying)
  1476. #endif
  1477. return 0;
  1478. }
  1479. static int findFreeSlot()
  1480. {
  1481. for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
  1482. if (currentASIODev[i] == 0)
  1483. return i;
  1484. jassertfalse; // unfortunately you can only have a finite number
  1485. // of ASIO devices open at the same time..
  1486. return -1;
  1487. }
  1488. int getIndexOfDevice (AudioIODevice* d, const bool /*asInput*/) const
  1489. {
  1490. jassert (hasScanned); // need to call scanForDevices() before doing this
  1491. return d == 0 ? -1 : deviceNames.indexOf (d->getName());
  1492. }
  1493. bool hasSeparateInputsAndOutputs() const { return false; }
  1494. AudioIODevice* createDevice (const String& outputDeviceName,
  1495. const String& inputDeviceName)
  1496. {
  1497. jassert (inputDeviceName == outputDeviceName || outputDeviceName.isEmpty() || inputDeviceName.isEmpty());
  1498. (void) inputDeviceName;
  1499. jassert (hasScanned); // need to call scanForDevices() before doing this
  1500. const int index = deviceNames.indexOf (outputDeviceName);
  1501. if (index >= 0)
  1502. {
  1503. const int freeSlot = findFreeSlot();
  1504. if (freeSlot >= 0)
  1505. return new ASIOAudioIODevice (outputDeviceName, *(classIds [index]), freeSlot, String::empty);
  1506. }
  1507. return 0;
  1508. }
  1509. //==============================================================================
  1510. juce_UseDebuggingNewOperator
  1511. private:
  1512. StringArray deviceNames;
  1513. OwnedArray <CLSID> classIds;
  1514. bool hasScanned;
  1515. //==============================================================================
  1516. static bool checkClassIsOk (const String& classId)
  1517. {
  1518. HKEY hk = 0;
  1519. bool ok = false;
  1520. if (RegOpenKeyA (HKEY_CLASSES_ROOT, "clsid", &hk) == ERROR_SUCCESS)
  1521. {
  1522. int index = 0;
  1523. for (;;)
  1524. {
  1525. char buf [512];
  1526. if (RegEnumKeyA (hk, index++, buf, 512) == ERROR_SUCCESS)
  1527. {
  1528. if (classId.equalsIgnoreCase (buf))
  1529. {
  1530. HKEY subKey, pathKey;
  1531. if (RegOpenKeyExA (hk, buf, 0, KEY_READ, &subKey) == ERROR_SUCCESS)
  1532. {
  1533. if (RegOpenKeyExA (subKey, "InprocServer32", 0, KEY_READ, &pathKey) == ERROR_SUCCESS)
  1534. {
  1535. char pathName [600];
  1536. DWORD dtype = REG_SZ;
  1537. DWORD dsize = sizeof (pathName);
  1538. if (RegQueryValueExA (pathKey, 0, 0, &dtype,
  1539. (LPBYTE) pathName, &dsize) == ERROR_SUCCESS)
  1540. {
  1541. OFSTRUCT of;
  1542. zerostruct (of);
  1543. of.cBytes = sizeof (of);
  1544. ok = (OpenFile (String (pathName), &of, OF_EXIST) != 0);
  1545. }
  1546. RegCloseKey (pathKey);
  1547. }
  1548. RegCloseKey (subKey);
  1549. }
  1550. break;
  1551. }
  1552. }
  1553. else
  1554. {
  1555. break;
  1556. }
  1557. }
  1558. RegCloseKey (hk);
  1559. }
  1560. return ok;
  1561. }
  1562. //==============================================================================
  1563. void addDriverInfo (const String& keyName, HKEY hk)
  1564. {
  1565. HKEY subKey;
  1566. if (RegOpenKeyExA (hk, keyName, 0, KEY_READ, &subKey) == ERROR_SUCCESS)
  1567. {
  1568. char buf [256];
  1569. DWORD dtype = REG_SZ;
  1570. DWORD dsize = sizeof (buf);
  1571. zeromem (buf, dsize);
  1572. if (RegQueryValueExA (subKey, "clsid", 0, &dtype, (LPBYTE) buf, &dsize) == ERROR_SUCCESS)
  1573. {
  1574. if (dsize > 0 && checkClassIsOk (buf))
  1575. {
  1576. wchar_t classIdStr [130];
  1577. MultiByteToWideChar (CP_ACP, 0, buf, -1, classIdStr, 128);
  1578. String deviceName;
  1579. CLSID classId;
  1580. if (CLSIDFromString ((LPOLESTR) classIdStr, &classId) == S_OK)
  1581. {
  1582. dtype = REG_SZ;
  1583. dsize = sizeof (buf);
  1584. if (RegQueryValueExA (subKey, "description", 0, &dtype, (LPBYTE) buf, &dsize) == ERROR_SUCCESS)
  1585. deviceName = buf;
  1586. else
  1587. deviceName = keyName;
  1588. log (T("found ") + deviceName);
  1589. deviceNames.add (deviceName);
  1590. classIds.add (new CLSID (classId));
  1591. }
  1592. }
  1593. RegCloseKey (subKey);
  1594. }
  1595. }
  1596. }
  1597. ASIOAudioIODeviceType (const ASIOAudioIODeviceType&);
  1598. const ASIOAudioIODeviceType& operator= (const ASIOAudioIODeviceType&);
  1599. };
  1600. AudioIODeviceType* juce_createASIOAudioIODeviceType()
  1601. {
  1602. return new ASIOAudioIODeviceType();
  1603. }
  1604. AudioIODevice* juce_createASIOAudioIODeviceForGUID (const String& name,
  1605. void* guid,
  1606. const String& optionalDllForDirectLoading)
  1607. {
  1608. const int freeSlot = ASIOAudioIODeviceType::findFreeSlot();
  1609. if (freeSlot < 0)
  1610. return 0;
  1611. return new ASIOAudioIODevice (name, *(CLSID*) guid, freeSlot, optionalDllForDirectLoading);
  1612. }
  1613. #undef log
  1614. #endif