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.

1944 lines
62KB

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