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.

1978 lines
63KB

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