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.

1948 lines
61KB

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