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.

1875 lines
62KB

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