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.

1994 lines
64KB

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