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.

1653 lines
50KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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
  21. //==============================================================================
  22. END_JUCE_NAMESPACE
  23. extern "C"
  24. {
  25. // Declare just the minimum number of interfaces for the DSound objects that we need..
  26. typedef struct typeDSBUFFERDESC
  27. {
  28. DWORD dwSize;
  29. DWORD dwFlags;
  30. DWORD dwBufferBytes;
  31. DWORD dwReserved;
  32. LPWAVEFORMATEX lpwfxFormat;
  33. GUID guid3DAlgorithm;
  34. } DSBUFFERDESC;
  35. struct IDirectSoundBuffer;
  36. #undef INTERFACE
  37. #define INTERFACE IDirectSound
  38. DECLARE_INTERFACE_(IDirectSound, IUnknown)
  39. {
  40. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  41. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  42. STDMETHOD_(ULONG,Release) (THIS) PURE;
  43. STDMETHOD(CreateSoundBuffer) (THIS_ DSBUFFERDESC*, IDirectSoundBuffer**, LPUNKNOWN) PURE;
  44. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  45. STDMETHOD(DuplicateSoundBuffer) (THIS_ IDirectSoundBuffer*, IDirectSoundBuffer**) PURE;
  46. STDMETHOD(SetCooperativeLevel) (THIS_ HWND, DWORD) PURE;
  47. STDMETHOD(Compact) (THIS) PURE;
  48. STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD) PURE;
  49. STDMETHOD(SetSpeakerConfig) (THIS_ DWORD) PURE;
  50. STDMETHOD(Initialize) (THIS_ const GUID*) PURE;
  51. };
  52. #undef INTERFACE
  53. #define INTERFACE IDirectSoundBuffer
  54. DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown)
  55. {
  56. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  57. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  58. STDMETHOD_(ULONG,Release) (THIS) PURE;
  59. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  60. STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD) PURE;
  61. STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
  62. STDMETHOD(GetVolume) (THIS_ LPLONG) PURE;
  63. STDMETHOD(GetPan) (THIS_ LPLONG) PURE;
  64. STDMETHOD(GetFrequency) (THIS_ LPDWORD) PURE;
  65. STDMETHOD(GetStatus) (THIS_ LPDWORD) PURE;
  66. STDMETHOD(Initialize) (THIS_ IDirectSound*, DSBUFFERDESC*) PURE;
  67. STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
  68. STDMETHOD(Play) (THIS_ DWORD, DWORD, DWORD) PURE;
  69. STDMETHOD(SetCurrentPosition) (THIS_ DWORD) PURE;
  70. STDMETHOD(SetFormat) (THIS_ const WAVEFORMATEX*) PURE;
  71. STDMETHOD(SetVolume) (THIS_ LONG) PURE;
  72. STDMETHOD(SetPan) (THIS_ LONG) PURE;
  73. STDMETHOD(SetFrequency) (THIS_ DWORD) PURE;
  74. STDMETHOD(Stop) (THIS) PURE;
  75. STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
  76. STDMETHOD(Restore) (THIS) PURE;
  77. };
  78. //==============================================================================
  79. typedef struct typeDSCBUFFERDESC
  80. {
  81. DWORD dwSize;
  82. DWORD dwFlags;
  83. DWORD dwBufferBytes;
  84. DWORD dwReserved;
  85. LPWAVEFORMATEX lpwfxFormat;
  86. } DSCBUFFERDESC;
  87. struct IDirectSoundCaptureBuffer;
  88. #undef INTERFACE
  89. #define INTERFACE IDirectSoundCapture
  90. DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown)
  91. {
  92. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  93. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  94. STDMETHOD_(ULONG,Release) (THIS) PURE;
  95. STDMETHOD(CreateCaptureBuffer) (THIS_ DSCBUFFERDESC*, IDirectSoundCaptureBuffer**, LPUNKNOWN) PURE;
  96. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  97. STDMETHOD(Initialize) (THIS_ const GUID*) PURE;
  98. };
  99. #undef INTERFACE
  100. #define INTERFACE IDirectSoundCaptureBuffer
  101. DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown)
  102. {
  103. STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
  104. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  105. STDMETHOD_(ULONG,Release) (THIS) PURE;
  106. STDMETHOD(GetCaps) (THIS_ void*) PURE;
  107. STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD) PURE;
  108. STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
  109. STDMETHOD(GetStatus) (THIS_ LPDWORD) PURE;
  110. STDMETHOD(Initialize) (THIS_ IDirectSoundCapture*, DSCBUFFERDESC*) PURE;
  111. STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
  112. STDMETHOD(Start) (THIS_ DWORD) PURE;
  113. STDMETHOD(Stop) (THIS) PURE;
  114. STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
  115. };
  116. };
  117. //==============================================================================
  118. BEGIN_JUCE_NAMESPACE
  119. #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
  120. #include "../../../src/juce_appframework/audio/devices/juce_AudioDeviceManager.h"
  121. #include "../../../src/juce_appframework/application/juce_Application.h"
  122. #include "../../../src/juce_appframework/gui/components/windows/juce_AlertWindow.h"
  123. #include "../../../src/juce_core/threads/juce_Thread.h"
  124. #include "../../../src/juce_core/basics/juce_Singleton.h"
  125. #include "../../../src/juce_core/basics/juce_Time.h"
  126. #include "../../../src/juce_core/containers/juce_OwnedArray.h"
  127. #include "../../../src/juce_core/text/juce_LocalisedStrings.h"
  128. #include "../../../src/juce_appframework/gui/components/buttons/juce_TextButton.h"
  129. #include "../../../src/juce_appframework/gui/components/special/juce_AudioDeviceSelectorComponent.h"
  130. static const String getDSErrorMessage (HRESULT hr)
  131. {
  132. const char* result = 0;
  133. switch (hr)
  134. {
  135. case MAKE_HRESULT(1, 0x878, 10):
  136. result = "Device already allocated";
  137. break;
  138. case MAKE_HRESULT(1, 0x878, 30):
  139. result = "Control unavailable";
  140. break;
  141. case E_INVALIDARG:
  142. result = "Invalid parameter";
  143. break;
  144. case MAKE_HRESULT(1, 0x878, 50):
  145. result = "Invalid call";
  146. break;
  147. case E_FAIL:
  148. result = "Generic error";
  149. break;
  150. case MAKE_HRESULT(1, 0x878, 70):
  151. result = "Priority level error";
  152. break;
  153. case E_OUTOFMEMORY:
  154. result = "Out of memory";
  155. break;
  156. case MAKE_HRESULT(1, 0x878, 100):
  157. result = "Bad format";
  158. break;
  159. case E_NOTIMPL:
  160. result = "Unsupported function";
  161. break;
  162. case MAKE_HRESULT(1, 0x878, 120):
  163. result = "No driver";
  164. break;
  165. case MAKE_HRESULT(1, 0x878, 130):
  166. result = "Already initialised";
  167. break;
  168. case CLASS_E_NOAGGREGATION:
  169. result = "No aggregation";
  170. break;
  171. case MAKE_HRESULT(1, 0x878, 150):
  172. result = "Buffer lost";
  173. break;
  174. case MAKE_HRESULT(1, 0x878, 160):
  175. result = "Another app has priority";
  176. break;
  177. case MAKE_HRESULT(1, 0x878, 170):
  178. result = "Uninitialised";
  179. break;
  180. case E_NOINTERFACE:
  181. result = "No interface";
  182. break;
  183. case S_OK:
  184. result = "No error";
  185. break;
  186. default:
  187. return "Unknown error: " + String ((int) hr);
  188. }
  189. return result;
  190. }
  191. //==============================================================================
  192. #define DS_DEBUGGING 1
  193. #ifdef DS_DEBUGGING
  194. #define CATCH JUCE_CATCH_EXCEPTION
  195. #undef log
  196. #define log(a) Logger::writeToLog(a);
  197. #undef logError
  198. #define logError(a) logDSError(a, __LINE__);
  199. static void logDSError (HRESULT hr, int lineNum)
  200. {
  201. if (hr != S_OK)
  202. {
  203. String error ("DS error at line ");
  204. error << lineNum << T(" - ") << getDSErrorMessage (hr);
  205. log (error);
  206. }
  207. }
  208. #else
  209. #define CATCH JUCE_CATCH_ALL
  210. #define log(a)
  211. #define logError(a)
  212. #endif
  213. //==============================================================================
  214. #define DSOUND_FUNCTION(functionName, params) \
  215. typedef HRESULT (WINAPI *type##functionName) params; \
  216. static type##functionName ds##functionName = 0;
  217. #define DSOUND_FUNCTION_LOAD(functionName) \
  218. ds##functionName = (type##functionName) GetProcAddress (h, #functionName); \
  219. jassert (ds##functionName != 0);
  220. typedef BOOL (CALLBACK *LPDSENUMCALLBACKW) (LPGUID, LPCWSTR, LPCWSTR, LPVOID);
  221. typedef BOOL (CALLBACK *LPDSENUMCALLBACKA) (LPGUID, LPCSTR, LPCSTR, LPVOID);
  222. DSOUND_FUNCTION (DirectSoundCreate, (const GUID*, IDirectSound**, LPUNKNOWN))
  223. DSOUND_FUNCTION (DirectSoundCaptureCreate, (const GUID*, IDirectSoundCapture**, LPUNKNOWN))
  224. DSOUND_FUNCTION (DirectSoundEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  225. DSOUND_FUNCTION (DirectSoundCaptureEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
  226. static void initialiseDSoundFunctions()
  227. {
  228. if (dsDirectSoundCreate == 0)
  229. {
  230. HMODULE h = LoadLibraryA ("dsound.dll");
  231. DSOUND_FUNCTION_LOAD (DirectSoundCreate)
  232. DSOUND_FUNCTION_LOAD (DirectSoundCaptureCreate)
  233. DSOUND_FUNCTION_LOAD (DirectSoundEnumerateW)
  234. DSOUND_FUNCTION_LOAD (DirectSoundCaptureEnumerateW)
  235. }
  236. }
  237. //==============================================================================
  238. class DSoundInternalOutChannel
  239. {
  240. String name;
  241. LPGUID guid;
  242. int sampleRate, bufferSizeSamples;
  243. float* leftBuffer;
  244. float* rightBuffer;
  245. IDirectSound* pDirectSound;
  246. IDirectSoundBuffer* pOutputBuffer;
  247. DWORD writeOffset;
  248. int totalBytesPerBuffer;
  249. int bytesPerBuffer;
  250. unsigned int lastPlayCursor;
  251. public:
  252. int bitDepth;
  253. bool doneFlag;
  254. DSoundInternalOutChannel (const String& name_,
  255. LPGUID guid_,
  256. int rate,
  257. int bufferSize,
  258. float* left,
  259. float* right)
  260. : name (name_),
  261. guid (guid_),
  262. sampleRate (rate),
  263. bufferSizeSamples (bufferSize),
  264. leftBuffer (left),
  265. rightBuffer (right),
  266. pDirectSound (0),
  267. pOutputBuffer (0),
  268. bitDepth (16)
  269. {
  270. }
  271. ~DSoundInternalOutChannel()
  272. {
  273. close();
  274. }
  275. void close()
  276. {
  277. HRESULT hr;
  278. if (pOutputBuffer != 0)
  279. {
  280. JUCE_TRY
  281. {
  282. log (T("closing dsound out: ") + name);
  283. hr = pOutputBuffer->Stop();
  284. logError (hr);
  285. }
  286. CATCH
  287. JUCE_TRY
  288. {
  289. hr = pOutputBuffer->Release();
  290. logError (hr);
  291. }
  292. CATCH
  293. pOutputBuffer = 0;
  294. }
  295. if (pDirectSound != 0)
  296. {
  297. JUCE_TRY
  298. {
  299. hr = pDirectSound->Release();
  300. logError (hr);
  301. }
  302. CATCH
  303. pDirectSound = 0;
  304. }
  305. }
  306. const String open()
  307. {
  308. log (T("opening dsound out device: ") + name
  309. + T(" rate=") + String (sampleRate)
  310. + T(" bits=") + String (bitDepth)
  311. + T(" buf=") + String (bufferSizeSamples));
  312. pDirectSound = 0;
  313. pOutputBuffer = 0;
  314. writeOffset = 0;
  315. String error;
  316. HRESULT hr = E_NOINTERFACE;
  317. if (dsDirectSoundCreate != 0)
  318. hr = dsDirectSoundCreate (guid, &pDirectSound, 0);
  319. if (hr == S_OK)
  320. {
  321. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  322. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  323. const int numChannels = 2;
  324. hr = pDirectSound->SetCooperativeLevel (GetDesktopWindow(), 2 /* DSSCL_PRIORITY */);
  325. logError (hr);
  326. if (hr == S_OK)
  327. {
  328. IDirectSoundBuffer* pPrimaryBuffer;
  329. DSBUFFERDESC primaryDesc;
  330. zerostruct (primaryDesc);
  331. primaryDesc.dwSize = sizeof (DSBUFFERDESC);
  332. primaryDesc.dwFlags = 1 /* DSBCAPS_PRIMARYBUFFER */;
  333. primaryDesc.dwBufferBytes = 0;
  334. primaryDesc.lpwfxFormat = 0;
  335. log ("opening dsound out step 2");
  336. hr = pDirectSound->CreateSoundBuffer (&primaryDesc, &pPrimaryBuffer, 0);
  337. logError (hr);
  338. if (hr == S_OK)
  339. {
  340. WAVEFORMATEX wfFormat;
  341. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  342. wfFormat.nChannels = (unsigned short) numChannels;
  343. wfFormat.nSamplesPerSec = sampleRate;
  344. wfFormat.wBitsPerSample = (unsigned short) bitDepth;
  345. wfFormat.nBlockAlign = (unsigned short) (wfFormat.nChannels * wfFormat.wBitsPerSample / 8);
  346. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  347. wfFormat.cbSize = 0;
  348. hr = pPrimaryBuffer->SetFormat (&wfFormat);
  349. logError (hr);
  350. if (hr == S_OK)
  351. {
  352. DSBUFFERDESC secondaryDesc;
  353. zerostruct (secondaryDesc);
  354. secondaryDesc.dwSize = sizeof (DSBUFFERDESC);
  355. secondaryDesc.dwFlags = 0x8000 /* DSBCAPS_GLOBALFOCUS */
  356. | 0x10000 /* DSBCAPS_GETCURRENTPOSITION2 */;
  357. secondaryDesc.dwBufferBytes = totalBytesPerBuffer;
  358. secondaryDesc.lpwfxFormat = &wfFormat;
  359. hr = pDirectSound->CreateSoundBuffer (&secondaryDesc, &pOutputBuffer, 0);
  360. logError (hr);
  361. if (hr == S_OK)
  362. {
  363. log ("opening dsound out step 3");
  364. DWORD dwDataLen;
  365. unsigned char* pDSBuffData;
  366. hr = pOutputBuffer->Lock (0, totalBytesPerBuffer,
  367. (LPVOID*) &pDSBuffData, &dwDataLen, 0, 0, 0);
  368. logError (hr);
  369. if (hr == S_OK)
  370. {
  371. zeromem (pDSBuffData, dwDataLen);
  372. hr = pOutputBuffer->Unlock (pDSBuffData, dwDataLen, 0, 0);
  373. if (hr == S_OK)
  374. {
  375. hr = pOutputBuffer->SetCurrentPosition (0);
  376. if (hr == S_OK)
  377. {
  378. hr = pOutputBuffer->Play (0, 0, 1 /* DSBPLAY_LOOPING */);
  379. if (hr == S_OK)
  380. return String::empty;
  381. }
  382. }
  383. }
  384. }
  385. }
  386. }
  387. }
  388. }
  389. error = getDSErrorMessage (hr);
  390. close();
  391. return error;
  392. }
  393. void synchronisePosition()
  394. {
  395. if (pOutputBuffer != 0)
  396. {
  397. DWORD playCursor;
  398. pOutputBuffer->GetCurrentPosition (&playCursor, &writeOffset);
  399. }
  400. }
  401. bool service()
  402. {
  403. if (pOutputBuffer == 0)
  404. return true;
  405. DWORD playCursor, writeCursor;
  406. HRESULT hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
  407. if (hr != S_OK)
  408. {
  409. logError (hr);
  410. jassertfalse
  411. return true;
  412. }
  413. int playWriteGap = writeCursor - playCursor;
  414. if (playWriteGap < 0)
  415. playWriteGap += totalBytesPerBuffer;
  416. int bytesEmpty = playCursor - writeOffset;
  417. if (bytesEmpty < 0)
  418. bytesEmpty += totalBytesPerBuffer;
  419. if (bytesEmpty > (totalBytesPerBuffer - playWriteGap))
  420. {
  421. writeOffset = writeCursor;
  422. bytesEmpty = totalBytesPerBuffer - playWriteGap;
  423. }
  424. if (bytesEmpty >= bytesPerBuffer)
  425. {
  426. LPBYTE lpbuf1 = 0;
  427. LPBYTE lpbuf2 = 0;
  428. DWORD dwSize1 = 0;
  429. DWORD dwSize2 = 0;
  430. HRESULT hr = pOutputBuffer->Lock (writeOffset,
  431. bytesPerBuffer,
  432. (void**) &lpbuf1, &dwSize1,
  433. (void**) &lpbuf2, &dwSize2, 0);
  434. if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
  435. {
  436. pOutputBuffer->Restore();
  437. hr = pOutputBuffer->Lock (writeOffset,
  438. bytesPerBuffer,
  439. (void**) &lpbuf1, &dwSize1,
  440. (void**) &lpbuf2, &dwSize2, 0);
  441. }
  442. if (hr == S_OK)
  443. {
  444. if (bitDepth == 16)
  445. {
  446. const float gainL = 32767.0f;
  447. const float gainR = 32767.0f;
  448. int* dest = (int*)lpbuf1;
  449. const float* left = leftBuffer;
  450. const float* right = rightBuffer;
  451. int samples1 = dwSize1 >> 2;
  452. int samples2 = dwSize2 >> 2;
  453. if (left == 0)
  454. {
  455. while (--samples1 >= 0)
  456. {
  457. int r = roundFloatToInt (gainR * *right++);
  458. if (r < -32768)
  459. r = -32768;
  460. else if (r > 32767)
  461. r = 32767;
  462. *dest++ = (r << 16);
  463. }
  464. dest = (int*)lpbuf2;
  465. while (--samples2 >= 0)
  466. {
  467. int r = roundFloatToInt (gainR * *right++);
  468. if (r < -32768)
  469. r = -32768;
  470. else if (r > 32767)
  471. r = 32767;
  472. *dest++ = (r << 16);
  473. }
  474. }
  475. else if (right == 0)
  476. {
  477. while (--samples1 >= 0)
  478. {
  479. int l = roundFloatToInt (gainL * *left++);
  480. if (l < -32768)
  481. l = -32768;
  482. else if (l > 32767)
  483. l = 32767;
  484. l &= 0xffff;
  485. *dest++ = l;
  486. }
  487. dest = (int*)lpbuf2;
  488. while (--samples2 >= 0)
  489. {
  490. int l = roundFloatToInt (gainL * *left++);
  491. if (l < -32768)
  492. l = -32768;
  493. else if (l > 32767)
  494. l = 32767;
  495. l &= 0xffff;
  496. *dest++ = l;
  497. }
  498. }
  499. else
  500. {
  501. while (--samples1 >= 0)
  502. {
  503. int l = roundFloatToInt (gainL * *left++);
  504. if (l < -32768)
  505. l = -32768;
  506. else if (l > 32767)
  507. l = 32767;
  508. l &= 0xffff;
  509. int r = roundFloatToInt (gainR * *right++);
  510. if (r < -32768)
  511. r = -32768;
  512. else if (r > 32767)
  513. r = 32767;
  514. *dest++ = (r << 16) | l;
  515. }
  516. dest = (int*)lpbuf2;
  517. while (--samples2 >= 0)
  518. {
  519. int l = roundFloatToInt (gainL * *left++);
  520. if (l < -32768)
  521. l = -32768;
  522. else if (l > 32767)
  523. l = 32767;
  524. l &= 0xffff;
  525. int r = roundFloatToInt (gainR * *right++);
  526. if (r < -32768)
  527. r = -32768;
  528. else if (r > 32767)
  529. r = 32767;
  530. *dest++ = (r << 16) | l;
  531. }
  532. }
  533. }
  534. else
  535. {
  536. jassertfalse
  537. }
  538. writeOffset = (writeOffset + dwSize1 + dwSize2) % totalBytesPerBuffer;
  539. pOutputBuffer->Unlock (lpbuf1, dwSize1, lpbuf2, dwSize2);
  540. }
  541. else
  542. {
  543. jassertfalse
  544. logError (hr);
  545. }
  546. bytesEmpty -= bytesPerBuffer;
  547. return true;
  548. }
  549. else
  550. {
  551. return false;
  552. }
  553. }
  554. };
  555. //==============================================================================
  556. struct DSoundInternalInChannel
  557. {
  558. String name;
  559. LPGUID guid;
  560. int sampleRate, bufferSizeSamples;
  561. float* leftBuffer;
  562. float* rightBuffer;
  563. IDirectSound* pDirectSound;
  564. IDirectSoundCapture* pDirectSoundCapture;
  565. IDirectSoundCaptureBuffer* pInputBuffer;
  566. public:
  567. unsigned int readOffset;
  568. int bytesPerBuffer, totalBytesPerBuffer;
  569. int bitDepth;
  570. bool doneFlag;
  571. DSoundInternalInChannel (const String& name_,
  572. LPGUID guid_,
  573. int rate,
  574. int bufferSize,
  575. float* left,
  576. float* right)
  577. : name (name_),
  578. guid (guid_),
  579. sampleRate (rate),
  580. bufferSizeSamples (bufferSize),
  581. leftBuffer (left),
  582. rightBuffer (right),
  583. pDirectSound (0),
  584. pDirectSoundCapture (0),
  585. pInputBuffer (0),
  586. bitDepth (16)
  587. {
  588. }
  589. ~DSoundInternalInChannel()
  590. {
  591. close();
  592. }
  593. void close()
  594. {
  595. HRESULT hr;
  596. if (pInputBuffer != 0)
  597. {
  598. JUCE_TRY
  599. {
  600. log (T("closing dsound in: ") + name);
  601. hr = pInputBuffer->Stop();
  602. logError (hr);
  603. }
  604. CATCH
  605. JUCE_TRY
  606. {
  607. hr = pInputBuffer->Release();
  608. logError (hr);
  609. }
  610. CATCH
  611. pInputBuffer = 0;
  612. }
  613. if (pDirectSoundCapture != 0)
  614. {
  615. JUCE_TRY
  616. {
  617. hr = pDirectSoundCapture->Release();
  618. logError (hr);
  619. }
  620. CATCH
  621. pDirectSoundCapture = 0;
  622. }
  623. if (pDirectSound != 0)
  624. {
  625. JUCE_TRY
  626. {
  627. hr = pDirectSound->Release();
  628. logError (hr);
  629. }
  630. CATCH
  631. pDirectSound = 0;
  632. }
  633. }
  634. const String open()
  635. {
  636. log (T("opening dsound in device: ") + name
  637. + T(" rate=") + String (sampleRate) + T(" bits=") + String (bitDepth) + T(" buf=") + String (bufferSizeSamples));
  638. pDirectSound = 0;
  639. pDirectSoundCapture = 0;
  640. pInputBuffer = 0;
  641. readOffset = 0;
  642. totalBytesPerBuffer = 0;
  643. String error;
  644. HRESULT hr = E_NOINTERFACE;
  645. if (dsDirectSoundCaptureCreate != 0)
  646. hr = dsDirectSoundCaptureCreate (guid, &pDirectSoundCapture, 0);
  647. logError (hr);
  648. if (hr == S_OK)
  649. {
  650. const int numChannels = 2;
  651. bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
  652. totalBytesPerBuffer = (3 * bytesPerBuffer) & ~15;
  653. WAVEFORMATEX wfFormat;
  654. wfFormat.wFormatTag = WAVE_FORMAT_PCM;
  655. wfFormat.nChannels = (unsigned short)numChannels;
  656. wfFormat.nSamplesPerSec = sampleRate;
  657. wfFormat.wBitsPerSample = (unsigned short)bitDepth;
  658. wfFormat.nBlockAlign = (unsigned short)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
  659. wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
  660. wfFormat.cbSize = 0;
  661. DSCBUFFERDESC captureDesc;
  662. zerostruct (captureDesc);
  663. captureDesc.dwSize = sizeof (DSCBUFFERDESC);
  664. captureDesc.dwFlags = 0;
  665. captureDesc.dwBufferBytes = totalBytesPerBuffer;
  666. captureDesc.lpwfxFormat = &wfFormat;
  667. log (T("opening dsound in step 2"));
  668. hr = pDirectSoundCapture->CreateCaptureBuffer (&captureDesc, &pInputBuffer, 0);
  669. logError (hr);
  670. if (hr == S_OK)
  671. {
  672. hr = pInputBuffer->Start (1 /* DSCBSTART_LOOPING */);
  673. logError (hr);
  674. if (hr == S_OK)
  675. return String::empty;
  676. }
  677. }
  678. error = getDSErrorMessage (hr);
  679. close();
  680. return error;
  681. }
  682. void synchronisePosition()
  683. {
  684. if (pInputBuffer != 0)
  685. {
  686. DWORD capturePos;
  687. pInputBuffer->GetCurrentPosition (&capturePos, (DWORD*)&readOffset);
  688. }
  689. }
  690. bool service()
  691. {
  692. if (pInputBuffer == 0)
  693. return true;
  694. DWORD capturePos, readPos;
  695. HRESULT hr = pInputBuffer->GetCurrentPosition (&capturePos, &readPos);
  696. logError (hr);
  697. if (hr != S_OK)
  698. return true;
  699. int bytesFilled = readPos - readOffset;
  700. if (bytesFilled < 0)
  701. bytesFilled += totalBytesPerBuffer;
  702. if (bytesFilled >= bytesPerBuffer)
  703. {
  704. LPBYTE lpbuf1 = 0;
  705. LPBYTE lpbuf2 = 0;
  706. DWORD dwsize1 = 0;
  707. DWORD dwsize2 = 0;
  708. HRESULT hr = pInputBuffer->Lock (readOffset,
  709. bytesPerBuffer,
  710. (void**) &lpbuf1, &dwsize1,
  711. (void**) &lpbuf2, &dwsize2, 0);
  712. if (hr == S_OK)
  713. {
  714. if (bitDepth == 16)
  715. {
  716. const float g = 1.0f / 32768.0f;
  717. float* destL = leftBuffer;
  718. float* destR = rightBuffer;
  719. int samples1 = dwsize1 >> 2;
  720. int samples2 = dwsize2 >> 2;
  721. const short* src = (const short*)lpbuf1;
  722. if (destL == 0)
  723. {
  724. while (--samples1 >= 0)
  725. {
  726. ++src;
  727. *destR++ = *src++ * g;
  728. }
  729. src = (const short*)lpbuf2;
  730. while (--samples2 >= 0)
  731. {
  732. ++src;
  733. *destR++ = *src++ * g;
  734. }
  735. }
  736. else if (destR == 0)
  737. {
  738. while (--samples1 >= 0)
  739. {
  740. *destL++ = *src++ * g;
  741. ++src;
  742. }
  743. src = (const short*)lpbuf2;
  744. while (--samples2 >= 0)
  745. {
  746. *destL++ = *src++ * g;
  747. ++src;
  748. }
  749. }
  750. else
  751. {
  752. while (--samples1 >= 0)
  753. {
  754. *destL++ = *src++ * g;
  755. *destR++ = *src++ * g;
  756. }
  757. src = (const short*)lpbuf2;
  758. while (--samples2 >= 0)
  759. {
  760. *destL++ = *src++ * g;
  761. *destR++ = *src++ * g;
  762. }
  763. }
  764. }
  765. else
  766. {
  767. jassertfalse
  768. }
  769. readOffset = (readOffset + dwsize1 + dwsize2) % totalBytesPerBuffer;
  770. pInputBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
  771. }
  772. else
  773. {
  774. logError (hr);
  775. jassertfalse
  776. }
  777. bytesFilled -= bytesPerBuffer;
  778. return true;
  779. }
  780. else
  781. {
  782. return false;
  783. }
  784. }
  785. };
  786. //==============================================================================
  787. class DSoundAudioIODevice : public AudioIODevice,
  788. public Thread
  789. {
  790. public:
  791. DSoundAudioIODevice (const String& deviceName,
  792. const int outputDeviceIndex_,
  793. const int inputDeviceIndex_)
  794. : AudioIODevice (deviceName, "DirectSound"),
  795. Thread ("Juce DSound"),
  796. isOpen_ (false),
  797. isStarted (false),
  798. outputDeviceIndex (outputDeviceIndex_),
  799. inputDeviceIndex (inputDeviceIndex_),
  800. inChans (4),
  801. outChans (4),
  802. numInputBuffers (0),
  803. numOutputBuffers (0),
  804. totalSamplesOut (0),
  805. sampleRate (0.0),
  806. inputBuffers (0),
  807. outputBuffers (0),
  808. callback (0),
  809. bufferSizeSamples (0)
  810. {
  811. if (outputDeviceIndex_ >= 0)
  812. {
  813. outChannels.add (TRANS("Left"));
  814. outChannels.add (TRANS("Right"));
  815. }
  816. if (inputDeviceIndex_ >= 0)
  817. {
  818. inChannels.add (TRANS("Left"));
  819. inChannels.add (TRANS("Right"));
  820. }
  821. }
  822. ~DSoundAudioIODevice()
  823. {
  824. close();
  825. }
  826. const StringArray getOutputChannelNames()
  827. {
  828. return outChannels;
  829. }
  830. const StringArray getInputChannelNames()
  831. {
  832. return inChannels;
  833. }
  834. int getNumSampleRates()
  835. {
  836. return 4;
  837. }
  838. double getSampleRate (int index)
  839. {
  840. const double samps[] = { 44100.0, 48000.0, 88200.0, 96000.0 };
  841. return samps [jlimit (0, 3, index)];
  842. }
  843. int getNumBufferSizesAvailable()
  844. {
  845. return 50;
  846. }
  847. int getBufferSizeSamples (int index)
  848. {
  849. int n = 64;
  850. for (int i = 0; i < index; ++i)
  851. n += (n < 512) ? 32
  852. : ((n < 1024) ? 64
  853. : ((n < 2048) ? 128 : 256));
  854. return n;
  855. }
  856. int getDefaultBufferSize()
  857. {
  858. return 2560;
  859. }
  860. const String open (const BitArray& inputChannels,
  861. const BitArray& outputChannels,
  862. double sampleRate,
  863. int bufferSizeSamples)
  864. {
  865. lastError = openDevice (inputChannels, outputChannels, sampleRate, bufferSizeSamples);
  866. isOpen_ = lastError.isEmpty();
  867. return lastError;
  868. }
  869. void close()
  870. {
  871. stop();
  872. if (isOpen_)
  873. {
  874. closeDevice();
  875. isOpen_ = false;
  876. }
  877. }
  878. bool isOpen()
  879. {
  880. return isOpen_ && isThreadRunning();
  881. }
  882. int getCurrentBufferSizeSamples()
  883. {
  884. return bufferSizeSamples;
  885. }
  886. double getCurrentSampleRate()
  887. {
  888. return sampleRate;
  889. }
  890. int getCurrentBitDepth()
  891. {
  892. int i, bits = 256;
  893. for (i = inChans.size(); --i >= 0;)
  894. bits = jmin (bits, inChans[i]->bitDepth);
  895. for (i = outChans.size(); --i >= 0;)
  896. bits = jmin (bits, outChans[i]->bitDepth);
  897. if (bits > 32)
  898. bits = 16;
  899. return bits;
  900. }
  901. const BitArray getActiveOutputChannels() const
  902. {
  903. return enabledOutputs;
  904. }
  905. const BitArray getActiveInputChannels() const
  906. {
  907. return enabledInputs;
  908. }
  909. int getOutputLatencyInSamples()
  910. {
  911. return (int) (getCurrentBufferSizeSamples() * 1.5);
  912. }
  913. int getInputLatencyInSamples()
  914. {
  915. return getOutputLatencyInSamples();
  916. }
  917. void start (AudioIODeviceCallback* call)
  918. {
  919. if (isOpen_ && call != 0 && ! isStarted)
  920. {
  921. if (! isThreadRunning())
  922. {
  923. // something gone wrong and the thread's stopped..
  924. isOpen_ = false;
  925. return;
  926. }
  927. call->audioDeviceAboutToStart (this);
  928. const ScopedLock sl (startStopLock);
  929. callback = call;
  930. isStarted = true;
  931. }
  932. }
  933. void stop()
  934. {
  935. if (isStarted)
  936. {
  937. AudioIODeviceCallback* const callbackLocal = callback;
  938. {
  939. const ScopedLock sl (startStopLock);
  940. isStarted = false;
  941. }
  942. if (callbackLocal != 0)
  943. callbackLocal->audioDeviceStopped();
  944. }
  945. }
  946. bool isPlaying()
  947. {
  948. return isStarted && isOpen_ && isThreadRunning();
  949. }
  950. const String getLastError()
  951. {
  952. return lastError;
  953. }
  954. //==============================================================================
  955. juce_UseDebuggingNewOperator
  956. StringArray inChannels, outChannels;
  957. int outputDeviceIndex, inputDeviceIndex;
  958. private:
  959. bool isOpen_;
  960. bool isStarted;
  961. String lastError;
  962. OwnedArray <DSoundInternalInChannel> inChans;
  963. OwnedArray <DSoundInternalOutChannel> outChans;
  964. WaitableEvent startEvent;
  965. int numInputBuffers, numOutputBuffers, bufferSizeSamples;
  966. int volatile totalSamplesOut;
  967. int64 volatile lastBlockTime;
  968. double sampleRate;
  969. BitArray enabledInputs, enabledOutputs;
  970. float** inputBuffers;
  971. float** outputBuffers;
  972. AudioIODeviceCallback* callback;
  973. CriticalSection startStopLock;
  974. DSoundAudioIODevice (const DSoundAudioIODevice&);
  975. const DSoundAudioIODevice& operator= (const DSoundAudioIODevice&);
  976. const String openDevice (const BitArray& inputChannels,
  977. const BitArray& outputChannels,
  978. double sampleRate_,
  979. int bufferSizeSamples_);
  980. void closeDevice()
  981. {
  982. isStarted = false;
  983. stopThread (5000);
  984. inChans.clear();
  985. outChans.clear();
  986. int i;
  987. for (i = 0; i < numInputBuffers; ++i)
  988. juce_free (inputBuffers[i]);
  989. delete[] inputBuffers;
  990. inputBuffers = 0;
  991. numInputBuffers = 0;
  992. for (i = 0; i < numOutputBuffers; ++i)
  993. juce_free (outputBuffers[i]);
  994. delete[] outputBuffers;
  995. outputBuffers = 0;
  996. numOutputBuffers = 0;
  997. }
  998. void resync()
  999. {
  1000. if (! threadShouldExit())
  1001. {
  1002. sleep (5);
  1003. int i;
  1004. for (i = 0; i < outChans.size(); ++i)
  1005. outChans.getUnchecked(i)->synchronisePosition();
  1006. for (i = 0; i < inChans.size(); ++i)
  1007. inChans.getUnchecked(i)->synchronisePosition();
  1008. }
  1009. }
  1010. public:
  1011. void run()
  1012. {
  1013. while (! threadShouldExit())
  1014. {
  1015. if (wait (100))
  1016. break;
  1017. }
  1018. const int latencyMs = (int) (bufferSizeSamples * 1000.0 / sampleRate);
  1019. const int maxTimeMS = jmax (5, 3 * latencyMs);
  1020. while (! threadShouldExit())
  1021. {
  1022. int numToDo = 0;
  1023. uint32 startTime = Time::getMillisecondCounter();
  1024. int i;
  1025. for (i = inChans.size(); --i >= 0;)
  1026. {
  1027. inChans.getUnchecked(i)->doneFlag = false;
  1028. ++numToDo;
  1029. }
  1030. for (i = outChans.size(); --i >= 0;)
  1031. {
  1032. outChans.getUnchecked(i)->doneFlag = false;
  1033. ++numToDo;
  1034. }
  1035. if (numToDo > 0)
  1036. {
  1037. const int maxCount = 3;
  1038. int count = maxCount;
  1039. for (;;)
  1040. {
  1041. for (i = inChans.size(); --i >= 0;)
  1042. {
  1043. DSoundInternalInChannel* const in = inChans.getUnchecked(i);
  1044. if ((! in->doneFlag) && in->service())
  1045. {
  1046. in->doneFlag = true;
  1047. --numToDo;
  1048. }
  1049. }
  1050. for (i = outChans.size(); --i >= 0;)
  1051. {
  1052. DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
  1053. if ((! out->doneFlag) && out->service())
  1054. {
  1055. out->doneFlag = true;
  1056. --numToDo;
  1057. }
  1058. }
  1059. if (numToDo <= 0)
  1060. break;
  1061. if (Time::getMillisecondCounter() > startTime + maxTimeMS)
  1062. {
  1063. resync();
  1064. break;
  1065. }
  1066. if (--count <= 0)
  1067. {
  1068. Sleep (1);
  1069. count = maxCount;
  1070. }
  1071. if (threadShouldExit())
  1072. return;
  1073. }
  1074. }
  1075. else
  1076. {
  1077. sleep (1);
  1078. }
  1079. const ScopedLock sl (startStopLock);
  1080. if (isStarted)
  1081. {
  1082. JUCE_TRY
  1083. {
  1084. callback->audioDeviceIOCallback ((const float**) inputBuffers,
  1085. numInputBuffers,
  1086. outputBuffers,
  1087. numOutputBuffers,
  1088. bufferSizeSamples);
  1089. }
  1090. JUCE_CATCH_EXCEPTION
  1091. totalSamplesOut += bufferSizeSamples;
  1092. }
  1093. else
  1094. {
  1095. for (i = 0; i < numOutputBuffers; ++i)
  1096. if (outputBuffers[i] != 0)
  1097. zeromem (outputBuffers[i], bufferSizeSamples * sizeof (float));
  1098. totalSamplesOut = 0;
  1099. sleep (1);
  1100. }
  1101. }
  1102. }
  1103. };
  1104. //==============================================================================
  1105. class DSoundAudioIODeviceType : public AudioIODeviceType
  1106. {
  1107. public:
  1108. DSoundAudioIODeviceType()
  1109. : AudioIODeviceType (T("DirectSound")),
  1110. hasScanned (false)
  1111. {
  1112. initialiseDSoundFunctions();
  1113. }
  1114. ~DSoundAudioIODeviceType()
  1115. {
  1116. }
  1117. //==============================================================================
  1118. void scanForDevices()
  1119. {
  1120. hasScanned = true;
  1121. outputDeviceNames.clear();
  1122. outputGuids.clear();
  1123. inputDeviceNames.clear();
  1124. inputGuids.clear();
  1125. if (dsDirectSoundEnumerateW != 0)
  1126. {
  1127. dsDirectSoundEnumerateW (outputEnumProcW, this);
  1128. dsDirectSoundCaptureEnumerateW (inputEnumProcW, this);
  1129. }
  1130. }
  1131. const StringArray getDeviceNames (const bool wantInputNames) const
  1132. {
  1133. jassert (hasScanned); // need to call scanForDevices() before doing this
  1134. return wantInputNames ? inputDeviceNames
  1135. : outputDeviceNames;
  1136. }
  1137. int getDefaultDeviceIndex (const bool /*forInput*/) const
  1138. {
  1139. jassert (hasScanned); // need to call scanForDevices() before doing this
  1140. return 0;
  1141. }
  1142. int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
  1143. {
  1144. jassert (hasScanned); // need to call scanForDevices() before doing this
  1145. DSoundAudioIODevice* const d = dynamic_cast <DSoundAudioIODevice*> (device);
  1146. if (d == 0)
  1147. return -1;
  1148. return asInput ? d->inputDeviceIndex
  1149. : d->outputDeviceIndex;
  1150. }
  1151. bool hasSeparateInputsAndOutputs() const { return true; }
  1152. AudioIODevice* createDevice (const String& outputDeviceName,
  1153. const String& inputDeviceName)
  1154. {
  1155. jassert (hasScanned); // need to call scanForDevices() before doing this
  1156. const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
  1157. const int inputIndex = inputDeviceNames.indexOf (inputDeviceName);
  1158. if (outputIndex >= 0 || inputIndex >= 0)
  1159. return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
  1160. : inputDeviceName,
  1161. outputIndex, inputIndex);
  1162. return 0;
  1163. }
  1164. //==============================================================================
  1165. juce_UseDebuggingNewOperator
  1166. StringArray outputDeviceNames;
  1167. OwnedArray <GUID> outputGuids;
  1168. StringArray inputDeviceNames;
  1169. OwnedArray <GUID> inputGuids;
  1170. private:
  1171. bool hasScanned;
  1172. //==============================================================================
  1173. BOOL outputEnumProc (LPGUID lpGUID, String desc)
  1174. {
  1175. desc = desc.trim();
  1176. if (desc.isNotEmpty())
  1177. {
  1178. const String origDesc (desc);
  1179. int n = 2;
  1180. while (outputDeviceNames.contains (desc))
  1181. desc = origDesc + T(" (") + String (n++) + T(")");
  1182. outputDeviceNames.add (desc);
  1183. if (lpGUID != 0)
  1184. outputGuids.add (new GUID (*lpGUID));
  1185. else
  1186. outputGuids.add (0);
  1187. }
  1188. return TRUE;
  1189. }
  1190. static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1191. {
  1192. return ((DSoundAudioIODeviceType*) object)
  1193. ->outputEnumProc (lpGUID, String (description));
  1194. }
  1195. static BOOL CALLBACK outputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1196. {
  1197. return ((DSoundAudioIODeviceType*) object)
  1198. ->outputEnumProc (lpGUID, String (description));
  1199. }
  1200. //==============================================================================
  1201. BOOL CALLBACK inputEnumProc (LPGUID lpGUID, String desc)
  1202. {
  1203. desc = desc.trim();
  1204. if (desc.isNotEmpty())
  1205. {
  1206. const String origDesc (desc);
  1207. int n = 2;
  1208. while (inputDeviceNames.contains (desc))
  1209. desc = origDesc + T(" (") + String (n++) + T(")");
  1210. inputDeviceNames.add (desc);
  1211. if (lpGUID != 0)
  1212. inputGuids.add (new GUID (*lpGUID));
  1213. else
  1214. inputGuids.add (0);
  1215. }
  1216. return TRUE;
  1217. }
  1218. static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
  1219. {
  1220. return ((DSoundAudioIODeviceType*) object)
  1221. ->inputEnumProc (lpGUID, String (description));
  1222. }
  1223. static BOOL CALLBACK inputEnumProcA (LPGUID lpGUID, LPCTSTR description, LPCTSTR, LPVOID object)
  1224. {
  1225. return ((DSoundAudioIODeviceType*) object)
  1226. ->inputEnumProc (lpGUID, String (description));
  1227. }
  1228. //==============================================================================
  1229. DSoundAudioIODeviceType (const DSoundAudioIODeviceType&);
  1230. const DSoundAudioIODeviceType& operator= (const DSoundAudioIODeviceType&);
  1231. };
  1232. //==============================================================================
  1233. AudioIODeviceType* juce_createDefaultAudioIODeviceType()
  1234. {
  1235. return new DSoundAudioIODeviceType();
  1236. }
  1237. //==============================================================================
  1238. const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
  1239. const BitArray& outputChannels,
  1240. double sampleRate_,
  1241. int bufferSizeSamples_)
  1242. {
  1243. closeDevice();
  1244. totalSamplesOut = 0;
  1245. sampleRate = sampleRate_;
  1246. if (bufferSizeSamples_ <= 0)
  1247. bufferSizeSamples_ = 960; // use as a default size if none is set.
  1248. bufferSizeSamples = bufferSizeSamples_ & ~7;
  1249. DSoundAudioIODeviceType dlh;
  1250. dlh.scanForDevices();
  1251. enabledInputs = inputChannels;
  1252. enabledInputs.setRange (inChannels.size(),
  1253. enabledInputs.getHighestBit() + 1 - inChannels.size(),
  1254. false);
  1255. numInputBuffers = enabledInputs.countNumberOfSetBits();
  1256. inputBuffers = new float* [numInputBuffers + 2];
  1257. zeromem (inputBuffers, sizeof (float*) * numInputBuffers + 2);
  1258. int i, numIns = 0;
  1259. for (i = 0; i <= enabledInputs.getHighestBit(); i += 2)
  1260. {
  1261. float* left = 0;
  1262. float* right = 0;
  1263. if (enabledInputs[i])
  1264. left = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1265. if (enabledInputs[i + 1])
  1266. right = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1267. if (left != 0 || right != 0)
  1268. inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [inputDeviceIndex],
  1269. dlh.inputGuids [inputDeviceIndex],
  1270. (int) sampleRate, bufferSizeSamples,
  1271. left, right));
  1272. }
  1273. enabledOutputs = outputChannels;
  1274. enabledOutputs.setRange (outChannels.size(),
  1275. enabledOutputs.getHighestBit() + 1 - outChannels.size(),
  1276. false);
  1277. numOutputBuffers = enabledOutputs.countNumberOfSetBits();
  1278. outputBuffers = new float* [numOutputBuffers + 2];
  1279. zeromem (outputBuffers, sizeof (float*) * numOutputBuffers + 2);
  1280. int numOuts = 0;
  1281. for (i = 0; i <= enabledOutputs.getHighestBit(); i += 2)
  1282. {
  1283. float* left = 0;
  1284. float* right = 0;
  1285. if (enabledOutputs[i])
  1286. left = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1287. if (enabledOutputs[i + 1])
  1288. right = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
  1289. if (left != 0 || right != 0)
  1290. outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[outputDeviceIndex],
  1291. dlh.outputGuids [outputDeviceIndex],
  1292. (int) sampleRate, bufferSizeSamples,
  1293. left, right));
  1294. }
  1295. String error;
  1296. // boost our priority while opening the devices to try to get better sync between them
  1297. const int oldThreadPri = GetThreadPriority (GetCurrentThread());
  1298. const int oldProcPri = GetPriorityClass (GetCurrentProcess());
  1299. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1300. SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  1301. for (i = 0; i < outChans.size(); ++i)
  1302. {
  1303. error = outChans[i]->open();
  1304. if (error.isNotEmpty())
  1305. {
  1306. error = T("Error opening ") + dlh.outputDeviceNames[i]
  1307. + T(": \"") + error + T("\"");
  1308. break;
  1309. }
  1310. }
  1311. if (error.isEmpty())
  1312. {
  1313. for (i = 0; i < inChans.size(); ++i)
  1314. {
  1315. error = inChans[i]->open();
  1316. if (error.isNotEmpty())
  1317. {
  1318. error = T("Error opening ") + dlh.inputDeviceNames[i]
  1319. + T(": \"") + error + T("\"");
  1320. break;
  1321. }
  1322. }
  1323. }
  1324. if (error.isEmpty())
  1325. {
  1326. totalSamplesOut = 0;
  1327. for (i = 0; i < outChans.size(); ++i)
  1328. outChans.getUnchecked(i)->synchronisePosition();
  1329. for (i = 0; i < inChans.size(); ++i)
  1330. inChans.getUnchecked(i)->synchronisePosition();
  1331. startThread (9);
  1332. sleep (10);
  1333. notify();
  1334. }
  1335. else
  1336. {
  1337. log (error);
  1338. }
  1339. SetThreadPriority (GetCurrentThread(), oldThreadPri);
  1340. SetPriorityClass (GetCurrentProcess(), oldProcPri);
  1341. return error;
  1342. }
  1343. #undef log
  1344. #endif